@posthog/mcp
Advanced tools
@@ -1,2 +0,2 @@ | ||
| import type { MCPServerLike, McpEvent } from '../types'; | ||
| import type { MCPServerLike, McpEvent, SessionInfo } from '../types'; | ||
| import type { LoggerFn } from './logger'; | ||
@@ -13,3 +13,3 @@ /** | ||
| */ | ||
| export declare function captureEvent(server: MCPServerLike, eventInput: McpEvent, logger: LoggerFn): Promise<void> | undefined; | ||
| export declare function captureEvent(server: MCPServerLike, eventInput: McpEvent, logger: LoggerFn, requestAttribution?: SessionInfo): Promise<void> | undefined; | ||
| //# sourceMappingURL=capture.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/extensions/capture.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGxC;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAkErH"} | ||
| {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/extensions/capture.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAGpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGxC;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,QAAQ,EAChB,kBAAkB,CAAC,EAAE,WAAW,GAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAoE3B"} |
@@ -32,3 +32,3 @@ "use strict"; | ||
| const external_session_js_namespaceObject = require("./session.js"); | ||
| function captureEvent(server, eventInput, logger) { | ||
| function captureEvent(server, eventInput, logger, requestAttribution) { | ||
| const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server); | ||
@@ -38,3 +38,3 @@ if (!data) return void logger('Warning: Server tracking data not found. Event will not be published.'); | ||
| if (!sink) return; | ||
| const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, eventInput.sessionId); | ||
| const sessionInfo = requestAttribution ?? (0, external_session_js_namespaceObject.getSessionInfo)(server, data, eventInput.sessionId); | ||
| const duration = eventInput.duration || (eventInput.timestamp ? Date.now() - eventInput.timestamp.getTime() : void 0); | ||
@@ -41,0 +41,0 @@ const fullEvent = { |
| import { MCPAnalyticsEventType } from "./event-types.mjs"; | ||
| import { getServerTrackingData } from "./internal.mjs"; | ||
| import { getSessionInfo } from "./session.mjs"; | ||
| function captureEvent(server, eventInput, logger) { | ||
| function captureEvent(server, eventInput, logger, requestAttribution) { | ||
| const data = getServerTrackingData(server); | ||
@@ -9,3 +9,3 @@ if (!data) return void logger('Warning: Server tracking data not found. Event will not be published.'); | ||
| if (!sink) return; | ||
| const sessionInfo = getSessionInfo(server, data, eventInput.sessionId); | ||
| const sessionInfo = requestAttribution ?? getSessionInfo(server, data, eventInput.sessionId); | ||
| const duration = eventInput.duration || (eventInput.timestamp ? Date.now() - eventInput.timestamp.getTime() : void 0); | ||
@@ -12,0 +12,0 @@ const fullEvent = { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"} |
@@ -58,4 +58,4 @@ "use strict"; | ||
| const startTime = new Date(); | ||
| const event = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType); | ||
| if (event && explicitContextIntent) (0, external_intent_js_namespaceObject.setExplicitContextIntent)(event, explicitContextIntent); | ||
| const preparedEvent = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType); | ||
| if (preparedEvent && explicitContextIntent) (0, external_intent_js_namespaceObject.setExplicitContextIntent)(preparedEvent.event, explicitContextIntent); | ||
| let result; | ||
@@ -65,7 +65,7 @@ try { | ||
| } catch (error) { | ||
| publishFailedToolEvent(server, event, error, startTime, conversation, data.logger); | ||
| publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger); | ||
| throw error; | ||
| } | ||
| const finalResult = applyConversationPromptBack(event, result, conversation); | ||
| publishSuccessfulToolEvent(server, event, finalResult, startTime, data.logger, takeCapturedError); | ||
| const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation); | ||
| publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError); | ||
| return finalResult; | ||
@@ -95,3 +95,5 @@ } | ||
| const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra); | ||
| await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra); | ||
| const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId); | ||
| const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, sessionInfo, extra); | ||
| const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(sessionInfo, identity); | ||
| const toolName = request.params?.name; | ||
@@ -111,3 +113,6 @@ const event = { | ||
| (0, external_intent_js_namespaceObject.setEventIntent)(event, await (0, external_intent_js_namespaceObject.resolveToolCallIntent)(data, request, ownership.context, extra)); | ||
| return event; | ||
| return { | ||
| event, | ||
| requestAttribution | ||
| }; | ||
| } catch (error) { | ||
@@ -124,4 +129,5 @@ data.logger(`Warning: PostHog MCP analytics instrumentation failed for tool ${request.params?.name}, the tool will still run - ${error}`); | ||
| } | ||
| function publishSuccessfulToolEvent(server, event, result, startTime, logger, takeCapturedError) { | ||
| if (!event) return; | ||
| function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) { | ||
| if (!preparedEvent) return; | ||
| const { event, requestAttribution } = preparedEvent; | ||
| try { | ||
@@ -135,3 +141,3 @@ if ((0, external_tracing_helpers_js_namespaceObject.isToolResultError)(result)) { | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger, requestAttribution); | ||
| } catch (error) { | ||
@@ -141,4 +147,5 @@ logger(`Warning: PostHog MCP analytics failed to publish tool event - ${error}`); | ||
| } | ||
| function publishFailedToolEvent(server, event, error, startTime, conversation, logger) { | ||
| if (!event) return; | ||
| function publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, logger) { | ||
| if (!preparedEvent) return; | ||
| const { event, requestAttribution } = preparedEvent; | ||
| try { | ||
@@ -149,3 +156,3 @@ if (conversation.minted) event.conversationId = void 0; | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger, requestAttribution); | ||
| } catch (publishError) { | ||
@@ -205,4 +212,6 @@ logger(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`); | ||
| const startTime = new Date(); | ||
| const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra); | ||
| const requestAttribution = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId); | ||
| const event = { | ||
| sessionId: (0, external_session_js_namespaceObject.getSessionId)(server, extra), | ||
| sessionId, | ||
| parameters: (0, external_mcp_payloads_js_namespaceObject.buildCapturedMcpParameters)(request), | ||
@@ -214,3 +223,3 @@ eventType: external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpToolsList, | ||
| if (data) await (0, external_tracing_helpers_js_namespaceObject.applyResolvedMetadata)(event, data, request, extra); | ||
| const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger); | ||
| const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution); | ||
| if (!data) { | ||
@@ -227,3 +236,3 @@ logger('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.'); | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger, requestAttribution); | ||
| return { | ||
@@ -239,3 +248,3 @@ tools | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger, requestAttribution); | ||
| return { | ||
@@ -253,3 +262,3 @@ tools | ||
| } | ||
| async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger) { | ||
| async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution) { | ||
| try { | ||
@@ -286,3 +295,3 @@ const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server); | ||
| event.duration = event.timestamp ? Date.now() - event.timestamp.getTime() : 0; | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger, requestAttribution); | ||
| throw error; | ||
@@ -336,3 +345,3 @@ } | ||
| } | ||
| function upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion) { | ||
| function upgradeMintedTokenToNegotiated(server, mintedSessionId, sessionInfo, negotiatedProtocolVersion, logger) { | ||
| try { | ||
@@ -343,4 +352,4 @@ const transport = server.transport; | ||
| sessionId: mintedSessionId, | ||
| clientName: data.sessionInfo.clientName, | ||
| clientVersion: data.sessionInfo.clientVersion, | ||
| clientName: sessionInfo.clientName, | ||
| clientVersion: sessionInfo.clientVersion, | ||
| protocolVersion: negotiatedProtocolVersion | ||
@@ -350,3 +359,3 @@ }); | ||
| } catch (error) { | ||
| data.logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`); | ||
| logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`); | ||
| } | ||
@@ -371,3 +380,11 @@ } | ||
| const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra); | ||
| await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra); | ||
| const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId); | ||
| const initializeClientInfo = readInitializeClientInfo(request); | ||
| const requestSessionInfo = { | ||
| ...sessionInfo, | ||
| clientName: initializeClientInfo?.name ?? sessionInfo.clientName, | ||
| clientVersion: initializeClientInfo?.version ?? sessionInfo.clientVersion | ||
| }; | ||
| const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, requestSessionInfo, extra); | ||
| const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(requestSessionInfo, identity); | ||
| const event = { | ||
@@ -386,6 +403,14 @@ sessionId, | ||
| event.protocolVersion = negotiatedProtocolVersion; | ||
| data.sessionInfo.protocolVersion = negotiatedProtocolVersion; | ||
| (0, external_internal_js_namespaceObject.setServerTrackingData)(server, data); | ||
| if (mintedSessionId) upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger); | ||
| if (data.sessionId === sessionId) { | ||
| data.sessionInfo = { | ||
| ...data.sessionInfo, | ||
| protocolVersion: negotiatedProtocolVersion | ||
| }; | ||
| (0, external_internal_js_namespaceObject.setServerTrackingData)(server, data); | ||
| } | ||
| if (mintedSessionId) upgradeMintedTokenToNegotiated(server, mintedSessionId, requestSessionInfo, negotiatedProtocolVersion, data.logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger, { | ||
| ...requestAttribution, | ||
| protocolVersion: negotiatedProtocolVersion | ||
| }); | ||
| return result; | ||
@@ -392,0 +417,0 @@ } |
@@ -9,6 +9,6 @@ import { getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from "./analytics-parameters.mjs"; | ||
| import { resolveToolCallIntent, setEventIntent, setExplicitContextIntent } from "./intent.mjs"; | ||
| import { getServerTrackingData, handleIdentify, setServerTrackingData } from "./internal.mjs"; | ||
| import { getServerTrackingData, handleIdentify, setServerTrackingData, withIdentity } from "./internal.mjs"; | ||
| import { buildCapturedMcpParameters } from "./mcp-payloads.mjs"; | ||
| import { getLiteralValue, getObjectShape } from "./mcp-sdk-compat.mjs"; | ||
| import { getSessionId, newSessionId } from "./session.mjs"; | ||
| import { getSessionId, getSessionInfo, newSessionId } from "./session.mjs"; | ||
| import { encodeSessionId, readMcpSessionHeader, writeSessionIdToTransport } from "./session-token.mjs"; | ||
@@ -24,4 +24,4 @@ import { getReportMissingToolDescriptor, resolveMissingCapabilityToolName } from "./tools.mjs"; | ||
| const startTime = new Date(); | ||
| const event = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType); | ||
| if (event && explicitContextIntent) setExplicitContextIntent(event, explicitContextIntent); | ||
| const preparedEvent = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType); | ||
| if (preparedEvent && explicitContextIntent) setExplicitContextIntent(preparedEvent.event, explicitContextIntent); | ||
| let result; | ||
@@ -31,7 +31,7 @@ try { | ||
| } catch (error) { | ||
| publishFailedToolEvent(server, event, error, startTime, conversation, data.logger); | ||
| publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger); | ||
| throw error; | ||
| } | ||
| const finalResult = applyConversationPromptBack(event, result, conversation); | ||
| publishSuccessfulToolEvent(server, event, finalResult, startTime, data.logger, takeCapturedError); | ||
| const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation); | ||
| publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError); | ||
| return finalResult; | ||
@@ -61,3 +61,5 @@ } | ||
| const sessionId = getSessionId(server, extra); | ||
| await handleIdentify(server, data, sessionId, request, extra); | ||
| const sessionInfo = getSessionInfo(server, data, sessionId); | ||
| const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra); | ||
| const requestAttribution = withIdentity(sessionInfo, identity); | ||
| const toolName = request.params?.name; | ||
@@ -77,3 +79,6 @@ const event = { | ||
| setEventIntent(event, await resolveToolCallIntent(data, request, ownership.context, extra)); | ||
| return event; | ||
| return { | ||
| event, | ||
| requestAttribution | ||
| }; | ||
| } catch (error) { | ||
@@ -90,4 +95,5 @@ data.logger(`Warning: PostHog MCP analytics instrumentation failed for tool ${request.params?.name}, the tool will still run - ${error}`); | ||
| } | ||
| function publishSuccessfulToolEvent(server, event, result, startTime, logger, takeCapturedError) { | ||
| if (!event) return; | ||
| function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) { | ||
| if (!preparedEvent) return; | ||
| const { event, requestAttribution } = preparedEvent; | ||
| try { | ||
@@ -101,3 +107,3 @@ if (isToolResultError(result)) { | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| captureEvent(server, event, logger); | ||
| captureEvent(server, event, logger, requestAttribution); | ||
| } catch (error) { | ||
@@ -107,4 +113,5 @@ logger(`Warning: PostHog MCP analytics failed to publish tool event - ${error}`); | ||
| } | ||
| function publishFailedToolEvent(server, event, error, startTime, conversation, logger) { | ||
| if (!event) return; | ||
| function publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, logger) { | ||
| if (!preparedEvent) return; | ||
| const { event, requestAttribution } = preparedEvent; | ||
| try { | ||
@@ -115,3 +122,3 @@ if (conversation.minted) event.conversationId = void 0; | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| captureEvent(server, event, logger); | ||
| captureEvent(server, event, logger, requestAttribution); | ||
| } catch (publishError) { | ||
@@ -171,4 +178,6 @@ logger(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`); | ||
| const startTime = new Date(); | ||
| const sessionId = getSessionId(server, extra); | ||
| const requestAttribution = getSessionInfo(server, data, sessionId); | ||
| const event = { | ||
| sessionId: getSessionId(server, extra), | ||
| sessionId, | ||
| parameters: buildCapturedMcpParameters(request), | ||
@@ -180,3 +189,3 @@ eventType: MCPAnalyticsEventType.mcpToolsList, | ||
| if (data) await applyResolvedMetadata(event, data, request, extra); | ||
| const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger); | ||
| const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution); | ||
| if (!data) { | ||
@@ -193,3 +202,3 @@ logger('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.'); | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| captureEvent(server, event, data.logger); | ||
| captureEvent(server, event, data.logger, requestAttribution); | ||
| return { | ||
@@ -205,3 +214,3 @@ tools | ||
| event.duration = Date.now() - startTime.getTime(); | ||
| captureEvent(server, event, data.logger); | ||
| captureEvent(server, event, data.logger, requestAttribution); | ||
| return { | ||
@@ -219,3 +228,3 @@ tools | ||
| } | ||
| async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger) { | ||
| async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution) { | ||
| try { | ||
@@ -252,3 +261,3 @@ const data = getServerTrackingData(server); | ||
| event.duration = event.timestamp ? Date.now() - event.timestamp.getTime() : 0; | ||
| captureEvent(server, event, logger); | ||
| captureEvent(server, event, logger, requestAttribution); | ||
| throw error; | ||
@@ -302,3 +311,3 @@ } | ||
| } | ||
| function upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion) { | ||
| function upgradeMintedTokenToNegotiated(server, mintedSessionId, sessionInfo, negotiatedProtocolVersion, logger) { | ||
| try { | ||
@@ -309,4 +318,4 @@ const transport = server.transport; | ||
| sessionId: mintedSessionId, | ||
| clientName: data.sessionInfo.clientName, | ||
| clientVersion: data.sessionInfo.clientVersion, | ||
| clientName: sessionInfo.clientName, | ||
| clientVersion: sessionInfo.clientVersion, | ||
| protocolVersion: negotiatedProtocolVersion | ||
@@ -316,3 +325,3 @@ }); | ||
| } catch (error) { | ||
| data.logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`); | ||
| logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`); | ||
| } | ||
@@ -337,3 +346,11 @@ } | ||
| const sessionId = getSessionId(server, extra); | ||
| await handleIdentify(server, data, sessionId, request, extra); | ||
| const sessionInfo = getSessionInfo(server, data, sessionId); | ||
| const initializeClientInfo = readInitializeClientInfo(request); | ||
| const requestSessionInfo = { | ||
| ...sessionInfo, | ||
| clientName: initializeClientInfo?.name ?? sessionInfo.clientName, | ||
| clientVersion: initializeClientInfo?.version ?? sessionInfo.clientVersion | ||
| }; | ||
| const identity = await handleIdentify(server, data, sessionId, request, requestSessionInfo, extra); | ||
| const requestAttribution = withIdentity(requestSessionInfo, identity); | ||
| const event = { | ||
@@ -352,6 +369,14 @@ sessionId, | ||
| event.protocolVersion = negotiatedProtocolVersion; | ||
| data.sessionInfo.protocolVersion = negotiatedProtocolVersion; | ||
| setServerTrackingData(server, data); | ||
| if (mintedSessionId) upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion); | ||
| captureEvent(server, event, data.logger); | ||
| if (data.sessionId === sessionId) { | ||
| data.sessionInfo = { | ||
| ...data.sessionInfo, | ||
| protocolVersion: negotiatedProtocolVersion | ||
| }; | ||
| setServerTrackingData(server, data); | ||
| } | ||
| if (mintedSessionId) upgradeMintedTokenToNegotiated(server, mintedSessionId, requestSessionInfo, negotiatedProtocolVersion, data.logger); | ||
| captureEvent(server, event, data.logger, { | ||
| ...requestAttribution, | ||
| protocolVersion: negotiatedProtocolVersion | ||
| }); | ||
| return result; | ||
@@ -358,0 +383,0 @@ } |
@@ -1,2 +0,2 @@ | ||
| import type { CompatibleRequestHandlerExtra, MCPAnalyticsData, MCPRequestLike, MCPServerLike, UserIdentity } from '../types'; | ||
| import type { CompatibleRequestHandlerExtra, MCPAnalyticsData, MCPRequestLike, MCPServerLike, SessionInfo, UserIdentity } from '../types'; | ||
| /** | ||
@@ -27,3 +27,4 @@ * Bounded LRU cache for session identities, capped at `maxSize` entries so a | ||
| */ | ||
| export declare function handleIdentify(server: MCPServerLike, data: MCPAnalyticsData, sessionId: string, request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra): Promise<void>; | ||
| export declare function handleIdentify(server: MCPServerLike, data: MCPAnalyticsData, sessionId: string, request: MCPRequestLike, requestAttribution: SessionInfo, extra?: CompatibleRequestHandlerExtra): Promise<UserIdentity | undefined>; | ||
| export declare function withIdentity(sessionInfo: SessionInfo, identity: UserIdentity | undefined): SessionInfo; | ||
| /** | ||
@@ -30,0 +31,0 @@ * Resolves the `eventProperties` callback. Returns null when no callback is |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"} | ||
| {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,WAAW,EACX,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,kBAAkB,EAAE,WAAW,EAC/B,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAsDnC;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,CAOtG;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"} |
@@ -29,7 +29,8 @@ "use strict"; | ||
| areIdentitiesEqual: ()=>areIdentitiesEqual, | ||
| getServerTrackingData: ()=>getServerTrackingData, | ||
| setServerTrackingData: ()=>setServerTrackingData, | ||
| resolveEventProperties: ()=>resolveEventProperties, | ||
| withIdentity: ()=>withIdentity, | ||
| handleIdentify: ()=>handleIdentify, | ||
| getServerTrackingData: ()=>getServerTrackingData, | ||
| IdentityCache: ()=>IdentityCache, | ||
| setServerTrackingData: ()=>setServerTrackingData | ||
| IdentityCache: ()=>IdentityCache | ||
| }); | ||
@@ -98,4 +99,6 @@ const external_event_types_js_namespaceObject = require("./event-types.js"); | ||
| } | ||
| async function handleIdentify(server, data, sessionId, request, extra) { | ||
| if (!data.options.identify) return; | ||
| async function handleIdentify(server, data, sessionId, request, requestAttribution, extra) { | ||
| const identityBeforeRequest = data.identifiedSessions.get(sessionId); | ||
| const sessionSourceBeforeIdentify = data.sessionSource; | ||
| if (!data.options.identify) return identityBeforeRequest; | ||
| const identifyEvent = { | ||
@@ -119,3 +122,3 @@ sessionId, | ||
| const firstSeen = void 0 === previousIdentity; | ||
| const announcedAtInitialize = 'token' === data.sessionSource && 'initialize' !== request.method; | ||
| const announcedAtInitialize = 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method; | ||
| const shouldPublish = changed || firstSeen && !announcedAtInitialize; | ||
@@ -125,9 +128,20 @@ data.identifiedSessions.set(sessionId, mergedIdentity); | ||
| data.logger(`Identified session ${sessionId}`); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, identifyEvent, data.logger); | ||
| (0, external_capture_js_namespaceObject.captureEvent)(server, identifyEvent, data.logger, withIdentity(requestAttribution, mergedIdentity)); | ||
| } | ||
| } else data.logger(`Warning: Supplied identify function returned null for session ${sessionId}`); | ||
| return mergedIdentity; | ||
| } | ||
| data.logger(`Warning: Supplied identify function returned null for session ${sessionId}`); | ||
| } catch (error) { | ||
| data.logger(`Error: User supplied identify function threw an error while identifying session ${sessionId} - ${error}`); | ||
| } | ||
| return identityBeforeRequest; | ||
| } | ||
| function withIdentity(sessionInfo, identity) { | ||
| return { | ||
| ...sessionInfo, | ||
| identifyActorGivenId: identity?.distinctId, | ||
| identifyActorData: identity?.properties || {}, | ||
| identifyActorGroups: identity?.groups | ||
| }; | ||
| } | ||
| async function resolveEventProperties(data, request, extra) { | ||
@@ -155,2 +169,3 @@ if (!data.options.eventProperties) return null; | ||
| exports.setServerTrackingData = __webpack_exports__.setServerTrackingData; | ||
| exports.withIdentity = __webpack_exports__.withIdentity; | ||
| for(var __webpack_i__ in __webpack_exports__)if (-1 === [ | ||
@@ -163,3 +178,4 @@ "IdentityCache", | ||
| "resolveEventProperties", | ||
| "setServerTrackingData" | ||
| "setServerTrackingData", | ||
| "withIdentity" | ||
| ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__]; | ||
@@ -166,0 +182,0 @@ Object.defineProperty(exports, '__esModule', { |
@@ -63,4 +63,6 @@ import { MCPAnalyticsEventType } from "./event-types.mjs"; | ||
| } | ||
| async function handleIdentify(server, data, sessionId, request, extra) { | ||
| if (!data.options.identify) return; | ||
| async function handleIdentify(server, data, sessionId, request, requestAttribution, extra) { | ||
| const identityBeforeRequest = data.identifiedSessions.get(sessionId); | ||
| const sessionSourceBeforeIdentify = data.sessionSource; | ||
| if (!data.options.identify) return identityBeforeRequest; | ||
| const identifyEvent = { | ||
@@ -84,3 +86,3 @@ sessionId, | ||
| const firstSeen = void 0 === previousIdentity; | ||
| const announcedAtInitialize = 'token' === data.sessionSource && 'initialize' !== request.method; | ||
| const announcedAtInitialize = 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method; | ||
| const shouldPublish = changed || firstSeen && !announcedAtInitialize; | ||
@@ -90,9 +92,20 @@ data.identifiedSessions.set(sessionId, mergedIdentity); | ||
| data.logger(`Identified session ${sessionId}`); | ||
| captureEvent(server, identifyEvent, data.logger); | ||
| captureEvent(server, identifyEvent, data.logger, withIdentity(requestAttribution, mergedIdentity)); | ||
| } | ||
| } else data.logger(`Warning: Supplied identify function returned null for session ${sessionId}`); | ||
| return mergedIdentity; | ||
| } | ||
| data.logger(`Warning: Supplied identify function returned null for session ${sessionId}`); | ||
| } catch (error) { | ||
| data.logger(`Error: User supplied identify function threw an error while identifying session ${sessionId} - ${error}`); | ||
| } | ||
| return identityBeforeRequest; | ||
| } | ||
| function withIdentity(sessionInfo, identity) { | ||
| return { | ||
| ...sessionInfo, | ||
| identifyActorGivenId: identity?.distinctId, | ||
| identifyActorData: identity?.properties || {}, | ||
| identifyActorGroups: identity?.groups | ||
| }; | ||
| } | ||
| async function resolveEventProperties(data, request, extra) { | ||
@@ -113,2 +126,2 @@ if (!data.options.eventProperties) return null; | ||
| } | ||
| export { IdentityCache, areIdentitiesEqual, getServerTrackingData, handleIdentify, mergeIdentities, resolveEventProperties, setServerTrackingData }; | ||
| export { IdentityCache, areIdentitiesEqual, getServerTrackingData, handleIdentify, mergeIdentities, resolveEventProperties, setServerTrackingData, withIdentity }; |
@@ -93,3 +93,5 @@ "use strict"; | ||
| (0, external_internal_js_namespaceObject.setServerTrackingData)(server, data); | ||
| return data.sessionInfo; | ||
| return { | ||
| ...sessionInfo | ||
| }; | ||
| } | ||
@@ -96,0 +98,0 @@ exports.deriveSessionIdFromMCPSession = __webpack_exports__.deriveSessionIdFromMCPSession; |
@@ -62,4 +62,6 @@ import { version } from "../version.mjs"; | ||
| setServerTrackingData(server, data); | ||
| return data.sessionInfo; | ||
| return { | ||
| ...sessionInfo | ||
| }; | ||
| } | ||
| export { deriveSessionIdFromMCPSession, getSessionId, getSessionInfo, newSessionId }; |
@@ -1,2 +0,2 @@ | ||
| export declare const version = "0.10.6"; | ||
| export declare const version = "0.10.7"; | ||
| //# sourceMappingURL=version.d.ts.map |
+1
-1
@@ -29,3 +29,3 @@ "use strict"; | ||
| }); | ||
| const version = '0.10.6'; | ||
| const version = '0.10.7'; | ||
| exports.version = __webpack_exports__.version; | ||
@@ -32,0 +32,0 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [ |
+1
-1
@@ -1,2 +0,2 @@ | ||
| const version = '0.10.6'; | ||
| const version = '0.10.7'; | ||
| export { version }; |
+3
-3
| { | ||
| "name": "@posthog/mcp", | ||
| "version": "0.10.6", | ||
| "version": "0.10.7", | ||
| "bugs": { | ||
@@ -42,4 +42,4 @@ "url": "https://github.com/PostHog/posthog-js/issues" | ||
| "zod": "^3.25.0", | ||
| "posthog-node": "^5.47.8", | ||
| "@posthog-tooling/tsconfig-base": "1.1.1" | ||
| "@posthog-tooling/tsconfig-base": "1.1.1", | ||
| "posthog-node": "^5.47.9" | ||
| }, | ||
@@ -46,0 +46,0 @@ "peerDependencies": { |
@@ -6,3 +6,3 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| import type { MCPServerLike, McpEvent } from '../types' | ||
| import type { MCPServerLike, McpEvent, SessionInfo } from '../types' | ||
| import { MCPAnalyticsEventType } from './event-types' | ||
@@ -23,3 +23,8 @@ import { getServerTrackingData } from './internal' | ||
| */ | ||
| export function captureEvent(server: MCPServerLike, eventInput: McpEvent, logger: LoggerFn): Promise<void> | undefined { | ||
| export function captureEvent( | ||
| server: MCPServerLike, | ||
| eventInput: McpEvent, | ||
| logger: LoggerFn, | ||
| requestAttribution?: SessionInfo | ||
| ): Promise<void> | undefined { | ||
| const data = getServerTrackingData(server) | ||
@@ -36,3 +41,6 @@ if (!data) { | ||
| const sessionInfo = getSessionInfo(server, data, eventInput.sessionId) | ||
| // Instrumented request paths pass an immutable snapshot resolved before any | ||
| // user callback or handler can yield to a concurrent request. Custom capture | ||
| // has no request context, so it intentionally falls back to current state. | ||
| const sessionInfo = requestAttribution ?? getSessionInfo(server, data, eventInput.sessionId) | ||
@@ -54,5 +62,4 @@ const duration = | ||
| serverVersion: sessionInfo.serverVersion, | ||
| // Prefer identity the event captured for *this* request (from `_meta`, see | ||
| // stampMetaClientInfo) over the server-wide sessionInfo, so a concurrent | ||
| // request from another client can't misattribute this one. | ||
| // Prefer client metadata stamped onto this event from the request's `_meta` | ||
| // over sessionInfo, so concurrent stateless requests stay isolated. | ||
| clientName: eventInput.clientName ?? sessionInfo.clientName, | ||
@@ -59,0 +66,0 @@ clientVersion: eventInput.clientVersion ?? sessionInfo.clientVersion, |
@@ -15,2 +15,3 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| ServerClientInfoLike, | ||
| SessionInfo, | ||
| } from '../types' | ||
@@ -31,7 +32,7 @@ import { getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from './analytics-parameters' | ||
| import { resolveToolCallIntent, setEventIntent, setExplicitContextIntent } from './intent' | ||
| import { getServerTrackingData, handleIdentify, setServerTrackingData } from './internal' | ||
| import { getServerTrackingData, handleIdentify, setServerTrackingData, withIdentity } from './internal' | ||
| import type { LoggerFn } from './logger' | ||
| import { buildCapturedMcpParameters } from './mcp-payloads' | ||
| import { getLiteralValue, getObjectShape } from './mcp-sdk-compat' | ||
| import { getSessionId, newSessionId } from './session' | ||
| import { getSessionId, getSessionInfo, newSessionId } from './session' | ||
| import { encodeSessionId, readMcpSessionHeader, writeSessionIdToTransport } from './session-token' | ||
@@ -123,3 +124,3 @@ import { getReportMissingToolDescriptor, resolveMissingCapabilityToolName } from './tools' | ||
| const startTime = new Date() | ||
| const event = await prepareToolCallEvent( | ||
| const preparedEvent = await prepareToolCallEvent( | ||
| server, | ||
@@ -135,4 +136,4 @@ data, | ||
| ) | ||
| if (event && explicitContextIntent) { | ||
| setExplicitContextIntent(event, explicitContextIntent) | ||
| if (preparedEvent && explicitContextIntent) { | ||
| setExplicitContextIntent(preparedEvent.event, explicitContextIntent) | ||
| } | ||
@@ -144,11 +145,16 @@ | ||
| } catch (error) { | ||
| publishFailedToolEvent(server, event, error, startTime, conversation, data.logger) | ||
| publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger) | ||
| throw error | ||
| } | ||
| const finalResult = applyConversationPromptBack(event, result, conversation) | ||
| publishSuccessfulToolEvent(server, event, finalResult, startTime, data.logger, takeCapturedError) | ||
| const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation) | ||
| publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError) | ||
| return finalResult | ||
| } | ||
| interface PreparedToolEvent { | ||
| event: McpEvent | ||
| requestAttribution: SessionInfo | ||
| } | ||
| function getActiveAnalyticsParameterOwnership( | ||
@@ -196,6 +202,10 @@ data: MCPAnalyticsData, | ||
| eventType: MCPAnalyticsEventType | ||
| ): Promise<McpEvent | null> { | ||
| ): Promise<PreparedToolEvent | null> { | ||
| try { | ||
| const sessionId = getSessionId(server, extra) | ||
| await handleIdentify(server, data, sessionId, request, extra) | ||
| // Snapshot token/client/protocol metadata synchronously, before identify or | ||
| // metadata callbacks can yield and let another request replace shared state. | ||
| const sessionInfo = getSessionInfo(server, data, sessionId) | ||
| const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra) | ||
| const requestAttribution = withIdentity(sessionInfo, identity) | ||
@@ -220,3 +230,3 @@ const toolName = request.params?.name | ||
| setEventIntent(event, await resolveToolCallIntent(data, request, ownership.context, extra)) | ||
| return event | ||
| return { event, requestAttribution } | ||
| } catch (error) { | ||
@@ -254,3 +264,3 @@ data.logger( | ||
| server: MCPServerLike, | ||
| event: McpEvent | null, | ||
| preparedEvent: PreparedToolEvent | null, | ||
| result: unknown, | ||
@@ -261,5 +271,6 @@ startTime: Date, | ||
| ): void { | ||
| if (!event) { | ||
| if (!preparedEvent) { | ||
| return | ||
| } | ||
| const { event, requestAttribution } = preparedEvent | ||
| try { | ||
@@ -275,3 +286,3 @@ if (isToolResultError(result)) { | ||
| event.duration = Date.now() - startTime.getTime() | ||
| captureEvent(server, event, logger) | ||
| captureEvent(server, event, logger, requestAttribution) | ||
| } catch (error) { | ||
@@ -284,3 +295,3 @@ logger(`Warning: PostHog MCP analytics failed to publish tool event - ${error}`) | ||
| server: MCPServerLike, | ||
| event: McpEvent | null, | ||
| preparedEvent: PreparedToolEvent | null, | ||
| error: unknown, | ||
@@ -291,5 +302,6 @@ startTime: Date, | ||
| ): void { | ||
| if (!event) { | ||
| if (!preparedEvent) { | ||
| return | ||
| } | ||
| const { event, requestAttribution } = preparedEvent | ||
| try { | ||
@@ -302,3 +314,3 @@ if (conversation.minted) { | ||
| event.duration = Date.now() - startTime.getTime() | ||
| captureEvent(server, event, logger) | ||
| captureEvent(server, event, logger, requestAttribution) | ||
| } catch (publishError) { | ||
@@ -423,4 +435,8 @@ logger(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`) | ||
| const startTime = new Date() | ||
| const sessionId = getSessionId(server, extra) | ||
| // Snapshot before metadata resolution or the list handler can yield to a | ||
| // concurrent request using the same instrumented server. | ||
| const requestAttribution = getSessionInfo(server, data, sessionId) | ||
| const event: McpEvent = { | ||
| sessionId: getSessionId(server, extra), | ||
| sessionId, | ||
| parameters: buildCapturedMcpParameters(request), | ||
@@ -436,3 +452,11 @@ eventType: MCPAnalyticsEventType.mcpToolsList, | ||
| const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger) | ||
| const tools = await getTracedToolsList( | ||
| server, | ||
| originalListToolsHandler, | ||
| request, | ||
| extra, | ||
| event, | ||
| logger, | ||
| requestAttribution | ||
| ) | ||
@@ -453,3 +477,3 @@ if (!data) { | ||
| event.duration = Date.now() - startTime.getTime() | ||
| captureEvent(server, event, data.logger) | ||
| captureEvent(server, event, data.logger, requestAttribution) | ||
| return { tools } | ||
@@ -462,3 +486,3 @@ } | ||
| event.duration = Date.now() - startTime.getTime() | ||
| captureEvent(server, event, data.logger) | ||
| captureEvent(server, event, data.logger, requestAttribution) | ||
| return { tools } | ||
@@ -493,3 +517,4 @@ } | ||
| event: McpEvent, | ||
| logger: LoggerFn | ||
| logger: LoggerFn, | ||
| requestAttribution: SessionInfo | ||
| ): Promise<ListToolsResult['tools']> { | ||
@@ -542,3 +567,3 @@ try { | ||
| event.duration = event.timestamp ? Date.now() - event.timestamp.getTime() : 0 | ||
| captureEvent(server, event, logger) | ||
| captureEvent(server, event, logger, requestAttribution) | ||
| throw error | ||
@@ -652,5 +677,6 @@ } | ||
| server: MCPServerLike, | ||
| data: MCPAnalyticsData, | ||
| mintedSessionId: string, | ||
| negotiatedProtocolVersion: string | undefined | ||
| sessionInfo: SessionInfo, | ||
| negotiatedProtocolVersion: string | undefined, | ||
| logger: LoggerFn | ||
| ): void { | ||
@@ -664,4 +690,4 @@ try { | ||
| sessionId: mintedSessionId, | ||
| clientName: data.sessionInfo.clientName, | ||
| clientVersion: data.sessionInfo.clientVersion, | ||
| clientName: sessionInfo.clientName, | ||
| clientVersion: sessionInfo.clientVersion, | ||
| protocolVersion: negotiatedProtocolVersion, | ||
@@ -671,3 +697,3 @@ }) | ||
| } catch (error) { | ||
| data.logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`) | ||
| logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`) | ||
| } | ||
@@ -714,3 +740,13 @@ } | ||
| const sessionId = getSessionId(server, extra) | ||
| await handleIdentify(server, data, sessionId, request, extra) | ||
| // Snapshot before identify, metadata, or the initialize handler can yield to | ||
| // another request using the same instrumented server. | ||
| const sessionInfo = getSessionInfo(server, data, sessionId) | ||
| const initializeClientInfo = readInitializeClientInfo(request) | ||
| const requestSessionInfo: SessionInfo = { | ||
| ...sessionInfo, | ||
| clientName: initializeClientInfo?.name ?? sessionInfo.clientName, | ||
| clientVersion: initializeClientInfo?.version ?? sessionInfo.clientVersion, | ||
| } | ||
| const identity = await handleIdentify(server, data, sessionId, request, requestSessionInfo, extra) | ||
| const requestAttribution = withIdentity(requestSessionInfo, identity) | ||
@@ -738,8 +774,15 @@ const event: McpEvent = { | ||
| event.protocolVersion = negotiatedProtocolVersion | ||
| data.sessionInfo.protocolVersion = negotiatedProtocolVersion | ||
| setServerTrackingData(server, data) | ||
| // Do not let a delayed initialize overwrite whichever session became current | ||
| // while its callbacks or the original handler were awaiting. | ||
| if (data.sessionId === sessionId) { | ||
| data.sessionInfo = { ...data.sessionInfo, protocolVersion: negotiatedProtocolVersion } | ||
| setServerTrackingData(server, data) | ||
| } | ||
| if (mintedSessionId) { | ||
| upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion) | ||
| upgradeMintedTokenToNegotiated(server, mintedSessionId, requestSessionInfo, negotiatedProtocolVersion, data.logger) | ||
| } | ||
| captureEvent(server, event, data.logger) | ||
| captureEvent(server, event, data.logger, { | ||
| ...requestAttribution, | ||
| protocolVersion: negotiatedProtocolVersion, | ||
| }) | ||
| return result | ||
@@ -746,0 +789,0 @@ } |
@@ -12,2 +12,3 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| McpEvent, | ||
| SessionInfo, | ||
| UserIdentity, | ||
@@ -132,6 +133,9 @@ } from '../types' | ||
| request: MCPRequestLike, | ||
| requestAttribution: SessionInfo, | ||
| extra?: CompatibleRequestHandlerExtra | ||
| ): Promise<void> { | ||
| ): Promise<UserIdentity | undefined> { | ||
| const identityBeforeRequest = data.identifiedSessions.get(sessionId) | ||
| const sessionSourceBeforeIdentify = data.sessionSource | ||
| if (!data.options.identify) { | ||
| return | ||
| return identityBeforeRequest | ||
| } | ||
@@ -167,3 +171,3 @@ | ||
| const firstSeen = previousIdentity === undefined | ||
| const announcedAtInitialize = data.sessionSource === 'token' && request.method !== 'initialize' | ||
| const announcedAtInitialize = sessionSourceBeforeIdentify === 'token' && request.method !== 'initialize' | ||
| const shouldPublish = changed || (firstSeen && !announcedAtInitialize) | ||
@@ -175,7 +179,8 @@ | ||
| data.logger(`Identified session ${sessionId}`) | ||
| captureEvent(server, identifyEvent, data.logger) | ||
| captureEvent(server, identifyEvent, data.logger, withIdentity(requestAttribution, mergedIdentity)) | ||
| } | ||
| } else { | ||
| data.logger(`Warning: Supplied identify function returned null for session ${sessionId}`) | ||
| return mergedIdentity | ||
| } | ||
| data.logger(`Warning: Supplied identify function returned null for session ${sessionId}`) | ||
| } catch (error) { | ||
@@ -186,4 +191,14 @@ data.logger( | ||
| } | ||
| return identityBeforeRequest | ||
| } | ||
| export function withIdentity(sessionInfo: SessionInfo, identity: UserIdentity | undefined): SessionInfo { | ||
| return { | ||
| ...sessionInfo, | ||
| identifyActorGivenId: identity?.distinctId, | ||
| identifyActorData: identity?.properties || {}, | ||
| identifyActorGroups: identity?.groups, | ||
| } | ||
| } | ||
| /** | ||
@@ -190,0 +205,0 @@ * Resolves the `eventProperties` callback. Returns null when no callback is |
@@ -128,3 +128,3 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| setServerTrackingData(server, data) | ||
| return data.sessionInfo | ||
| return { ...sessionInfo } | ||
| } |
+1
-1
@@ -1,1 +0,1 @@ | ||
| export const version = '0.10.6' | ||
| export const version = '0.10.7' |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
583465
1.32%11845
1.25%1
Infinity%