@@ -18,6 +18,18 @@ public async Task Session_TracksActivities()
1818 var activities = new List < Activity > ( ) ;
1919 var clientToServerLog = new List < string > ( ) ;
2020
21+ // Predicate for the expected server tool-call activity, including all required tags.
22+ // Defined here so it can be reused for both the wait and the assertion below.
23+ Func < Activity , bool > isExpectedServerToolCall = a =>
24+ a . DisplayName == "tools/call DoubleValue" &&
25+ a . Kind == ActivityKind . Server &&
26+ a . Status == ActivityStatusCode . Unset &&
27+ a . Tags . Any ( t => t . Key == "gen_ai.tool.name" && t . Value == "DoubleValue" ) &&
28+ a . Tags . Any ( t => t . Key == "mcp.method.name" && t . Value == "tools/call" ) &&
29+ a . Tags . Any ( t => t . Key == "gen_ai.operation.name" && t . Value == "execute_tool" ) &&
30+ a . Tags . Any ( t => t . Key == "mcp.protocol.version" && ! string . IsNullOrEmpty ( t . Value ) ) &&
31+ a . Tags . Any ( t => t . Key == "mcp.session.id" && ! string . IsNullOrEmpty ( t . Value ) ) ;
32+
2133 using ( var tracerProvider = OpenTelemetry . Sdk . CreateTracerProviderBuilder ( )
2234 . AddSource ( "Experimental.ModelContextProtocol" )
2335 . AddInMemoryExporter ( activities )
@@ -36,9 +48,11 @@ await RunConnected(async (client, server) =>
3648 // Wait for server-side activities to be exported. The server processes messages
3749 // via fire-and-forget tasks, so activities may not be immediately available
3850 // after the client operation completes. Wait for the specific activity we need
39- // rather than a count, as other server activities may be exported first.
40- await WaitForAsync ( ( ) => activities . Any ( a =>
41- a . DisplayName == "tools/call DoubleValue" && a . Kind == ActivityKind . Server ) ) ;
51+ // (including required tags) rather than just the display name, so that we don't
52+ // assert before all tags have been populated.
53+ await WaitForAsync (
54+ ( ) => activities . Any ( isExpectedServerToolCall ) ,
55+ failureMessage : "Timed out waiting for the expected server tool-call activity (tools/call DoubleValue) to be exported with required tags." ) ;
4256 }
4357
4458 Assert . NotEmpty ( activities ) ;
@@ -54,13 +68,7 @@ await WaitForAsync(() => activities.Any(a =>
5468 // Per semantic conventions: mcp.protocol.version should be present after initialization
5569 Assert . Contains ( clientToolCall . Tags , t => t . Key == "mcp.protocol.version" && ! string . IsNullOrEmpty ( t . Value ) ) ;
5670
57- var serverToolCall = Assert . Single ( activities , a =>
58- a . Tags . Any ( t => t . Key == "gen_ai.tool.name" && t . Value == "DoubleValue" ) &&
59- a . Tags . Any ( t => t . Key == "mcp.method.name" && t . Value == "tools/call" ) &&
60- a . Tags . Any ( t => t . Key == "gen_ai.operation.name" && t . Value == "execute_tool" ) &&
61- a . DisplayName == "tools/call DoubleValue" &&
62- a . Kind == ActivityKind . Server &&
63- a . Status == ActivityStatusCode . Unset ) ;
71+ var serverToolCall = Assert . Single ( activities , a => isExpectedServerToolCall ( a ) ) ;
6472
6573 // Per semantic conventions: mcp.protocol.version should be present after initialization
6674 Assert . Contains ( serverToolCall . Tags , t => t . Key == "mcp.protocol.version" && ! string . IsNullOrEmpty ( t . Value ) ) ;
@@ -245,12 +253,19 @@ private static async Task RunConnected(Func<McpClient, McpServer, Task> action,
245253 await serverTask ;
246254 }
247255
248- private static async Task WaitForAsync ( Func < bool > condition , int timeoutMs = 10_000 )
256+ private static async Task WaitForAsync ( Func < bool > condition , int timeoutMs = 10_000 , string ? failureMessage = null )
249257 {
250258 using var cts = new CancellationTokenSource ( timeoutMs ) ;
251- while ( ! condition ( ) )
259+ try
260+ {
261+ while ( ! condition ( ) )
262+ {
263+ await Task . Delay ( 10 , cts . Token ) ;
264+ }
265+ }
266+ catch ( TaskCanceledException )
252267 {
253- await Task . Delay ( 10 , cts . Token ) ;
268+ throw new Xunit . Sdk . XunitException ( failureMessage ?? $ "Condition was not met within { timeoutMs } ms." ) ;
254269 }
255270 }
256271}
0 commit comments