UNPKG

@sentry/core

Version:
120 lines (106 loc) 3.87 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const spanstatus = require('../../tracing/spanstatus.js'); const attributes = require('./attributes.js'); const resultExtraction = require('./resultExtraction.js'); const sessionExtraction = require('./sessionExtraction.js'); /** * Request-span correlation system for MCP server instrumentation * * Handles mapping requestId to span data for correlation with handler execution. * Uses WeakMap to scope correlation maps per transport instance, preventing * request ID collisions between different MCP sessions. */ /** * Transport-scoped correlation system that prevents collisions between different MCP sessions * @internal Each transport instance gets its own correlation map, eliminating request ID conflicts */ const transportToSpanMap = new WeakMap(); /** * Gets or creates the span map for a specific transport instance * @internal * @param transport - MCP transport instance * @returns Span map for the transport */ function getOrCreateSpanMap(transport) { let spanMap = transportToSpanMap.get(transport); if (!spanMap) { spanMap = new Map(); transportToSpanMap.set(transport, spanMap); } return spanMap; } /** * Stores span context for later correlation with handler execution * @param transport - MCP transport instance * @param requestId - Request identifier * @param span - Active span to correlate * @param method - MCP method name */ function storeSpanForRequest(transport, requestId, span, method) { const spanMap = getOrCreateSpanMap(transport); spanMap.set(requestId, { span, method, // eslint-disable-next-line @sentry-internal/sdk/no-unsafe-random-apis startTime: Date.now(), }); } /** * Completes span with results and cleans up correlation * @param transport - MCP transport instance * @param requestId - Request identifier * @param result - Execution result for attribute extraction * @param options - Resolved MCP options */ function completeSpanWithResults( transport, requestId, result, options, ) { const spanMap = getOrCreateSpanMap(transport); const spanData = spanMap.get(requestId); if (spanData) { const { span, method } = spanData; if (method === 'initialize') { const sessionData = sessionExtraction.extractSessionDataFromInitializeResponse(result); const serverAttributes = sessionExtraction.buildServerAttributesFromInfo(sessionData.serverInfo); const initAttributes = { ...serverAttributes, }; if (sessionData.protocolVersion) { initAttributes[attributes.MCP_PROTOCOL_VERSION_ATTRIBUTE] = sessionData.protocolVersion; } span.setAttributes(initAttributes); } else if (method === 'tools/call') { const toolAttributes = resultExtraction.extractToolResultAttributes(result, options.recordOutputs); span.setAttributes(toolAttributes); } else if (method === 'prompts/get') { const promptAttributes = resultExtraction.extractPromptResultAttributes(result, options.recordOutputs); span.setAttributes(promptAttributes); } span.end(); spanMap.delete(requestId); } } /** * Cleans up pending spans for a specific transport (when that transport closes) * @param transport - MCP transport instance */ function cleanupPendingSpansForTransport(transport) { const spanMap = transportToSpanMap.get(transport); if (spanMap) { for (const [, spanData] of spanMap) { spanData.span.setStatus({ code: spanstatus.SPAN_STATUS_ERROR, message: 'cancelled', }); spanData.span.end(); } spanMap.clear(); } } exports.cleanupPendingSpansForTransport = cleanupPendingSpansForTransport; exports.completeSpanWithResults = completeSpanWithResults; exports.storeSpanForRequest = storeSpanForRequest; //# sourceMappingURL=correlation.js.map