44 */
55
66import { getClient } from '../../currentScopes' ;
7- import { SPAN_STATUS_ERROR , withActiveSpan } from '../../tracing' ;
7+ import { SPAN_STATUS_ERROR } from '../../tracing' ;
88import type { Span } from '../../types-hoist/span' ;
99import { extractToolResultAttributes } from './attributeExtraction' ;
1010import { filterMcpPiiFromSpanData } from './piiFiltering' ;
11- import type { RequestId , RequestSpanMapValue } from './types' ;
11+ import type { MCPTransport , RequestId , RequestSpanMapValue } from './types' ;
1212
13- // Simplified correlation system that works with or without sessionId
14- // Maps requestId directly to span data for stateless operation
15- const requestIdToSpanMap = new Map < RequestId , RequestSpanMapValue > ( ) ;
13+ // Transport-scoped correlation system that prevents collisions between different MCP sessions
14+ // Each transport instance gets its own correlation map, eliminating request ID conflicts
15+ const transportToSpanMap = new WeakMap < MCPTransport , Map < RequestId , RequestSpanMapValue > > ( ) ;
16+
17+ /**
18+ * Gets or creates the span map for a specific transport instance
19+ */
20+ function getOrCreateSpanMap ( transport : MCPTransport ) : Map < RequestId , RequestSpanMapValue > {
21+ let spanMap = transportToSpanMap . get ( transport ) ;
22+ if ( ! spanMap ) {
23+ spanMap = new Map ( ) ;
24+ transportToSpanMap . set ( transport , spanMap ) ;
25+ }
26+ return spanMap ;
27+ }
1628
1729/**
1830 * Stores span context for later correlation with handler execution
1931 */
20- export function storeSpanForRequest ( requestId : RequestId , span : Span , method : string ) : void {
21- requestIdToSpanMap . set ( requestId , {
32+ export function storeSpanForRequest ( transport : MCPTransport , requestId : RequestId , span : Span , method : string ) : void {
33+ const spanMap = getOrCreateSpanMap ( transport ) ;
34+ spanMap . set ( requestId , {
2235 span,
2336 method,
2437 startTime : Date . now ( ) ,
2538 } ) ;
2639}
2740
28- /**
29- * Associates handler execution with the corresponding request span
30- */
31- export function associateContextWithRequestSpan < T > (
32- extraHandlerData : { requestId : RequestId } | undefined ,
33- cb : ( ) => T ,
34- ) : T {
35- if ( extraHandlerData ) {
36- const { requestId } = extraHandlerData ;
37-
38- const spanData = requestIdToSpanMap . get ( requestId ) ;
39- if ( ! spanData ) {
40- return cb ( ) ;
41- }
42-
43- // Keep span in map for response enrichment (don't delete yet)
44- return withActiveSpan ( spanData . span , ( ) => {
45- return cb ( ) ;
46- } ) ;
47- }
48-
49- return cb ( ) ;
50- }
51-
5241/**
5342 * Completes span with tool results and cleans up correlation
5443 */
55- export function completeSpanWithResults ( requestId : RequestId , result : unknown ) : void {
56- const spanData = requestIdToSpanMap . get ( requestId ) ;
44+ export function completeSpanWithResults ( transport : MCPTransport , requestId : RequestId , result : unknown ) : void {
45+ const spanMap = getOrCreateSpanMap ( transport ) ;
46+ const spanData = spanMap . get ( requestId ) ;
5747 if ( spanData ) {
5848 const { span, method } = spanData ;
5949
@@ -68,24 +58,27 @@ export function completeSpanWithResults(requestId: RequestId, result: unknown):
6858 }
6959
7060 span . end ( ) ;
71- requestIdToSpanMap . delete ( requestId ) ;
61+ spanMap . delete ( requestId ) ;
7262 }
7363}
7464
7565/**
76- * Cleans up all pending spans ( for transport close )
66+ * Cleans up pending spans for a specific transport (when that transport closes )
7767 */
78- export function cleanupAllPendingSpans ( ) : number {
79- const pendingCount = requestIdToSpanMap . size ;
68+ export function cleanupPendingSpansForTransport ( transport : MCPTransport ) : number {
69+ const spanMap = transportToSpanMap . get ( transport ) ;
70+ if ( ! spanMap ) return 0 ;
71+
72+ const pendingCount = spanMap . size ;
8073
81- for ( const [ , spanData ] of requestIdToSpanMap ) {
74+ for ( const [ , spanData ] of spanMap ) {
8275 spanData . span . setStatus ( {
8376 code : SPAN_STATUS_ERROR ,
8477 message : 'cancelled' ,
8578 } ) ;
8679 spanData . span . end ( ) ;
8780 }
8881
89- requestIdToSpanMap . clear ( ) ;
82+ spanMap . clear ( ) ;
9083 return pendingCount ;
9184}
0 commit comments