@@ -682,6 +682,152 @@ async def _test():
682682
683683 anyio .run (_test )
684684
685+ def test_get_mcp_status (self ):
686+ """Test get_mcp_status returns McpStatusResponse shape."""
687+
688+ async def _test ():
689+ with patch (
690+ "claude_agent_sdk._internal.transport.subprocess_cli.SubprocessCLITransport"
691+ ) as mock_transport_class :
692+ mock_transport = AsyncMock ()
693+ mock_transport .connect = AsyncMock ()
694+ mock_transport .close = AsyncMock ()
695+ mock_transport .end_input = AsyncMock ()
696+ mock_transport .is_ready = Mock (return_value = True )
697+ mock_transport_class .return_value = mock_transport
698+
699+ written_messages : list [str ] = []
700+
701+ async def mock_write (data ):
702+ written_messages .append (data )
703+
704+ mock_transport .write = AsyncMock (side_effect = mock_write )
705+
706+ # Simulated mcp_status response matching McpServerStatus shape
707+ mcp_status_response = {
708+ "mcpServers" : [
709+ {
710+ "name" : "my-http-server" ,
711+ "status" : "connected" ,
712+ "serverInfo" : {
713+ "name" : "my-http-server" ,
714+ "version" : "1.0.0" ,
715+ },
716+ "config" : {
717+ "type" : "http" ,
718+ "url" : "https://example.com/mcp" ,
719+ },
720+ "scope" : "project" ,
721+ "tools" : [
722+ {
723+ "name" : "greet" ,
724+ "description" : "Greet a user" ,
725+ "annotations" : {"readOnly" : True },
726+ },
727+ {"name" : "reset" },
728+ ],
729+ },
730+ {
731+ "name" : "failed-server" ,
732+ "status" : "failed" ,
733+ "error" : "Connection refused" ,
734+ },
735+ {
736+ "name" : "proxy-server" ,
737+ "status" : "needs-auth" ,
738+ "config" : {
739+ "type" : "claudeai-proxy" ,
740+ "url" : "https://claude.ai/proxy" ,
741+ "id" : "proxy-123" ,
742+ },
743+ },
744+ ]
745+ }
746+
747+ async def control_protocol_generator ():
748+ last_check = 0
749+ timeout_counter = 0
750+ while timeout_counter < 200 :
751+ await asyncio .sleep (0.01 )
752+ timeout_counter += 1
753+
754+ for msg_str in written_messages [last_check :]:
755+ try :
756+ msg = json .loads (msg_str .strip ())
757+ if msg .get ("type" ) == "control_request" :
758+ subtype = msg .get ("request" , {}).get ("subtype" )
759+ if subtype == "initialize" :
760+ yield {
761+ "type" : "control_response" ,
762+ "response" : {
763+ "request_id" : msg .get ("request_id" ),
764+ "subtype" : "success" ,
765+ "response" : {},
766+ },
767+ }
768+ elif subtype == "mcp_status" :
769+ yield {
770+ "type" : "control_response" ,
771+ "response" : {
772+ "request_id" : msg .get ("request_id" ),
773+ "subtype" : "success" ,
774+ "response" : mcp_status_response ,
775+ },
776+ }
777+ except (json .JSONDecodeError , KeyError , AttributeError ):
778+ pass
779+ last_check = len (written_messages )
780+
781+ mock_transport .read_messages = control_protocol_generator
782+
783+ async with ClaudeSDKClient () as client :
784+ status = await client .get_mcp_status ()
785+
786+ # Verify response conforms to McpStatusResponse shape
787+ assert "mcpServers" in status
788+ servers = status ["mcpServers" ]
789+ assert len (servers ) == 3
790+
791+ # Connected server with full info
792+ connected = servers [0 ]
793+ assert connected ["name" ] == "my-http-server"
794+ assert connected ["status" ] == "connected"
795+ assert connected ["serverInfo" ]["version" ] == "1.0.0"
796+ assert connected ["config" ]["type" ] == "http"
797+ assert connected ["config" ]["url" ] == "https://example.com/mcp"
798+ assert connected ["scope" ] == "project"
799+ assert len (connected ["tools" ]) == 2
800+ assert connected ["tools" ][0 ]["name" ] == "greet"
801+ assert connected ["tools" ][0 ]["annotations" ]["readOnly" ] is True
802+ # Tool without optional fields
803+ assert connected ["tools" ][1 ]["name" ] == "reset"
804+ assert "description" not in connected ["tools" ][1 ]
805+
806+ # Failed server with error
807+ failed = servers [1 ]
808+ assert failed ["name" ] == "failed-server"
809+ assert failed ["status" ] == "failed"
810+ assert failed ["error" ] == "Connection refused"
811+
812+ # Server with claudeai-proxy config
813+ proxy = servers [2 ]
814+ assert proxy ["name" ] == "proxy-server"
815+ assert proxy ["status" ] == "needs-auth"
816+ assert proxy ["config" ]["type" ] == "claudeai-proxy"
817+ assert proxy ["config" ]["id" ] == "proxy-123"
818+
819+ anyio .run (_test )
820+
821+ def test_get_mcp_status_not_connected (self ):
822+ """Test get_mcp_status when not connected raises error."""
823+
824+ async def _test ():
825+ client = ClaudeSDKClient ()
826+ with pytest .raises (CLIConnectionError , match = "Not connected" ):
827+ await client .get_mcp_status ()
828+
829+ anyio .run (_test )
830+
685831 def test_client_with_options (self ):
686832 """Test client initialization with options."""
687833
0 commit comments