@@ -19,6 +19,21 @@ def test_build_span_attributes_ref_uri() -> None:
1919 params = {"ref" : {"uri" : "test://doc" }},
2020 )
2121 assert attrs ["mcp.resource.uri" ] == "test://doc"
22+ assert "gen_ai.operation.name" not in attrs
23+
24+
25+ def test_build_span_attributes_tools_call_no_name () -> None :
26+ """tools/call without a name param omits gen_ai.tool.name."""
27+ attrs = build_span_attributes ("tools/call" , "1" , params = {})
28+ assert attrs ["gen_ai.operation.name" ] == "execute_tool"
29+ assert "gen_ai.tool.name" not in attrs
30+
31+
32+ def test_build_span_attributes_prompts_get_no_name () -> None :
33+ """prompts/get without a name param omits gen_ai.prompt.name."""
34+ attrs = build_span_attributes ("prompts/get" , "1" , params = {})
35+ assert "gen_ai.prompt.name" not in attrs
36+ assert "gen_ai.operation.name" not in attrs
2237
2338
2439async def test_client_and_server_spans (capfire : CaptureLogfire ):
@@ -52,7 +67,7 @@ def greet(name: str) -> str:
5267 assert server_span ["attributes" ]["rpc.system" ] == "mcp"
5368 assert server_span ["attributes" ]["mcp.method.name" ] == "tools/call"
5469
55- # GenAI semconv attributes
70+ # GenAI semconv attributes — execute_tool only on tools/call
5671 assert client_span ["attributes" ]["gen_ai.operation.name" ] == "execute_tool"
5772 assert client_span ["attributes" ]["gen_ai.tool.name" ] == "greet"
5873 assert server_span ["attributes" ]["gen_ai.operation.name" ] == "execute_tool"
@@ -63,7 +78,7 @@ def greet(name: str) -> str:
6378
6479
6580async def test_list_tools_spans (capfire : CaptureLogfire ):
66- """Verify that listing tools produces spans with list_tools operation."""
81+ """Verify that listing tools produces spans without gen_ai. operation.name ."""
6782 server = MCPServer ("test" )
6883
6984 async with Client (server ) as client :
@@ -74,9 +89,9 @@ async def test_list_tools_spans(capfire: CaptureLogfire):
7489 client_span = next (s for s in spans if s ["name" ] == "MCP send tools/list" )
7590 server_span = next (s for s in spans if s ["name" ] == "MCP handle tools/list" )
7691
77- assert client_span [ "attributes" ][ " gen_ai.operation.name" ] == "list_tools"
78- assert server_span [ "attributes" ][ " gen_ai.operation.name"] == "list_tools"
79- # No tool name on list — no specific tool targeted
92+ # gen_ai.operation.name SHOULD NOT be set for non-tool-call methods per spec
93+ assert " gen_ai.operation.name" not in client_span [ "attributes" ]
94+ assert "gen_ai.operation. name" not in server_span [ "attributes" ]
8095 assert "gen_ai.tool.name" not in client_span ["attributes" ]
8196 assert "gen_ai.tool.name" not in server_span ["attributes" ]
8297
@@ -99,9 +114,36 @@ def greeting() -> str:
99114 client_span = next (s for s in spans if s ["name" ] == "MCP send resources/read" )
100115 server_span = next (s for s in spans if s ["name" ] == "MCP handle resources/read" )
101116
102- assert client_span ["attributes" ]["gen_ai.operation.name" ] == "read_resource"
103117 assert client_span ["attributes" ]["mcp.resource.uri" ] == "test://greeting"
104- assert server_span ["attributes" ]["gen_ai.operation.name" ] == "read_resource"
105118 assert server_span ["attributes" ]["mcp.resource.uri" ] == "test://greeting"
119+ # gen_ai.operation.name SHOULD NOT be set for resources/read per spec
120+ assert "gen_ai.operation.name" not in client_span ["attributes" ]
121+ assert "gen_ai.operation.name" not in server_span ["attributes" ]
122+
123+ assert server_span ["context" ]["trace_id" ] == client_span ["context" ]["trace_id" ]
124+
125+
126+ async def test_prompt_get_spans (capfire : CaptureLogfire ):
127+ """Verify that getting a prompt produces spans with gen_ai.prompt.name."""
128+ server = MCPServer ("test" )
129+
130+ @server .prompt ()
131+ def summarize () -> str :
132+ """Summarize text."""
133+ return "Summarize the following: "
134+
135+ async with Client (server ) as client :
136+ await client .get_prompt ("summarize" , {})
137+
138+ spans = capfire .exporter .exported_spans_as_dict ()
139+
140+ client_span = next (s for s in spans if s ["name" ] == "MCP send prompts/get summarize" )
141+ server_span = next (s for s in spans if s ["name" ] == "MCP handle prompts/get summarize" )
142+
143+ assert client_span ["attributes" ]["gen_ai.prompt.name" ] == "summarize"
144+ assert server_span ["attributes" ]["gen_ai.prompt.name" ] == "summarize"
145+ # gen_ai.operation.name SHOULD NOT be set for prompts/get per spec
146+ assert "gen_ai.operation.name" not in client_span ["attributes" ]
147+ assert "gen_ai.operation.name" not in server_span ["attributes" ]
106148
107149 assert server_span ["context" ]["trace_id" ] == client_span ["context" ]["trace_id" ]
0 commit comments