@posthog/mcp 0.10.3 → 0.10.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.
Files changed (40) hide show
  1. package/dist/extensions/analytics-parameters.d.ts +5 -0
  2. package/dist/extensions/analytics-parameters.d.ts.map +1 -1
  3. package/dist/extensions/analytics-parameters.js +57 -3
  4. package/dist/extensions/analytics-parameters.mjs +47 -2
  5. package/dist/extensions/context-parameters.d.ts +1 -1
  6. package/dist/extensions/context-parameters.js +1 -1
  7. package/dist/extensions/context-parameters.mjs +1 -1
  8. package/dist/extensions/conversation-id.d.ts +0 -6
  9. package/dist/extensions/conversation-id.d.ts.map +1 -1
  10. package/dist/extensions/conversation-id.js +3 -18
  11. package/dist/extensions/conversation-id.mjs +2 -14
  12. package/dist/extensions/instrument-highlevel.d.ts.map +1 -1
  13. package/dist/extensions/instrument-highlevel.js +9 -28
  14. package/dist/extensions/instrument-highlevel.mjs +8 -27
  15. package/dist/extensions/instrumentation.d.ts +4 -6
  16. package/dist/extensions/instrumentation.d.ts.map +1 -1
  17. package/dist/extensions/instrumentation.js +32 -6
  18. package/dist/extensions/instrumentation.mjs +33 -7
  19. package/dist/extensions/intent.d.ts +1 -1
  20. package/dist/extensions/intent.d.ts.map +1 -1
  21. package/dist/extensions/intent.js +2 -2
  22. package/dist/extensions/intent.mjs +2 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -0
  25. package/dist/index.mjs +1 -0
  26. package/dist/types.d.ts +5 -0
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/dist/version.mjs +1 -1
  31. package/package.json +4 -4
  32. package/src/extensions/analytics-parameters.ts +67 -1
  33. package/src/extensions/context-parameters.ts +2 -2
  34. package/src/extensions/conversation-id.ts +1 -20
  35. package/src/extensions/instrument-highlevel.ts +21 -50
  36. package/src/extensions/instrumentation.ts +71 -11
  37. package/src/extensions/intent.ts +7 -1
  38. package/src/index.ts +1 -0
  39. package/src/types.ts +6 -0
  40. package/src/version.ts +1 -1
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { ListToolsResult } from '@modelcontextprotocol/sdk/types.js'
7
7
  import type {
8
+ AnalyticsParameterOwnership,
8
9
  CompatibleRequestHandlerExtra,
9
10
  MCPAnalyticsData,
10
11
  MCPRequestLike,
@@ -12,12 +13,12 @@ import type {
12
13
  McpEvent,
13
14
  ServerClientInfoLike,
14
15
  } from '../types'
16
+ import { getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from './analytics-parameters'
15
17
  import { addContextParameterToTools, getContextDescription, isContextEnabled } from './context-parameters'
16
18
  import {
17
19
  addConversationIdToTools,
18
20
  type ConversationIdResolution,
19
21
  canInjectConversationIdPromptBack,
20
- cloneRequestWithoutConversationId,
21
22
  injectConversationIdPromptBack,
22
23
  resolveConversationId,
23
24
  } from './conversation-id'
@@ -45,11 +46,7 @@ import { applyResolvedMetadata, isToolResultError } from './tracing-helpers'
45
46
 
46
47
  type MCPRequestHandler = (request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra) => Promise<unknown>
47
48
 
48
- /**
49
- * Runs the underlying tool. Receives the request with the SDK-injected
50
- * `conversation_id` stripped; an adapter is free to ignore it (the high-level
51
- * path strips arguments inside the wrapped callback instead).
52
- */
49
+ /** Runs the underlying tool with SDK-owned analytics arguments removed. */
53
50
  type ToolExecutor = (downstreamRequest: MCPRequestLike) => Promise<unknown>
54
51
 
55
52
  interface TraceToolCallParams {
@@ -58,6 +55,8 @@ interface TraceToolCallParams {
58
55
  request: MCPRequestLike
59
56
  extra?: CompatibleRequestHandlerExtra
60
57
  execute: ToolExecutor
58
+ /** Optional schema-derived ownership override for adapters with direct registry access. */
59
+ parameterOwnership?: AnalyticsParameterOwnership
61
60
  /**
62
61
  * Event type to capture. Defaults to a tool call; the `get_more_tools` virtual
63
62
  * tool passes `mcpMissingCapability` so it records a capability gap rather than
@@ -88,15 +87,26 @@ interface TraceToolCallParams {
88
87
  * throws, and the tool's own errors are always re-thrown to the caller.
89
88
  */
90
89
  export async function captureToolCall(params: TraceToolCallParams): Promise<unknown> {
91
- const { server, data, request, extra, execute, eventType, explicitContextIntent, takeCapturedError } = params
92
-
90
+ const {
91
+ server,
92
+ data,
93
+ request,
94
+ extra,
95
+ execute,
96
+ parameterOwnership,
97
+ eventType,
98
+ explicitContextIntent,
99
+ takeCapturedError,
100
+ } = params
101
+
102
+ const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership)
93
103
  const conversation = resolveConversationId(
94
- data.options.enableConversationId ?? false,
104
+ ownership.conversationId,
95
105
  request.params?.arguments,
96
106
  request.params?.name,
97
107
  resolveMissingCapabilityToolName(data.options)
98
108
  )
99
- const downstreamRequest = conversation.conversationId ? cloneRequestWithoutConversationId(request) : request
109
+ const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership)
100
110
 
101
111
  // Prepare the event in isolation: if identity/metadata/intent resolution
102
112
  // throws, we drop instrumentation for this call but still run the tool.
@@ -109,6 +119,7 @@ export async function captureToolCall(params: TraceToolCallParams): Promise<unkn
109
119
  extra,
110
120
  startTime,
111
121
  conversation,
122
+ ownership,
112
123
  eventType ?? MCPAnalyticsEventType.mcpToolsCall
113
124
  )
114
125
  if (event && explicitContextIntent) {
@@ -128,6 +139,38 @@ export async function captureToolCall(params: TraceToolCallParams): Promise<unkn
128
139
  return finalResult
129
140
  }
130
141
 
142
+ function getActiveAnalyticsParameterOwnership(
143
+ data: MCPAnalyticsData,
144
+ toolName: string | undefined,
145
+ override?: AnalyticsParameterOwnership
146
+ ): AnalyticsParameterOwnership {
147
+ const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : undefined)
148
+ const isMissingCapabilityTool = toolName === resolveMissingCapabilityToolName(data.options)
149
+ return {
150
+ context: !isMissingCapabilityTool && isContextEnabled(data.options.context) && ownership?.context === true,
151
+ conversationId:
152
+ !isMissingCapabilityTool && data.options.enableConversationId === true && ownership?.conversationId === true,
153
+ }
154
+ }
155
+
156
+ function cloneRequestWithoutOwnedAnalyticsArguments(
157
+ request: MCPRequestLike,
158
+ ownership: AnalyticsParameterOwnership
159
+ ): MCPRequestLike {
160
+ const args = request.params?.arguments
161
+ const cleanedArgs = stripOwnedAnalyticsArguments(args, ownership)
162
+ if (cleanedArgs === args || !request.params) {
163
+ return request
164
+ }
165
+ return {
166
+ ...request,
167
+ params: {
168
+ ...request.params,
169
+ arguments: cleanedArgs as typeof request.params.arguments,
170
+ },
171
+ }
172
+ }
173
+
131
174
  async function prepareToolCallEvent(
132
175
  server: MCPServerLike,
133
176
  data: MCPAnalyticsData,
@@ -136,6 +179,7 @@ async function prepareToolCallEvent(
136
179
  extra: CompatibleRequestHandlerExtra | undefined,
137
180
  startTime: Date,
138
181
  conversation: ConversationIdResolution,
182
+ ownership: AnalyticsParameterOwnership,
139
183
  eventType: MCPAnalyticsEventType
140
184
  ): Promise<McpEvent | null> {
141
185
  try {
@@ -159,7 +203,7 @@ async function prepareToolCallEvent(
159
203
  stampMetaClientInfo(event, request)
160
204
 
161
205
  await applyResolvedMetadata(event, data, request, extra)
162
- setEventIntent(event, await resolveToolCallIntent(data, request, extra))
206
+ setEventIntent(event, await resolveToolCallIntent(data, request, ownership.context, extra))
163
207
  return event
164
208
  } catch (error) {
165
209
  log(
@@ -336,6 +380,18 @@ export async function handleListToolsRequest(
336
380
  return { tools }
337
381
  }
338
382
 
383
+ function cacheToolAnalyticsParameterOwnership(
384
+ cache: Map<string, AnalyticsParameterOwnership>,
385
+ tools: ListToolsResult['tools']
386
+ ): void {
387
+ // Merge pages and concurrent enumerations; repeated tool names overwrite stale schemas.
388
+ for (const tool of tools) {
389
+ if (tool?.name) {
390
+ cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema))
391
+ }
392
+ }
393
+ }
394
+
339
395
  function collectListedToolNames(tools: ListToolsResult['tools'] | undefined): string[] | undefined {
340
396
  if (!tools || tools.length === 0) {
341
397
  return
@@ -356,6 +412,10 @@ async function getTracedToolsList(
356
412
  const originalResponse = (await originalListToolsHandler(request, extra)) as ListToolsResult
357
413
  let tools = originalResponse.tools || []
358
414
 
415
+ if (data) {
416
+ cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, tools)
417
+ }
418
+
359
419
  if (data && isContextEnabled(data.options.context)) {
360
420
  tools = addContextParameterToTools(tools, getContextDescription(data.options.context))
361
421
  }
@@ -53,10 +53,16 @@ async function runIntentFallback(
53
53
  export async function resolveToolCallIntent(
54
54
  data: MCPAnalyticsData,
55
55
  request: MCPRequestLike,
56
+ analyticsOwnsContext: boolean,
56
57
  extra?: CompatibleRequestHandlerExtra
57
58
  ): Promise<ResolvedIntent | null> {
58
59
  const contextArgument = getContextArgument(request)
59
- if (isContextEnabled(data.options.context) && request.params?.name !== 'get_more_tools' && contextArgument) {
60
+ if (
61
+ analyticsOwnsContext &&
62
+ isContextEnabled(data.options.context) &&
63
+ request.params?.name !== 'get_more_tools' &&
64
+ contextArgument
65
+ ) {
60
66
  return { intent: contextArgument, source: 'context_parameter' }
61
67
  }
62
68
 
package/src/index.ts CHANGED
@@ -143,6 +143,7 @@ function buildTrackingData(
143
143
  sessionId: newSessionId(),
144
144
  lastActivity: new Date(),
145
145
  identifiedSessions: new IdentityCache(),
146
+ toolAnalyticsParameterOwnership: new Map(),
146
147
  toolCategories: new Map<string, string>(),
147
148
  toolDescriptions: new Map<string, string>(),
148
149
  sessionInfo: getSessionInfo(lowLevelServer, undefined),
package/src/types.ts CHANGED
@@ -271,6 +271,11 @@ export interface SessionInfo {
271
271
  serverVersion?: string
272
272
  }
273
273
 
274
+ export interface AnalyticsParameterOwnership {
275
+ context: boolean
276
+ conversationId: boolean
277
+ }
278
+
274
279
  export interface MCPAnalyticsData {
275
280
  sink: McpEventSink | undefined
276
281
  identifiedSessions: IdentityCache
@@ -280,6 +285,7 @@ export interface MCPAnalyticsData {
280
285
  sessionInfo: SessionInfo
281
286
  /** `token` = recovered from a self-encoded `Mcp-Session-Id` token (see session-token.ts). */
282
287
  sessionSource: 'generated' | 'mcp' | 'token'
288
+ toolAnalyticsParameterOwnership: Map<string, AnalyticsParameterOwnership>
283
289
  toolCategories: Map<string, string>
284
290
  toolDescriptions: Map<string, string>
285
291
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.10.3'
1
+ export const version = '0.10.4'