@@ -70,6 +70,29 @@ async def test_emits_server_span_with_method_and_target(server: SrvT, spans: Spa
7070 assert span .status .status_code == StatusCode .UNSET
7171
7272
73+ @pytest .mark .anyio
74+ async def test_client_span_records_jsonrpc_error (server : SrvT , spans : SpanCapture ):
75+ """A JSON-RPC error marks the client span while preserving the MCPError contract."""
76+
77+ async def failing (ctx : Ctx , params : PaginatedRequestParams | None ) -> Any :
78+ raise MCPError (code = INVALID_PARAMS , message = "forced failure" )
79+
80+ server .add_request_handler ("resources/list" , PaginatedRequestParams , failing )
81+ async with connected_runner (server ) as (client , _ ):
82+ spans .clear ()
83+ with pytest .raises (MCPError ) as exc :
84+ await client .send_raw_request ("resources/list" , None )
85+
86+ assert exc .value .error .code == INVALID_PARAMS
87+ [span ] = [s for s in spans .finished () if s .kind == SpanKind .CLIENT ]
88+ assert span .status .status_code == StatusCode .ERROR
89+ assert span .status .description == "forced failure"
90+ assert span .attributes is not None
91+ assert span .attributes ["error.type" ] == str (INVALID_PARAMS )
92+ assert span .attributes ["rpc.response.status_code" ] == str (INVALID_PARAMS )
93+ assert not [event for event in span .events if event .name == "exception" ]
94+
95+
7396@pytest .mark .anyio
7497async def test_tool_error_dict_result_sets_error_type (server : SrvT , spans : SpanCapture ):
7598 async def err_tool (ctx : Ctx , params : CallToolRequestParams ) -> dict [str , Any ]:
0 commit comments