@posthog/mcp 0.16.2 → 0.16.4

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.
package/README.md CHANGED
@@ -81,6 +81,8 @@ Protocol revision is a property of each **request**, not of the server: a v2 ser
81
81
  - **On `2026-07-28`** there is no `initialize` and no session header — the revision removed
82
82
  protocol-level sessions, and this SDK will not mint one. Session correlation therefore comes from
83
83
  `enableConversationId`, which is **opt-in**. Without it every request is its own `$session_id`.
84
+ The `get_more_tools` and `send_feedback` virtual tools also use this handle, including calls handled
85
+ by a fresh server instance.
84
86
  - **On `2025-11-25`**, the session id and the client's name and version are exchanged once at
85
87
  `initialize`. If your server builds a fresh `McpServer` per HTTP request — which
86
88
  `createMcpHandler` does by default — the instance serving a later `tools/call` never saw that
@@ -283,10 +285,11 @@ both advertises both tools. Like `get_more_tools`, a real tool that already uses
283
285
  wins: the SDK warns, skips injection, and delegates calls to the real handler.
284
286
 
285
287
  On a paginated catalogue (a `tools/list` response with a `nextCursor`), `instrument()` injects
286
- `send_feedback` on the first page only — the page every client reads, including clients that never
287
- follow `nextCursor` — so a compliant client's concatenated list carries it once. "First page" means
288
- a `tools/list` request with no cursor; an empty string is a valid cursor, so `cursor: ""` is a
289
- continuation page. Hosts using `prepareToolList()` directly own this rule themselves: pass
288
+ its virtual tools (`send_feedback` and `get_more_tools`) on the first page only — the page every
289
+ client reads, including clients that never follow `nextCursor` — so a compliant client's
290
+ concatenated list carries each once. "First page" means a `tools/list` request with no cursor; an
291
+ empty string is a valid cursor, so `cursor: ""` is a continuation page. Hosts using
292
+ `prepareToolList()` directly own this rule themselves: pass `reportMissing: true` and
290
293
  `collectFeedback: true` only for the first page.
291
294
 
292
295
  Name collisions are detected on the first page only. A real tool named `send_feedback` (or
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,sBAAsB,EAIvB,MAAM,UAAU,CAAA;AAmBjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAgSxC,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA+BhG"}
1
+ {"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,sBAAsB,EAIvB,MAAM,UAAU,CAAA;AAmBjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAuRxC,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA+BhG"}
@@ -172,7 +172,7 @@ async function handleToolCallRequest(highLevelServer, server, originalCallToolHa
172
172
  extra,
173
173
  eventType: external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability,
174
174
  explicitContextIntent: context,
175
- parameterOwnership: (0, external_instrumentation_js_namespaceObject.getVirtualToolParameterOwnership)(data, toolName, (0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(toolName).inputSchema),
175
+ parameterOwnership: (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)((0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(toolName).inputSchema),
176
176
  execute: async ()=>(0, external_tools_js_namespaceObject.handleReportMissing)({
177
177
  context
178
178
  }, data.logger)
@@ -191,7 +191,7 @@ async function handleToolCallRequest(highLevelServer, server, originalCallToolHa
191
191
  explicitContextIntent: (0, external_feedback_js_namespaceObject.buildFeedbackIntent)(report),
192
192
  omitCapturedParameters: true,
193
193
  extraEventProperties: (0, external_feedback_js_namespaceObject.buildFeedbackEventProperties)(report),
194
- parameterOwnership: (0, external_instrumentation_js_namespaceObject.getVirtualToolParameterOwnership)(data, toolName, (0, external_feedback_js_namespaceObject.getFeedbackToolDescriptor)(feedbackOptions).inputSchema),
194
+ parameterOwnership: (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)((0, external_feedback_js_namespaceObject.getFeedbackToolDescriptor)(feedbackOptions).inputSchema),
195
195
  execute: async ()=>(0, external_feedback_js_namespaceObject.handleFeedback)(report, feedbackOptions, data.logger)
196
196
  });
197
197
  }
@@ -6,7 +6,7 @@ import { MCPAnalyticsEventType } from "./event-types.mjs";
6
6
  import { getServerTrackingData } from "./internal.mjs";
7
7
  import { createWrappedTool, getToolFunction, hasToolFunction } from "./mcp-sdk-compat.mjs";
8
8
  import { getReportMissingToolDescriptor, handleReportMissing, resolveMissingCapabilityToolName } from "./tools.mjs";
9
- import { captureToolCall, getVirtualToolParameterOwnership, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, readToolMetaCategory, traceResourceRequest } from "./instrumentation.mjs";
9
+ import { captureToolCall, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, readToolMetaCategory, traceResourceRequest } from "./instrumentation.mjs";
10
10
  import { getContextArgument } from "./tracing-helpers.mjs";
11
11
  const wrappedCallbacks = new WeakMap();
12
12
  const MCP_ANALYTICS_PROCESSED = Symbol('__posthog_mcp_analytics_processed__');
@@ -140,7 +140,7 @@ async function handleToolCallRequest(highLevelServer, server, originalCallToolHa
140
140
  extra,
141
141
  eventType: MCPAnalyticsEventType.mcpMissingCapability,
142
142
  explicitContextIntent: context,
143
- parameterOwnership: getVirtualToolParameterOwnership(data, toolName, getReportMissingToolDescriptor(toolName).inputSchema),
143
+ parameterOwnership: getAnalyticsParameterOwnership(getReportMissingToolDescriptor(toolName).inputSchema),
144
144
  execute: async ()=>handleReportMissing({
145
145
  context
146
146
  }, data.logger)
@@ -159,7 +159,7 @@ async function handleToolCallRequest(highLevelServer, server, originalCallToolHa
159
159
  explicitContextIntent: buildFeedbackIntent(report),
160
160
  omitCapturedParameters: true,
161
161
  extraEventProperties: buildFeedbackEventProperties(report),
162
- parameterOwnership: getVirtualToolParameterOwnership(data, toolName, getFeedbackToolDescriptor(feedbackOptions).inputSchema),
162
+ parameterOwnership: getAnalyticsParameterOwnership(getFeedbackToolDescriptor(feedbackOptions).inputSchema),
163
163
  execute: async ()=>handleFeedback(report, feedbackOptions, data.logger)
164
164
  });
165
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-lowlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-lowlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiD,aAAa,EAAE,MAAM,UAAU,CAAA;AAY5F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAqBxC;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA8BtF"}
1
+ {"version":3,"file":"instrument-lowlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-lowlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiD,aAAa,EAAE,MAAM,UAAU,CAAA;AAa5F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAoBxC;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA8BtF"}
@@ -31,6 +31,7 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  instrumentLowLevelServer: ()=>instrumentLowLevelServer
32
32
  });
33
33
  const external_feedback_js_namespaceObject = require("./feedback.js");
34
+ const external_analytics_parameters_js_namespaceObject = require("./analytics-parameters.js");
34
35
  const external_event_types_js_namespaceObject = require("./event-types.js");
35
36
  const external_internal_js_namespaceObject = require("./internal.js");
36
37
  const external_tools_js_namespaceObject = require("./tools.js");
@@ -75,7 +76,7 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
75
76
  extra,
76
77
  eventType: external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability,
77
78
  explicitContextIntent: context,
78
- parameterOwnership: (0, external_instrumentation_js_namespaceObject.getVirtualToolParameterOwnership)(data, toolName, (0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(toolName).inputSchema),
79
+ parameterOwnership: (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)((0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(toolName).inputSchema),
79
80
  execute: async ()=>(0, external_tools_js_namespaceObject.handleReportMissing)({
80
81
  context
81
82
  }, data.logger)
@@ -94,7 +95,7 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
94
95
  explicitContextIntent: (0, external_feedback_js_namespaceObject.buildFeedbackIntent)(report),
95
96
  omitCapturedParameters: true,
96
97
  extraEventProperties: (0, external_feedback_js_namespaceObject.buildFeedbackEventProperties)(report),
97
- parameterOwnership: (0, external_instrumentation_js_namespaceObject.getVirtualToolParameterOwnership)(data, toolName, (0, external_feedback_js_namespaceObject.getFeedbackToolDescriptor)(feedbackOptions).inputSchema),
98
+ parameterOwnership: (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)((0, external_feedback_js_namespaceObject.getFeedbackToolDescriptor)(feedbackOptions).inputSchema),
98
99
  execute: async ()=>(0, external_feedback_js_namespaceObject.handleFeedback)(report, feedbackOptions, data.logger)
99
100
  });
100
101
  }
@@ -1,8 +1,9 @@
1
1
  import { SEND_FEEDBACK_TOOL_NAME, buildFeedbackEventProperties, buildFeedbackIntent, getFeedbackToolDescriptor, handleFeedback, parseFeedbackReport, resolveCollectFeedbackOptions } from "./feedback.mjs";
2
+ import { getAnalyticsParameterOwnership } from "./analytics-parameters.mjs";
2
3
  import { MCPAnalyticsEventType } from "./event-types.mjs";
3
4
  import { getServerTrackingData } from "./internal.mjs";
4
5
  import { getReportMissingToolDescriptor, handleReportMissing, resolveMissingCapabilityToolName } from "./tools.mjs";
5
- import { captureToolCall, getVirtualToolParameterOwnership, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, registerFallbackRequestHandler, traceResourceRequest } from "./instrumentation.mjs";
6
+ import { captureToolCall, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, registerFallbackRequestHandler, traceResourceRequest } from "./instrumentation.mjs";
6
7
  import { getContextArgument } from "./tracing-helpers.mjs";
7
8
  function instrumentLowLevelServer(server, logger) {
8
9
  try {
@@ -43,7 +44,7 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
43
44
  extra,
44
45
  eventType: MCPAnalyticsEventType.mcpMissingCapability,
45
46
  explicitContextIntent: context,
46
- parameterOwnership: getVirtualToolParameterOwnership(data, toolName, getReportMissingToolDescriptor(toolName).inputSchema),
47
+ parameterOwnership: getAnalyticsParameterOwnership(getReportMissingToolDescriptor(toolName).inputSchema),
47
48
  execute: async ()=>handleReportMissing({
48
49
  context
49
50
  }, data.logger)
@@ -62,7 +63,7 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
62
63
  explicitContextIntent: buildFeedbackIntent(report),
63
64
  omitCapturedParameters: true,
64
65
  extraEventProperties: buildFeedbackEventProperties(report),
65
- parameterOwnership: getVirtualToolParameterOwnership(data, toolName, getFeedbackToolDescriptor(feedbackOptions).inputSchema),
66
+ parameterOwnership: getAnalyticsParameterOwnership(getFeedbackToolDescriptor(feedbackOptions).inputSchema),
66
67
  execute: async ()=>handleFeedback(report, feedbackOptions, data.logger)
67
68
  });
68
69
  }
@@ -100,26 +100,6 @@ export declare function registerFallbackRequestHandler(server: MCPServerLike, ha
100
100
  * bare server to instrument() and only then registers its handlers.
101
101
  */
102
102
  export declare function patchRequestHandlers(server: MCPServerLike, patches: Record<string, HandlerPatch>): void;
103
- /**
104
- * Ownership for an SDK-owned virtual tool (`get_more_tools`, `send_feedback`),
105
- * resolved from its own descriptor rather than the `tools/list` cache.
106
- *
107
- * A virtual-tool branch is only entered when the application does not advertise
108
- * a tool by this name, so the descriptor is the SDK's own and what it declares
109
- * is known statically. An instance that never served a listing — a per-request
110
- * `McpServer`/`Server`, the topology in ADR-0011 — would otherwise read every
111
- * injected parameter as not-ours and neither capture nor strip it.
112
- *
113
- * `conversation_id` still comes from the cache on purpose: resolving it here too
114
- * would start minting a handle, and appending its prompt-back block, on
115
- * instances that today mint none. That changes session anchoring (ADR-0004)
116
- * rather than closing this gap.
117
- *
118
- * `virtualToolInputSchema` is required (not defaulted to one specific virtual
119
- * tool's descriptor) so every call site names the tool it means; each caller
120
- * passes its own descriptor's `inputSchema`.
121
- */
122
- export declare function getVirtualToolParameterOwnership(data: MCPAnalyticsData, toolName: string, virtualToolInputSchema: unknown): AnalyticsParameterOwnership;
123
103
  /**
124
104
  * Checks the server's raw listing for a real owner of a candidate virtual tool.
125
105
  * This does not depend on a previous client request and does not call the
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"}
@@ -31,7 +31,6 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  cacheToolCategories: ()=>cacheToolCategories,
32
32
  cacheToolDescriptions: ()=>cacheToolDescriptions,
33
33
  captureToolCall: ()=>captureToolCall,
34
- getVirtualToolParameterOwnership: ()=>getVirtualToolParameterOwnership,
35
34
  handleInitializeRequest: ()=>handleInitializeRequest,
36
35
  handleListToolsRequest: ()=>handleListToolsRequest,
37
36
  isToolAdvertised: ()=>isToolAdvertised,
@@ -296,12 +295,6 @@ function patchRequestHandlers(server, patches) {
296
295
  return result;
297
296
  };
298
297
  }
299
- function getVirtualToolParameterOwnership(data, toolName, virtualToolInputSchema) {
300
- return {
301
- ...(0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(virtualToolInputSchema),
302
- conversationId: data.toolAnalyticsParameterOwnership.get(toolName)?.conversationId === true
303
- };
304
- }
305
298
  async function isToolAdvertised(server, toolName, extra, logger) {
306
299
  const listHandler = originalRequestHandlers.get(server)?.get('tools/list');
307
300
  if (!listHandler || !server._requestHandlers.has('tools/list')) return;
@@ -372,23 +365,23 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
372
365
  if (data) cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, tools);
373
366
  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);
374
367
  if (data) {
368
+ const isFirstPage = request.params?.cursor == null;
375
369
  const missingToolName = (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options);
376
370
  if (data.options.reportMissing) {
377
371
  const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
378
- 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.`);
379
- else {
372
+ if (isFirstPage && 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. To keep missing-capability reports, rename the SDK's tool with the missingCapabilityToolName option.`);
373
+ else if (isFirstPage) {
380
374
  const virtualTool = (0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName);
381
375
  tools.push(virtualTool);
382
376
  cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [
383
377
  virtualTool
384
378
  ]);
385
- }
379
+ } else if (alreadyPresent) data.logger(`Warning: A real tool "${missingToolName}" on a later tools/list page is shadowed by the SDK's missing-capability tool. Its calls will be intercepted. Rename the SDK's tool with the missingCapabilityToolName option to keep both.`);
386
380
  }
387
381
  const feedbackOptions = (0, external_feedback_js_namespaceObject.resolveCollectFeedbackOptions)(data.options.collectFeedback);
388
382
  if (feedbackOptions) {
389
383
  const feedbackToolName = feedbackOptions.toolName ?? external_feedback_js_namespaceObject.SEND_FEEDBACK_TOOL_NAME;
390
384
  const alreadyPresent = tools.some((tool)=>tool?.name === feedbackToolName);
391
- const isFirstPage = request.params?.cursor == null;
392
385
  if (isFirstPage && alreadyPresent) data.logger(`Warning: Cannot inject agent-feedback tool "${feedbackToolName}" because a real tool already uses that name. The real tool will not be intercepted. To collect feedback alongside it, rename the SDK's tool with collectFeedback: { toolName: "..." }.`);
393
386
  else if (isFirstPage) {
394
387
  const virtualTool = (0, external_feedback_js_namespaceObject.getFeedbackToolDescriptor)(feedbackOptions);
@@ -547,7 +540,6 @@ function readProtocolVersion(result, request) {
547
540
  exports.cacheToolCategories = __webpack_exports__.cacheToolCategories;
548
541
  exports.cacheToolDescriptions = __webpack_exports__.cacheToolDescriptions;
549
542
  exports.captureToolCall = __webpack_exports__.captureToolCall;
550
- exports.getVirtualToolParameterOwnership = __webpack_exports__.getVirtualToolParameterOwnership;
551
543
  exports.handleInitializeRequest = __webpack_exports__.handleInitializeRequest;
552
544
  exports.handleListToolsRequest = __webpack_exports__.handleListToolsRequest;
553
545
  exports.isToolAdvertised = __webpack_exports__.isToolAdvertised;
@@ -559,7 +551,6 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
559
551
  "cacheToolCategories",
560
552
  "cacheToolDescriptions",
561
553
  "captureToolCall",
562
- "getVirtualToolParameterOwnership",
563
554
  "handleInitializeRequest",
564
555
  "handleListToolsRequest",
565
556
  "isToolAdvertised",
@@ -254,12 +254,6 @@ function patchRequestHandlers(server, patches) {
254
254
  return result;
255
255
  };
256
256
  }
257
- function getVirtualToolParameterOwnership(data, toolName, virtualToolInputSchema) {
258
- return {
259
- ...getAnalyticsParameterOwnership(virtualToolInputSchema),
260
- conversationId: data.toolAnalyticsParameterOwnership.get(toolName)?.conversationId === true
261
- };
262
- }
263
257
  async function isToolAdvertised(server, toolName, extra, logger) {
264
258
  const listHandler = originalRequestHandlers.get(server)?.get('tools/list');
265
259
  if (!listHandler || !server._requestHandlers.has('tools/list')) return;
@@ -330,23 +324,23 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
330
324
  if (data) cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, tools);
331
325
  if (data && isContextEnabled(data.options.context)) tools = addContextParameterToTools(tools, getContextDescription(data.options.context), data.logger);
332
326
  if (data) {
327
+ const isFirstPage = request.params?.cursor == null;
333
328
  const missingToolName = resolveMissingCapabilityToolName(data.options);
334
329
  if (data.options.reportMissing) {
335
330
  const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
336
- 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.`);
337
- else {
331
+ if (isFirstPage && 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. To keep missing-capability reports, rename the SDK's tool with the missingCapabilityToolName option.`);
332
+ else if (isFirstPage) {
338
333
  const virtualTool = getReportMissingToolDescriptor(missingToolName);
339
334
  tools.push(virtualTool);
340
335
  cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [
341
336
  virtualTool
342
337
  ]);
343
- }
338
+ } else if (alreadyPresent) data.logger(`Warning: A real tool "${missingToolName}" on a later tools/list page is shadowed by the SDK's missing-capability tool. Its calls will be intercepted. Rename the SDK's tool with the missingCapabilityToolName option to keep both.`);
344
339
  }
345
340
  const feedbackOptions = resolveCollectFeedbackOptions(data.options.collectFeedback);
346
341
  if (feedbackOptions) {
347
342
  const feedbackToolName = feedbackOptions.toolName ?? SEND_FEEDBACK_TOOL_NAME;
348
343
  const alreadyPresent = tools.some((tool)=>tool?.name === feedbackToolName);
349
- const isFirstPage = request.params?.cursor == null;
350
344
  if (isFirstPage && alreadyPresent) data.logger(`Warning: Cannot inject agent-feedback tool "${feedbackToolName}" because a real tool already uses that name. The real tool will not be intercepted. To collect feedback alongside it, rename the SDK's tool with collectFeedback: { toolName: "..." }.`);
351
345
  else if (isFirstPage) {
352
346
  const virtualTool = getFeedbackToolDescriptor(feedbackOptions);
@@ -502,4 +496,4 @@ function readProtocolVersion(result, request) {
502
496
  const requested = request.params?.protocolVersion;
503
497
  return 'string' == typeof requested && requested.length > 0 ? requested : void 0;
504
498
  }
505
- export { cacheToolCategories, cacheToolDescriptions, captureToolCall, getVirtualToolParameterOwnership, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, readToolMetaCategory, registerFallbackRequestHandler, traceResourceRequest };
499
+ export { cacheToolCategories, cacheToolDescriptions, captureToolCall, handleInitializeRequest, handleListToolsRequest, isToolAdvertised, patchRequestHandlers, readToolMetaCategory, registerFallbackRequestHandler, traceResourceRequest };
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "0.16.2";
1
+ export declare const version = "0.16.4";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -27,7 +27,7 @@ var __webpack_require__ = {};
27
27
  })();
28
28
  var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
- const version = '0.16.2';
30
+ const version = '0.16.4';
31
31
  __webpack_require__.d(__webpack_exports__, {}, {
32
32
  version: version
33
33
  });
package/dist/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- const version = '0.16.2';
1
+ const version = '0.16.4';
2
2
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/mcp",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
4
4
  "bugs": {
5
5
  "url": "https://github.com/PostHog/posthog-js/issues"
6
6
  },
@@ -28,7 +28,7 @@
28
28
  "module": "dist/index.mjs",
29
29
  "types": "dist/index.d.ts",
30
30
  "dependencies": {
31
- "@posthog/core": "^1.54.2"
31
+ "@posthog/core": "^1.54.3"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@babel/preset-env": "^7.27.1",
@@ -84,6 +84,7 @@
84
84
  }
85
85
  },
86
86
  "scripts": {
87
+ "check-types": "pnpm prebuild && tsc --noEmit --project tsconfig.build.json",
87
88
  "clean": "rimraf dist coverage",
88
89
  "lint": "oxlint --report-unused-disable-directives-severity error src && oxfmt --check harness",
89
90
  "lint:fix": "oxlint --report-unused-disable-directives-severity error src --fix && oxfmt --write harness",
@@ -38,7 +38,6 @@ import {
38
38
  traceResourceRequest,
39
39
  patchRequestHandlers,
40
40
  captureToolCall,
41
- getVirtualToolParameterOwnership,
42
41
  isToolAdvertised,
43
42
  readToolMetaCategory,
44
43
  type HandlerPatch,
@@ -260,11 +259,7 @@ async function handleToolCallRequest(
260
259
  extra,
261
260
  eventType: MCPAnalyticsEventType.mcpMissingCapability,
262
261
  explicitContextIntent: context,
263
- parameterOwnership: getVirtualToolParameterOwnership(
264
- data,
265
- toolName,
266
- getReportMissingToolDescriptor(toolName).inputSchema
267
- ),
262
+ parameterOwnership: getAnalyticsParameterOwnership(getReportMissingToolDescriptor(toolName).inputSchema),
268
263
  execute: async () => handleReportMissing({ context }, data.logger),
269
264
  })
270
265
  }
@@ -284,11 +279,7 @@ async function handleToolCallRequest(
284
279
  explicitContextIntent: buildFeedbackIntent(report),
285
280
  omitCapturedParameters: true,
286
281
  extraEventProperties: buildFeedbackEventProperties(report),
287
- parameterOwnership: getVirtualToolParameterOwnership(
288
- data,
289
- toolName,
290
- getFeedbackToolDescriptor(feedbackOptions).inputSchema
291
- ),
282
+ parameterOwnership: getAnalyticsParameterOwnership(getFeedbackToolDescriptor(feedbackOptions).inputSchema),
292
283
  execute: async () => handleFeedback(report, feedbackOptions, data.logger),
293
284
  })
294
285
  }
@@ -13,6 +13,7 @@ import {
13
13
  resolveCollectFeedbackOptions,
14
14
  SEND_FEEDBACK_TOOL_NAME,
15
15
  } from './feedback'
16
+ import { getAnalyticsParameterOwnership } from './analytics-parameters'
16
17
  import { MCPAnalyticsEventType } from './event-types'
17
18
  import { getServerTrackingData } from './internal'
18
19
  import type { LoggerFn } from './logger'
@@ -24,7 +25,6 @@ import {
24
25
  patchRequestHandlers,
25
26
  registerFallbackRequestHandler,
26
27
  captureToolCall,
27
- getVirtualToolParameterOwnership,
28
28
  isToolAdvertised,
29
29
  type HandlerPatch,
30
30
  } from './instrumentation'
@@ -107,11 +107,7 @@ async function handleToolCallRequest(
107
107
  extra,
108
108
  eventType: MCPAnalyticsEventType.mcpMissingCapability,
109
109
  explicitContextIntent: context,
110
- parameterOwnership: getVirtualToolParameterOwnership(
111
- data,
112
- toolName,
113
- getReportMissingToolDescriptor(toolName).inputSchema
114
- ),
110
+ parameterOwnership: getAnalyticsParameterOwnership(getReportMissingToolDescriptor(toolName).inputSchema),
115
111
  execute: async () => handleReportMissing({ context }, data.logger),
116
112
  })
117
113
  }
@@ -131,11 +127,7 @@ async function handleToolCallRequest(
131
127
  explicitContextIntent: buildFeedbackIntent(report),
132
128
  omitCapturedParameters: true,
133
129
  extraEventProperties: buildFeedbackEventProperties(report),
134
- parameterOwnership: getVirtualToolParameterOwnership(
135
- data,
136
- toolName,
137
- getFeedbackToolDescriptor(feedbackOptions).inputSchema
138
- ),
130
+ parameterOwnership: getAnalyticsParameterOwnership(getFeedbackToolDescriptor(feedbackOptions).inputSchema),
139
131
  execute: async () => handleFeedback(report, feedbackOptions, data.logger),
140
132
  })
141
133
  }
@@ -640,36 +640,6 @@ export function patchRequestHandlers(server: MCPServerLike, patches: Record<stri
640
640
  }) as MCPServerLike['setRequestHandler']
641
641
  }
642
642
 
643
- /**
644
- * Ownership for an SDK-owned virtual tool (`get_more_tools`, `send_feedback`),
645
- * resolved from its own descriptor rather than the `tools/list` cache.
646
- *
647
- * A virtual-tool branch is only entered when the application does not advertise
648
- * a tool by this name, so the descriptor is the SDK's own and what it declares
649
- * is known statically. An instance that never served a listing — a per-request
650
- * `McpServer`/`Server`, the topology in ADR-0011 — would otherwise read every
651
- * injected parameter as not-ours and neither capture nor strip it.
652
- *
653
- * `conversation_id` still comes from the cache on purpose: resolving it here too
654
- * would start minting a handle, and appending its prompt-back block, on
655
- * instances that today mint none. That changes session anchoring (ADR-0004)
656
- * rather than closing this gap.
657
- *
658
- * `virtualToolInputSchema` is required (not defaulted to one specific virtual
659
- * tool's descriptor) so every call site names the tool it means; each caller
660
- * passes its own descriptor's `inputSchema`.
661
- */
662
- export function getVirtualToolParameterOwnership(
663
- data: MCPAnalyticsData,
664
- toolName: string,
665
- virtualToolInputSchema: unknown
666
- ): AnalyticsParameterOwnership {
667
- return {
668
- ...getAnalyticsParameterOwnership(virtualToolInputSchema),
669
- conversationId: data.toolAnalyticsParameterOwnership.get(toolName)?.conversationId === true,
670
- }
671
- }
672
-
673
643
  /**
674
644
  * Checks the server's raw listing for a real owner of a candidate virtual tool.
675
645
  * This does not depend on a previous client request and does not call the
@@ -825,19 +795,32 @@ async function getTracedToolsList(
825
795
  }
826
796
 
827
797
  if (data) {
798
+ // A compliant client concatenates every page into one list, so only the
799
+ // first page — the one every client reads, including clients that never
800
+ // follow `nextCursor` — may carry a virtual tool. Presence, not
801
+ // truthiness: `cursor: ""` is a continuation page.
802
+ const isFirstPage = request.params?.cursor == null
803
+
828
804
  const missingToolName = resolveMissingCapabilityToolName(data.options)
829
805
  if (data.options.reportMissing) {
830
806
  const alreadyPresent = tools.some((tool) => tool?.name === missingToolName)
831
- if (alreadyPresent) {
807
+ if (isFirstPage && alreadyPresent) {
832
808
  data.logger(
833
- `Warning: Cannot inject missing-capability tool "${missingToolName}" because a real tool already uses that name. The real tool will not be intercepted.`
809
+ `Warning: Cannot inject missing-capability tool "${missingToolName}" because a real tool already uses that name. The real tool will not be intercepted. To keep missing-capability reports, rename the SDK's tool with the missingCapabilityToolName option.`
834
810
  )
835
- } else {
811
+ } else if (isFirstPage) {
836
812
  const virtualTool = getReportMissingToolDescriptor(missingToolName)
837
813
  tools.push(virtualTool)
838
814
  // Cached separately because the virtual tool is added after the listing
839
815
  // was cached, and its calls need ownership like any other tool's.
840
816
  cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [virtualTool])
817
+ } else if (alreadyPresent) {
818
+ // Conflicts are only detected on the pages a client actually
819
+ // fetches; a real owner here is already shadowed by the first-page
820
+ // injection, so the host must rename the SDK's tool.
821
+ data.logger(
822
+ `Warning: A real tool "${missingToolName}" on a later tools/list page is shadowed by the SDK's missing-capability tool. Its calls will be intercepted. Rename the SDK's tool with the missingCapabilityToolName option to keep both.`
823
+ )
841
824
  }
842
825
  }
843
826
 
@@ -845,11 +828,6 @@ async function getTracedToolsList(
845
828
  if (feedbackOptions) {
846
829
  const feedbackToolName = feedbackOptions.toolName ?? SEND_FEEDBACK_TOOL_NAME
847
830
  const alreadyPresent = tools.some((tool) => tool?.name === feedbackToolName)
848
- // A compliant client concatenates every page into one list, so only the
849
- // first page — the one every client reads, including clients that never
850
- // follow `nextCursor` — may carry the virtual tool. Presence, not
851
- // truthiness: `cursor: ""` is a continuation page.
852
- const isFirstPage = request.params?.cursor == null
853
831
  if (isFirstPage && alreadyPresent) {
854
832
  data.logger(
855
833
  `Warning: Cannot inject agent-feedback tool "${feedbackToolName}" because a real tool already uses that name. The real tool will not be intercepted. To collect feedback alongside it, rename the SDK's tool with collectFeedback: { toolName: "..." }.`
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.16.2'
1
+ export const version = '0.16.4'