@posthog/mcp 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/extensions/capture.d.ts +2 -2
  2. package/dist/extensions/capture.d.ts.map +1 -1
  3. package/dist/extensions/capture.js +2 -2
  4. package/dist/extensions/capture.mjs +2 -2
  5. package/dist/extensions/context-parameters.d.ts.map +1 -1
  6. package/dist/extensions/context-parameters.js +1 -4
  7. package/dist/extensions/context-parameters.mjs +1 -4
  8. package/dist/extensions/conversation-id.d.ts +1 -1
  9. package/dist/extensions/conversation-id.d.ts.map +1 -1
  10. package/dist/extensions/conversation-id.js +2 -2
  11. package/dist/extensions/conversation-id.mjs +2 -2
  12. package/dist/extensions/instrument-highlevel.d.ts.map +1 -1
  13. package/dist/extensions/instrument-highlevel.js +5 -5
  14. package/dist/extensions/instrument-highlevel.mjs +6 -6
  15. package/dist/extensions/instrument-lowlevel.d.ts.map +1 -1
  16. package/dist/extensions/instrument-lowlevel.js +9 -4
  17. package/dist/extensions/instrument-lowlevel.mjs +10 -5
  18. package/dist/extensions/instrumentation.d.ts +6 -6
  19. package/dist/extensions/instrumentation.d.ts.map +1 -1
  20. package/dist/extensions/instrumentation.js +112 -42
  21. package/dist/extensions/instrumentation.mjs +110 -43
  22. package/dist/extensions/intent.d.ts.map +1 -1
  23. package/dist/extensions/intent.js +1 -1
  24. package/dist/extensions/intent.mjs +1 -1
  25. package/dist/extensions/internal.d.ts +3 -2
  26. package/dist/extensions/internal.d.ts.map +1 -1
  27. package/dist/extensions/internal.js +25 -9
  28. package/dist/extensions/internal.mjs +19 -6
  29. package/dist/extensions/session.js +3 -1
  30. package/dist/extensions/session.mjs +3 -1
  31. package/dist/version.d.ts +1 -1
  32. package/dist/version.js +1 -1
  33. package/dist/version.mjs +1 -1
  34. package/package.json +2 -2
  35. package/src/extensions/capture.ts +13 -6
  36. package/src/extensions/context-parameters.ts +1 -7
  37. package/src/extensions/conversation-id.ts +2 -1
  38. package/src/extensions/instrument-highlevel.ts +8 -13
  39. package/src/extensions/instrument-lowlevel.ts +17 -6
  40. package/src/extensions/instrumentation.ts +166 -51
  41. package/src/extensions/intent.ts +1 -6
  42. package/src/extensions/internal.ts +21 -6
  43. package/src/extensions/session.ts +1 -1
  44. package/src/version.ts +1 -1
@@ -24,11 +24,12 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
- readToolMetaCategory: ()=>readToolMetaCategory,
27
+ isToolAdvertised: ()=>isToolAdvertised,
28
28
  cacheToolDescriptions: ()=>cacheToolDescriptions,
29
- cacheToolCategories: ()=>cacheToolCategories,
30
29
  handleInitializeRequest: ()=>handleInitializeRequest,
31
30
  captureToolCall: ()=>captureToolCall,
31
+ readToolMetaCategory: ()=>readToolMetaCategory,
32
+ cacheToolCategories: ()=>cacheToolCategories,
32
33
  handleListToolsRequest: ()=>handleListToolsRequest,
33
34
  patchRequestHandlers: ()=>patchRequestHandlers
34
35
  });
@@ -49,26 +50,26 @@ const external_tools_js_namespaceObject = require("./tools.js");
49
50
  const external_tracing_helpers_js_namespaceObject = require("./tracing-helpers.js");
50
51
  async function captureToolCall(params) {
51
52
  const { server, data, request, extra, execute, parameterOwnership, eventType, explicitContextIntent, takeCapturedError } = params;
52
- const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership);
53
- const conversation = (0, external_conversation_id_js_namespaceObject.resolveConversationId)(ownership.conversationId, request.params?.arguments, request.params?.name, (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options));
53
+ const resolvedEventType = eventType ?? external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpToolsCall;
54
+ const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership, resolvedEventType === external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability);
55
+ const conversation = (0, external_conversation_id_js_namespaceObject.resolveConversationId)(ownership.conversationId, request.params?.arguments, request.params?.name, resolvedEventType === external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability ? (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options) : '');
54
56
  const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership);
55
57
  const startTime = new Date();
56
- const event = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, eventType ?? external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpToolsCall);
57
- if (event && explicitContextIntent) (0, external_intent_js_namespaceObject.setExplicitContextIntent)(event, explicitContextIntent);
58
+ const preparedEvent = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType);
59
+ if (preparedEvent && explicitContextIntent) (0, external_intent_js_namespaceObject.setExplicitContextIntent)(preparedEvent.event, explicitContextIntent);
58
60
  let result;
59
61
  try {
60
62
  result = await execute(downstreamRequest);
61
63
  } catch (error) {
62
- publishFailedToolEvent(server, event, error, startTime, conversation, data.logger);
64
+ publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger);
63
65
  throw error;
64
66
  }
65
- const finalResult = applyConversationPromptBack(event, result, conversation);
66
- publishSuccessfulToolEvent(server, event, finalResult, startTime, data.logger, takeCapturedError);
67
+ const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation);
68
+ publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError);
67
69
  return finalResult;
68
70
  }
69
- function getActiveAnalyticsParameterOwnership(data, toolName, override) {
71
+ function getActiveAnalyticsParameterOwnership(data, toolName, override, isMissingCapabilityTool) {
70
72
  const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0);
71
- const isMissingCapabilityTool = toolName === (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options);
72
73
  return {
73
74
  context: !isMissingCapabilityTool && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context) && ownership?.context === true,
74
75
  conversationId: !isMissingCapabilityTool && true === data.options.enableConversationId && ownership?.conversationId === true
@@ -89,7 +90,9 @@ function cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) {
89
90
  async function prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, eventType) {
90
91
  try {
91
92
  const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra);
92
- await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra);
93
+ const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId);
94
+ const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, sessionInfo, extra);
95
+ const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(sessionInfo, identity);
93
96
  const toolName = request.params?.name;
94
97
  const event = {
95
98
  sessionId,
@@ -104,7 +107,10 @@ async function prepareToolCallEvent(server, data, request, downstreamRequest, ex
104
107
  (0, external_client_identity_js_namespaceObject.stampMetaClientInfo)(event, request);
105
108
  await (0, external_tracing_helpers_js_namespaceObject.applyResolvedMetadata)(event, data, request, extra);
106
109
  (0, external_intent_js_namespaceObject.setEventIntent)(event, await (0, external_intent_js_namespaceObject.resolveToolCallIntent)(data, request, ownership.context, extra));
107
- return event;
110
+ return {
111
+ event,
112
+ requestAttribution
113
+ };
108
114
  } catch (error) {
109
115
  data.logger(`Warning: PostHog MCP analytics instrumentation failed for tool ${request.params?.name}, the tool will still run - ${error}`);
110
116
  return null;
@@ -116,8 +122,9 @@ function applyConversationPromptBack(event, result, conversation) {
116
122
  if (event) event.conversationId = void 0;
117
123
  return result;
118
124
  }
119
- function publishSuccessfulToolEvent(server, event, result, startTime, logger, takeCapturedError) {
120
- if (!event) return;
125
+ function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) {
126
+ if (!preparedEvent) return;
127
+ const { event, requestAttribution } = preparedEvent;
121
128
  try {
122
129
  if ((0, external_tracing_helpers_js_namespaceObject.isToolResultError)(result)) {
123
130
  event.isError = true;
@@ -126,49 +133,85 @@ function publishSuccessfulToolEvent(server, event, result, startTime, logger, ta
126
133
  } else event.isError = false;
127
134
  event.response = result;
128
135
  event.duration = Date.now() - startTime.getTime();
129
- (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger);
136
+ (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger, requestAttribution);
130
137
  } catch (error) {
131
138
  logger(`Warning: PostHog MCP analytics failed to publish tool event - ${error}`);
132
139
  }
133
140
  }
134
- function publishFailedToolEvent(server, event, error, startTime, conversation, logger) {
135
- if (!event) return;
141
+ function publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, logger) {
142
+ if (!preparedEvent) return;
143
+ const { event, requestAttribution } = preparedEvent;
136
144
  try {
137
145
  if (conversation.minted) event.conversationId = void 0;
138
146
  event.isError = true;
139
147
  event.error = (0, external_exceptions_js_namespaceObject.captureException)(error);
140
148
  event.duration = Date.now() - startTime.getTime();
141
- (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger);
149
+ (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger, requestAttribution);
142
150
  } catch (publishError) {
143
151
  logger(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`);
144
152
  }
145
153
  }
154
+ const originalRequestHandlers = new WeakMap();
155
+ function rememberOriginalRequestHandler(server, handlerName, originalHandler) {
156
+ let handlers = originalRequestHandlers.get(server);
157
+ if (!handlers) {
158
+ handlers = new Map();
159
+ originalRequestHandlers.set(server, handlers);
160
+ }
161
+ handlers.set(handlerName, originalHandler);
162
+ }
146
163
  function patchRequestHandlers(server, patches) {
147
164
  for (const [handlerName, patch] of Object.entries(patches)){
148
165
  const originalHandler = server._requestHandlers.get(handlerName);
149
- if (originalHandler) server._requestHandlers.set(handlerName, (request, extra)=>patch(server, originalHandler, request, extra));
166
+ if (originalHandler) {
167
+ rememberOriginalRequestHandler(server, handlerName, originalHandler);
168
+ server._requestHandlers.set(handlerName, (request, extra)=>patch(server, originalHandler, request, extra));
169
+ }
150
170
  }
151
171
  const originalSetRequestHandler = server.setRequestHandler.bind(server);
152
172
  server.setRequestHandler = (requestSchema, originalHandler)=>{
153
173
  const shape = (0, external_mcp_sdk_compat_js_namespaceObject.getObjectShape)(requestSchema);
154
174
  const handlerName = shape?.method ? (0, external_mcp_sdk_compat_js_namespaceObject.getLiteralValue)(shape.method) : void 0;
155
175
  const patch = 'string' == typeof handlerName ? patches[handlerName] : void 0;
156
- if (!patch) return originalSetRequestHandler(requestSchema, originalHandler);
157
- return originalSetRequestHandler(requestSchema, (request, extra)=>patch(server, originalHandler, request, extra));
176
+ if (!patch || 'string' != typeof handlerName) return originalSetRequestHandler(requestSchema, originalHandler);
177
+ const result = originalSetRequestHandler(requestSchema, originalHandler);
178
+ const registeredHandler = server._requestHandlers.get(handlerName);
179
+ if (registeredHandler) {
180
+ rememberOriginalRequestHandler(server, handlerName, registeredHandler);
181
+ server._requestHandlers.set(handlerName, (request, extra)=>patch(server, registeredHandler, request, extra));
182
+ }
183
+ return result;
158
184
  };
159
185
  }
186
+ async function isToolAdvertised(server, toolName, extra, logger) {
187
+ const listHandler = originalRequestHandlers.get(server)?.get('tools/list');
188
+ if (!listHandler || !server._requestHandlers.has('tools/list')) return;
189
+ try {
190
+ const response = await listHandler({
191
+ method: 'tools/list',
192
+ params: {}
193
+ }, extra);
194
+ if (!response || !Array.isArray(response.tools)) return;
195
+ return response.tools.some((tool)=>tool?.name === toolName);
196
+ } catch (error) {
197
+ logger(`Warning: PostHog MCP analytics could not determine whether "${toolName}" is advertised; delegating to the server - ${error}`);
198
+ return;
199
+ }
200
+ }
160
201
  async function handleListToolsRequest(server, originalListToolsHandler, request, extra, logger) {
161
202
  const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
162
203
  const startTime = new Date();
204
+ const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra);
205
+ const requestAttribution = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId);
163
206
  const event = {
164
- sessionId: (0, external_session_js_namespaceObject.getSessionId)(server, extra),
207
+ sessionId,
165
208
  parameters: (0, external_mcp_payloads_js_namespaceObject.buildCapturedMcpParameters)(request),
166
209
  eventType: external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpToolsList,
167
210
  timestamp: startTime
168
211
  };
169
212
  (0, external_client_identity_js_namespaceObject.stampMetaClientInfo)(event, request);
170
213
  if (data) await (0, external_tracing_helpers_js_namespaceObject.applyResolvedMetadata)(event, data, request, extra);
171
- const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger);
214
+ const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution);
172
215
  if (!data) {
173
216
  logger('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.');
174
217
  return {
@@ -180,7 +223,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
180
223
  event.error = (0, external_exceptions_js_namespaceObject.captureException)('No tools were sent to MCP client.');
181
224
  event.isError = true;
182
225
  event.duration = Date.now() - startTime.getTime();
183
- (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger);
226
+ (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger, requestAttribution);
184
227
  return {
185
228
  tools
186
229
  };
@@ -191,7 +234,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
191
234
  event.listedToolNames = collectListedToolNames(tools);
192
235
  event.isError = false;
193
236
  event.duration = Date.now() - startTime.getTime();
194
- (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger);
237
+ (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger, requestAttribution);
195
238
  return {
196
239
  tools
197
240
  };
@@ -204,18 +247,27 @@ function collectListedToolNames(tools) {
204
247
  const names = tools.map((tool)=>tool?.name).filter((name)=>'string' == typeof name);
205
248
  return names.length > 0 ? names : void 0;
206
249
  }
207
- async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger) {
250
+ async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution) {
208
251
  try {
209
252
  const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
210
253
  const originalResponse = await originalListToolsHandler(request, extra);
211
- let tools = originalResponse.tools || [];
254
+ let tools = [
255
+ ...originalResponse.tools || []
256
+ ];
212
257
  if (data) cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, tools);
213
258
  if (data && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context)) tools = (0, external_context_parameters_js_namespaceObject.addContextParameterToTools)(tools, (0, external_context_parameters_js_namespaceObject.getContextDescription)(data.options.context), data.logger);
214
- if (data?.options.enableConversationId) tools = (0, external_conversation_id_js_namespaceObject.addConversationIdToTools)(tools, (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options), data.logger);
215
- if (data?.options.reportMissing) {
259
+ if (data) {
216
260
  const missingToolName = (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options);
217
- const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
218
- if (!alreadyPresent) tools.push((0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName));
261
+ let injectedMissingCapabilityTool = false;
262
+ if (data.options.reportMissing) {
263
+ const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
264
+ if (alreadyPresent) data.logger(`Warning: Cannot inject missing-capability tool "${missingToolName}" because a real tool already uses that name. The real tool will not be intercepted.`);
265
+ else {
266
+ tools.push((0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName));
267
+ injectedMissingCapabilityTool = true;
268
+ }
269
+ }
270
+ if (data.options.enableConversationId) tools = (0, external_conversation_id_js_namespaceObject.addConversationIdToTools)(tools, missingToolName, injectedMissingCapabilityTool, data.logger);
219
271
  }
220
272
  if (data) {
221
273
  cacheToolDescriptions(data.toolDescriptions, tools);
@@ -227,7 +279,7 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
227
279
  event.error = (0, external_exceptions_js_namespaceObject.captureException)(error);
228
280
  event.isError = true;
229
281
  event.duration = event.timestamp ? Date.now() - event.timestamp.getTime() : 0;
230
- (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger);
282
+ (0, external_capture_js_namespaceObject.captureEvent)(server, event, logger, requestAttribution);
231
283
  throw error;
232
284
  }
233
285
  }
@@ -276,19 +328,19 @@ function mintStatelessSessionOnInitialize(server, data, request, extra) {
276
328
  return;
277
329
  }
278
330
  }
279
- function upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion) {
331
+ function upgradeMintedTokenToNegotiated(server, mintedSessionId, sessionInfo, negotiatedProtocolVersion, logger) {
280
332
  try {
281
333
  const transport = server.transport;
282
334
  if (!transport) return;
283
335
  const token = (0, external_session_token_js_namespaceObject.encodeSessionId)({
284
336
  sessionId: mintedSessionId,
285
- clientName: data.sessionInfo.clientName,
286
- clientVersion: data.sessionInfo.clientVersion,
337
+ clientName: sessionInfo.clientName,
338
+ clientVersion: sessionInfo.clientVersion,
287
339
  protocolVersion: negotiatedProtocolVersion
288
340
  });
289
341
  (0, external_session_token_js_namespaceObject.writeSessionIdToTransport)(transport, token);
290
342
  } catch (error) {
291
- data.logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`);
343
+ logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`);
292
344
  }
293
345
  }
294
346
  function readInitializeClientInfo(request) {
@@ -308,7 +360,15 @@ async function handleInitializeRequest(server, originalInitializeHandler, reques
308
360
  }
309
361
  const mintedSessionId = mintStatelessSessionOnInitialize(server, data, request, extra);
310
362
  const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra);
311
- await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra);
363
+ const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId);
364
+ const initializeClientInfo = readInitializeClientInfo(request);
365
+ const requestSessionInfo = {
366
+ ...sessionInfo,
367
+ clientName: initializeClientInfo?.name ?? sessionInfo.clientName,
368
+ clientVersion: initializeClientInfo?.version ?? sessionInfo.clientVersion
369
+ };
370
+ const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, requestSessionInfo, extra);
371
+ const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(requestSessionInfo, identity);
312
372
  const event = {
313
373
  sessionId,
314
374
  resourceName: request.params?.name || 'Unknown Tool Name',
@@ -322,10 +382,18 @@ async function handleInitializeRequest(server, originalInitializeHandler, reques
322
382
  event.response = result;
323
383
  const negotiatedProtocolVersion = readProtocolVersion(result, request);
324
384
  event.protocolVersion = negotiatedProtocolVersion;
325
- data.sessionInfo.protocolVersion = negotiatedProtocolVersion;
326
- (0, external_internal_js_namespaceObject.setServerTrackingData)(server, data);
327
- if (mintedSessionId) upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion);
328
- (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger);
385
+ if (data.sessionId === sessionId) {
386
+ data.sessionInfo = {
387
+ ...data.sessionInfo,
388
+ protocolVersion: negotiatedProtocolVersion
389
+ };
390
+ (0, external_internal_js_namespaceObject.setServerTrackingData)(server, data);
391
+ }
392
+ if (mintedSessionId) upgradeMintedTokenToNegotiated(server, mintedSessionId, requestSessionInfo, negotiatedProtocolVersion, data.logger);
393
+ (0, external_capture_js_namespaceObject.captureEvent)(server, event, data.logger, {
394
+ ...requestAttribution,
395
+ protocolVersion: negotiatedProtocolVersion
396
+ });
329
397
  return result;
330
398
  }
331
399
  function readProtocolVersion(result, request) {
@@ -339,6 +407,7 @@ exports.cacheToolDescriptions = __webpack_exports__.cacheToolDescriptions;
339
407
  exports.captureToolCall = __webpack_exports__.captureToolCall;
340
408
  exports.handleInitializeRequest = __webpack_exports__.handleInitializeRequest;
341
409
  exports.handleListToolsRequest = __webpack_exports__.handleListToolsRequest;
410
+ exports.isToolAdvertised = __webpack_exports__.isToolAdvertised;
342
411
  exports.patchRequestHandlers = __webpack_exports__.patchRequestHandlers;
343
412
  exports.readToolMetaCategory = __webpack_exports__.readToolMetaCategory;
344
413
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
@@ -347,6 +416,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
347
416
  "captureToolCall",
348
417
  "handleInitializeRequest",
349
418
  "handleListToolsRequest",
419
+ "isToolAdvertised",
350
420
  "patchRequestHandlers",
351
421
  "readToolMetaCategory"
352
422
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
@@ -6,35 +6,35 @@ import { captureEvent } from "./capture.mjs";
6
6
  import { MCPAnalyticsEventType } from "./event-types.mjs";
7
7
  import { captureException } from "./exceptions.mjs";
8
8
  import { resolveToolCallIntent, setEventIntent, setExplicitContextIntent } from "./intent.mjs";
9
- import { getServerTrackingData, handleIdentify, setServerTrackingData } from "./internal.mjs";
9
+ import { getServerTrackingData, handleIdentify, setServerTrackingData, withIdentity } from "./internal.mjs";
10
10
  import { buildCapturedMcpParameters } from "./mcp-payloads.mjs";
11
11
  import { getLiteralValue, getObjectShape } from "./mcp-sdk-compat.mjs";
12
- import { getSessionId, newSessionId } from "./session.mjs";
12
+ import { getSessionId, getSessionInfo, newSessionId } from "./session.mjs";
13
13
  import { encodeSessionId, readMcpSessionHeader, writeSessionIdToTransport } from "./session-token.mjs";
14
14
  import { getReportMissingToolDescriptor, resolveMissingCapabilityToolName } from "./tools.mjs";
15
15
  import { applyResolvedMetadata, isToolResultError } from "./tracing-helpers.mjs";
16
16
  async function captureToolCall(params) {
17
17
  const { server, data, request, extra, execute, parameterOwnership, eventType, explicitContextIntent, takeCapturedError } = params;
18
- const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership);
19
- const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments, request.params?.name, resolveMissingCapabilityToolName(data.options));
18
+ const resolvedEventType = eventType ?? MCPAnalyticsEventType.mcpToolsCall;
19
+ const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership, resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability);
20
+ const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments, request.params?.name, resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability ? resolveMissingCapabilityToolName(data.options) : '');
20
21
  const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership);
21
22
  const startTime = new Date();
22
- const event = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, eventType ?? MCPAnalyticsEventType.mcpToolsCall);
23
- if (event && explicitContextIntent) setExplicitContextIntent(event, explicitContextIntent);
23
+ const preparedEvent = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType);
24
+ if (preparedEvent && explicitContextIntent) setExplicitContextIntent(preparedEvent.event, explicitContextIntent);
24
25
  let result;
25
26
  try {
26
27
  result = await execute(downstreamRequest);
27
28
  } catch (error) {
28
- publishFailedToolEvent(server, event, error, startTime, conversation, data.logger);
29
+ publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger);
29
30
  throw error;
30
31
  }
31
- const finalResult = applyConversationPromptBack(event, result, conversation);
32
- publishSuccessfulToolEvent(server, event, finalResult, startTime, data.logger, takeCapturedError);
32
+ const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation);
33
+ publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError);
33
34
  return finalResult;
34
35
  }
35
- function getActiveAnalyticsParameterOwnership(data, toolName, override) {
36
+ function getActiveAnalyticsParameterOwnership(data, toolName, override, isMissingCapabilityTool) {
36
37
  const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0);
37
- const isMissingCapabilityTool = toolName === resolveMissingCapabilityToolName(data.options);
38
38
  return {
39
39
  context: !isMissingCapabilityTool && isContextEnabled(data.options.context) && ownership?.context === true,
40
40
  conversationId: !isMissingCapabilityTool && true === data.options.enableConversationId && ownership?.conversationId === true
@@ -55,7 +55,9 @@ function cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) {
55
55
  async function prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, eventType) {
56
56
  try {
57
57
  const sessionId = getSessionId(server, extra);
58
- await handleIdentify(server, data, sessionId, request, extra);
58
+ const sessionInfo = getSessionInfo(server, data, sessionId);
59
+ const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra);
60
+ const requestAttribution = withIdentity(sessionInfo, identity);
59
61
  const toolName = request.params?.name;
60
62
  const event = {
61
63
  sessionId,
@@ -70,7 +72,10 @@ async function prepareToolCallEvent(server, data, request, downstreamRequest, ex
70
72
  stampMetaClientInfo(event, request);
71
73
  await applyResolvedMetadata(event, data, request, extra);
72
74
  setEventIntent(event, await resolveToolCallIntent(data, request, ownership.context, extra));
73
- return event;
75
+ return {
76
+ event,
77
+ requestAttribution
78
+ };
74
79
  } catch (error) {
75
80
  data.logger(`Warning: PostHog MCP analytics instrumentation failed for tool ${request.params?.name}, the tool will still run - ${error}`);
76
81
  return null;
@@ -82,8 +87,9 @@ function applyConversationPromptBack(event, result, conversation) {
82
87
  if (event) event.conversationId = void 0;
83
88
  return result;
84
89
  }
85
- function publishSuccessfulToolEvent(server, event, result, startTime, logger, takeCapturedError) {
86
- if (!event) return;
90
+ function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) {
91
+ if (!preparedEvent) return;
92
+ const { event, requestAttribution } = preparedEvent;
87
93
  try {
88
94
  if (isToolResultError(result)) {
89
95
  event.isError = true;
@@ -92,49 +98,85 @@ function publishSuccessfulToolEvent(server, event, result, startTime, logger, ta
92
98
  } else event.isError = false;
93
99
  event.response = result;
94
100
  event.duration = Date.now() - startTime.getTime();
95
- captureEvent(server, event, logger);
101
+ captureEvent(server, event, logger, requestAttribution);
96
102
  } catch (error) {
97
103
  logger(`Warning: PostHog MCP analytics failed to publish tool event - ${error}`);
98
104
  }
99
105
  }
100
- function publishFailedToolEvent(server, event, error, startTime, conversation, logger) {
101
- if (!event) return;
106
+ function publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, logger) {
107
+ if (!preparedEvent) return;
108
+ const { event, requestAttribution } = preparedEvent;
102
109
  try {
103
110
  if (conversation.minted) event.conversationId = void 0;
104
111
  event.isError = true;
105
112
  event.error = captureException(error);
106
113
  event.duration = Date.now() - startTime.getTime();
107
- captureEvent(server, event, logger);
114
+ captureEvent(server, event, logger, requestAttribution);
108
115
  } catch (publishError) {
109
116
  logger(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`);
110
117
  }
111
118
  }
119
+ const originalRequestHandlers = new WeakMap();
120
+ function rememberOriginalRequestHandler(server, handlerName, originalHandler) {
121
+ let handlers = originalRequestHandlers.get(server);
122
+ if (!handlers) {
123
+ handlers = new Map();
124
+ originalRequestHandlers.set(server, handlers);
125
+ }
126
+ handlers.set(handlerName, originalHandler);
127
+ }
112
128
  function patchRequestHandlers(server, patches) {
113
129
  for (const [handlerName, patch] of Object.entries(patches)){
114
130
  const originalHandler = server._requestHandlers.get(handlerName);
115
- if (originalHandler) server._requestHandlers.set(handlerName, (request, extra)=>patch(server, originalHandler, request, extra));
131
+ if (originalHandler) {
132
+ rememberOriginalRequestHandler(server, handlerName, originalHandler);
133
+ server._requestHandlers.set(handlerName, (request, extra)=>patch(server, originalHandler, request, extra));
134
+ }
116
135
  }
117
136
  const originalSetRequestHandler = server.setRequestHandler.bind(server);
118
137
  server.setRequestHandler = (requestSchema, originalHandler)=>{
119
138
  const shape = getObjectShape(requestSchema);
120
139
  const handlerName = shape?.method ? getLiteralValue(shape.method) : void 0;
121
140
  const patch = 'string' == typeof handlerName ? patches[handlerName] : void 0;
122
- if (!patch) return originalSetRequestHandler(requestSchema, originalHandler);
123
- return originalSetRequestHandler(requestSchema, (request, extra)=>patch(server, originalHandler, request, extra));
141
+ if (!patch || 'string' != typeof handlerName) return originalSetRequestHandler(requestSchema, originalHandler);
142
+ const result = originalSetRequestHandler(requestSchema, originalHandler);
143
+ const registeredHandler = server._requestHandlers.get(handlerName);
144
+ if (registeredHandler) {
145
+ rememberOriginalRequestHandler(server, handlerName, registeredHandler);
146
+ server._requestHandlers.set(handlerName, (request, extra)=>patch(server, registeredHandler, request, extra));
147
+ }
148
+ return result;
124
149
  };
125
150
  }
151
+ async function isToolAdvertised(server, toolName, extra, logger) {
152
+ const listHandler = originalRequestHandlers.get(server)?.get('tools/list');
153
+ if (!listHandler || !server._requestHandlers.has('tools/list')) return;
154
+ try {
155
+ const response = await listHandler({
156
+ method: 'tools/list',
157
+ params: {}
158
+ }, extra);
159
+ if (!response || !Array.isArray(response.tools)) return;
160
+ return response.tools.some((tool)=>tool?.name === toolName);
161
+ } catch (error) {
162
+ logger(`Warning: PostHog MCP analytics could not determine whether "${toolName}" is advertised; delegating to the server - ${error}`);
163
+ return;
164
+ }
165
+ }
126
166
  async function handleListToolsRequest(server, originalListToolsHandler, request, extra, logger) {
127
167
  const data = getServerTrackingData(server);
128
168
  const startTime = new Date();
169
+ const sessionId = getSessionId(server, extra);
170
+ const requestAttribution = getSessionInfo(server, data, sessionId);
129
171
  const event = {
130
- sessionId: getSessionId(server, extra),
172
+ sessionId,
131
173
  parameters: buildCapturedMcpParameters(request),
132
174
  eventType: MCPAnalyticsEventType.mcpToolsList,
133
175
  timestamp: startTime
134
176
  };
135
177
  stampMetaClientInfo(event, request);
136
178
  if (data) await applyResolvedMetadata(event, data, request, extra);
137
- const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger);
179
+ const tools = await getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution);
138
180
  if (!data) {
139
181
  logger('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.');
140
182
  return {
@@ -146,7 +188,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
146
188
  event.error = captureException('No tools were sent to MCP client.');
147
189
  event.isError = true;
148
190
  event.duration = Date.now() - startTime.getTime();
149
- captureEvent(server, event, data.logger);
191
+ captureEvent(server, event, data.logger, requestAttribution);
150
192
  return {
151
193
  tools
152
194
  };
@@ -157,7 +199,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
157
199
  event.listedToolNames = collectListedToolNames(tools);
158
200
  event.isError = false;
159
201
  event.duration = Date.now() - startTime.getTime();
160
- captureEvent(server, event, data.logger);
202
+ captureEvent(server, event, data.logger, requestAttribution);
161
203
  return {
162
204
  tools
163
205
  };
@@ -170,18 +212,27 @@ function collectListedToolNames(tools) {
170
212
  const names = tools.map((tool)=>tool?.name).filter((name)=>'string' == typeof name);
171
213
  return names.length > 0 ? names : void 0;
172
214
  }
173
- async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger) {
215
+ async function getTracedToolsList(server, originalListToolsHandler, request, extra, event, logger, requestAttribution) {
174
216
  try {
175
217
  const data = getServerTrackingData(server);
176
218
  const originalResponse = await originalListToolsHandler(request, extra);
177
- let tools = originalResponse.tools || [];
219
+ let tools = [
220
+ ...originalResponse.tools || []
221
+ ];
178
222
  if (data) cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, tools);
179
223
  if (data && isContextEnabled(data.options.context)) tools = addContextParameterToTools(tools, getContextDescription(data.options.context), data.logger);
180
- if (data?.options.enableConversationId) tools = addConversationIdToTools(tools, resolveMissingCapabilityToolName(data.options), data.logger);
181
- if (data?.options.reportMissing) {
224
+ if (data) {
182
225
  const missingToolName = resolveMissingCapabilityToolName(data.options);
183
- const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
184
- if (!alreadyPresent) tools.push(getReportMissingToolDescriptor(missingToolName));
226
+ let injectedMissingCapabilityTool = false;
227
+ if (data.options.reportMissing) {
228
+ const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
229
+ if (alreadyPresent) data.logger(`Warning: Cannot inject missing-capability tool "${missingToolName}" because a real tool already uses that name. The real tool will not be intercepted.`);
230
+ else {
231
+ tools.push(getReportMissingToolDescriptor(missingToolName));
232
+ injectedMissingCapabilityTool = true;
233
+ }
234
+ }
235
+ if (data.options.enableConversationId) tools = addConversationIdToTools(tools, missingToolName, injectedMissingCapabilityTool, data.logger);
185
236
  }
186
237
  if (data) {
187
238
  cacheToolDescriptions(data.toolDescriptions, tools);
@@ -193,7 +244,7 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
193
244
  event.error = captureException(error);
194
245
  event.isError = true;
195
246
  event.duration = event.timestamp ? Date.now() - event.timestamp.getTime() : 0;
196
- captureEvent(server, event, logger);
247
+ captureEvent(server, event, logger, requestAttribution);
197
248
  throw error;
198
249
  }
199
250
  }
@@ -242,19 +293,19 @@ function mintStatelessSessionOnInitialize(server, data, request, extra) {
242
293
  return;
243
294
  }
244
295
  }
245
- function upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion) {
296
+ function upgradeMintedTokenToNegotiated(server, mintedSessionId, sessionInfo, negotiatedProtocolVersion, logger) {
246
297
  try {
247
298
  const transport = server.transport;
248
299
  if (!transport) return;
249
300
  const token = encodeSessionId({
250
301
  sessionId: mintedSessionId,
251
- clientName: data.sessionInfo.clientName,
252
- clientVersion: data.sessionInfo.clientVersion,
302
+ clientName: sessionInfo.clientName,
303
+ clientVersion: sessionInfo.clientVersion,
253
304
  protocolVersion: negotiatedProtocolVersion
254
305
  });
255
306
  writeSessionIdToTransport(transport, token);
256
307
  } catch (error) {
257
- data.logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`);
308
+ logger(`Warning: PostHog MCP analytics failed to upgrade the stateless session token - ${error}`);
258
309
  }
259
310
  }
260
311
  function readInitializeClientInfo(request) {
@@ -274,7 +325,15 @@ async function handleInitializeRequest(server, originalInitializeHandler, reques
274
325
  }
275
326
  const mintedSessionId = mintStatelessSessionOnInitialize(server, data, request, extra);
276
327
  const sessionId = getSessionId(server, extra);
277
- await handleIdentify(server, data, sessionId, request, extra);
328
+ const sessionInfo = getSessionInfo(server, data, sessionId);
329
+ const initializeClientInfo = readInitializeClientInfo(request);
330
+ const requestSessionInfo = {
331
+ ...sessionInfo,
332
+ clientName: initializeClientInfo?.name ?? sessionInfo.clientName,
333
+ clientVersion: initializeClientInfo?.version ?? sessionInfo.clientVersion
334
+ };
335
+ const identity = await handleIdentify(server, data, sessionId, request, requestSessionInfo, extra);
336
+ const requestAttribution = withIdentity(requestSessionInfo, identity);
278
337
  const event = {
279
338
  sessionId,
280
339
  resourceName: request.params?.name || 'Unknown Tool Name',
@@ -288,10 +347,18 @@ async function handleInitializeRequest(server, originalInitializeHandler, reques
288
347
  event.response = result;
289
348
  const negotiatedProtocolVersion = readProtocolVersion(result, request);
290
349
  event.protocolVersion = negotiatedProtocolVersion;
291
- data.sessionInfo.protocolVersion = negotiatedProtocolVersion;
292
- setServerTrackingData(server, data);
293
- if (mintedSessionId) upgradeMintedTokenToNegotiated(server, data, mintedSessionId, negotiatedProtocolVersion);
294
- captureEvent(server, event, data.logger);
350
+ if (data.sessionId === sessionId) {
351
+ data.sessionInfo = {
352
+ ...data.sessionInfo,
353
+ protocolVersion: negotiatedProtocolVersion
354
+ };
355
+ setServerTrackingData(server, data);
356
+ }
357
+ if (mintedSessionId) upgradeMintedTokenToNegotiated(server, mintedSessionId, requestSessionInfo, negotiatedProtocolVersion, data.logger);
358
+ captureEvent(server, event, data.logger, {
359
+ ...requestAttribution,
360
+ protocolVersion: negotiatedProtocolVersion
361
+ });
295
362
  return result;
296
363
  }
297
364
  function readProtocolVersion(result, request) {
@@ -300,4 +367,4 @@ function readProtocolVersion(result, request) {
300
367
  const requested = request.params?.protocolVersion;
301
368
  return 'string' == typeof requested && requested.length > 0 ? requested : void 0;
302
369
  }
303
- export { cacheToolCategories, cacheToolDescriptions, captureToolCall, handleInitializeRequest, handleListToolsRequest, patchRequestHandlers, readToolMetaCategory };
370
+ export { cacheToolCategories, cacheToolDescriptions, captureToolCall, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, readToolMetaCategory };
@@ -1 +1 @@
1
- {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/extensions/intent.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,QAAQ,EACT,MAAM,UAAU,CAAA;AAGjB,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,wBAAwB,CAAA;CACjC;AAkCD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,oBAAoB,EAAE,OAAO,EAC7B,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAYhC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAO3F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQ/E"}
1
+ {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/extensions/intent.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,QAAQ,EACT,MAAM,UAAU,CAAA;AAGjB,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,wBAAwB,CAAA;CACjC;AAkCD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,oBAAoB,EAAE,OAAO,EAC7B,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAO3F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQ/E"}
@@ -53,7 +53,7 @@ async function runIntentFallback(data, request, extra) {
53
53
  }
54
54
  async function resolveToolCallIntent(data, request, analyticsOwnsContext, extra) {
55
55
  const contextArgument = getContextArgument(request);
56
- if (analyticsOwnsContext && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context) && request.params?.name !== 'get_more_tools' && contextArgument) return {
56
+ if (analyticsOwnsContext && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context) && contextArgument) return {
57
57
  intent: contextArgument,
58
58
  source: 'context_parameter'
59
59
  };