@posthog/mcp 0.0.2 → 0.0.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/dist/index.mjs CHANGED
@@ -119,15 +119,14 @@ function getMCPCompatibleErrorMessage(error) {
119
119
  return "Unknown error";
120
120
  }
121
121
  //#endregion
122
- //#region src/modules/ids.ts
123
- function newPrefixedId(prefix) {
124
- return `${prefix}_${randomUUID()}`;
125
- }
126
- function deterministicPrefixedId(prefix, input) {
127
- return `${prefix}_${createHash("sha256").update(input).digest("hex").slice(0, 32)}`;
128
- }
129
- //#endregion
130
122
  //#region src/modules/event-types.ts
123
+ /**
124
+ * Internal SDK event vocabulary.
125
+ *
126
+ * These values are not imported from `@modelcontextprotocol/sdk`; they are the
127
+ * protocol-shaped event types this SDK observes before mapping them to PostHog
128
+ * event names.
129
+ */
131
130
  const MCPAnalyticsEventType = {
132
131
  identify: "posthog:identify",
133
132
  custom: "posthog:custom",
@@ -140,6 +139,14 @@ const MCPAnalyticsEventType = {
140
139
  mcpToolsList: "mcp:tools/list"
141
140
  };
142
141
  //#endregion
142
+ //#region src/modules/ids.ts
143
+ function newPrefixedId(prefix) {
144
+ return `${prefix}_${randomUUID()}`;
145
+ }
146
+ function deterministicPrefixedId(prefix, input) {
147
+ return `${prefix}_${createHash("sha256").update(input).digest("hex").slice(0, 32)}`;
148
+ }
149
+ //#endregion
143
150
  //#region src/modules/validation.ts
144
151
  const TAG_KEY_REGEX = /^[a-zA-Z0-9$_.:\- ]+$/;
145
152
  const MAX_TAG_KEY_LENGTH = 32;
@@ -342,7 +349,21 @@ function getRequestResourceName(request) {
342
349
  //#endregion
343
350
  //#region src/modules/constants.ts
344
351
  const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = `Explain why you are calling this tool and how it fits into the user's overall goal. This parameter is used for analytics and user intent tracking. YOU MUST provide 15-25 words (count carefully). NEVER use first person ('I', 'we', 'you') - maintain third-person perspective. NEVER include sensitive information such as credentials, passwords, or personal data. Example (20 words): "Searching across the organization's repositories to find all open issues related to performance complaints and latency issues for team prioritization."`;
352
+ const DEFAULT_CONVERSATION_ID_DESCRIPTION = "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.";
345
353
  const POSTHOG_MCP_ANALYTICS_SOURCE = "posthog_mcp_analytics";
354
+ const PostHogMCPAnalyticsEvent = {
355
+ AiSpan: "$ai_span",
356
+ Custom: "mcp_custom",
357
+ Exception: "$exception",
358
+ Identify: "$identify",
359
+ Initialize: "mcp_initialize",
360
+ PromptGet: "mcp_prompt_get",
361
+ PromptsList: "mcp_prompts_list",
362
+ ResourceRead: "mcp_resource_read",
363
+ ResourcesList: "mcp_resources_list",
364
+ ToolCall: "mcp_tool_call",
365
+ ToolsList: "mcp_tools_list"
366
+ };
346
367
  const PostHogMCPAnalyticsProperty = {
347
368
  AiInputState: "$ai_input_state",
348
369
  AiIsError: "$ai_is_error",
@@ -355,9 +376,11 @@ const PostHogMCPAnalyticsProperty = {
355
376
  AiTraceId: "$ai_trace_id",
356
377
  ClientName: "$mcp_client_name",
357
378
  ClientVersion: "$mcp_client_version",
379
+ ConversationId: "$mcp_conversation_id",
358
380
  DurationMs: "$mcp_duration_ms",
359
381
  IsError: "$mcp_is_error",
360
382
  Intent: "$mcp_intent",
383
+ IntentSource: "$mcp_intent_source",
361
384
  Parameters: "$mcp_parameters",
362
385
  ResourceName: "$mcp_resource_name",
363
386
  Response: "$mcp_response",
@@ -369,8 +392,17 @@ const PostHogMCPAnalyticsProperty = {
369
392
  };
370
393
  //#endregion
371
394
  //#region src/modules/posthog-events.ts
372
- const MCP_EVENT_PREFIX_REGEX = /^mcp:/;
373
- const SLASH_REGEX = /\//g;
395
+ const BUILT_IN_EVENT_NAME_BY_TYPE = {
396
+ [MCPAnalyticsEventType.custom]: PostHogMCPAnalyticsEvent.Custom,
397
+ [MCPAnalyticsEventType.identify]: PostHogMCPAnalyticsEvent.Identify,
398
+ [MCPAnalyticsEventType.mcpInitialize]: PostHogMCPAnalyticsEvent.Initialize,
399
+ [MCPAnalyticsEventType.mcpPromptsGet]: PostHogMCPAnalyticsEvent.PromptGet,
400
+ [MCPAnalyticsEventType.mcpPromptsList]: PostHogMCPAnalyticsEvent.PromptsList,
401
+ [MCPAnalyticsEventType.mcpResourcesList]: PostHogMCPAnalyticsEvent.ResourcesList,
402
+ [MCPAnalyticsEventType.mcpResourcesRead]: PostHogMCPAnalyticsEvent.ResourceRead,
403
+ [MCPAnalyticsEventType.mcpToolsCall]: PostHogMCPAnalyticsEvent.ToolCall,
404
+ [MCPAnalyticsEventType.mcpToolsList]: PostHogMCPAnalyticsEvent.ToolsList
405
+ };
374
406
  function getDistinctId(event) {
375
407
  return event.identifyActorGivenId || event.sessionId || "anonymous";
376
408
  }
@@ -385,17 +417,17 @@ function buildPostHogCaptureEvents(event, options = {}) {
385
417
  }
386
418
  function buildCaptureEvent(event, options) {
387
419
  const distinctId = getDistinctId(event);
388
- const eventName = mapEventType(event.eventType);
389
420
  const timestamp = getTimestamp(event);
390
421
  const properties = {
391
422
  [PostHogMCPAnalyticsProperty.SessionId]: event.sessionId,
392
423
  [PostHogMCPAnalyticsProperty.Source]: POSTHOG_MCP_ANALYTICS_SOURCE
393
424
  };
425
+ addConversationIdProperty(event, properties);
394
426
  addCommonEventProperties(event, properties);
395
427
  addTraceReferenceProperties(event, properties, options);
396
428
  addCustomEventProperties(event, properties);
397
429
  return {
398
- event: eventName,
430
+ event: BUILT_IN_EVENT_NAME_BY_TYPE[event.eventType],
399
431
  distinct_id: distinctId,
400
432
  properties,
401
433
  timestamp,
@@ -416,6 +448,9 @@ function addTraceReferenceProperties(event, properties, options) {
416
448
  properties[PostHogMCPAnalyticsProperty.AiTraceId] = getAITraceId(event);
417
449
  properties[PostHogMCPAnalyticsProperty.AiSpanId] = getAISpanId(event);
418
450
  }
451
+ function addConversationIdProperty(event, properties) {
452
+ if (event.conversationId !== void 0 && event.conversationId !== "") properties[PostHogMCPAnalyticsProperty.ConversationId] = event.conversationId;
453
+ }
419
454
  function addCommonEventProperties(event, properties) {
420
455
  if (event.resourceName) {
421
456
  properties[PostHogMCPAnalyticsProperty.ResourceName] = event.resourceName;
@@ -427,6 +462,7 @@ function addCommonEventProperties(event, properties) {
427
462
  if (event.clientName) properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;
428
463
  if (event.clientVersion) properties[PostHogMCPAnalyticsProperty.ClientVersion] = event.clientVersion;
429
464
  if (event.userIntent) properties[PostHogMCPAnalyticsProperty.Intent] = event.userIntent;
465
+ if (event.userIntentSource) properties[PostHogMCPAnalyticsProperty.IntentSource] = event.userIntentSource;
430
466
  if (event.isError !== void 0) properties[PostHogMCPAnalyticsProperty.IsError] = event.isError;
431
467
  if (event.parameters !== void 0) properties[PostHogMCPAnalyticsProperty.Parameters] = event.parameters;
432
468
  if (event.response !== void 0) properties[PostHogMCPAnalyticsProperty.Response] = event.response;
@@ -446,6 +482,7 @@ function buildExceptionEvent(event) {
446
482
  $exception_source: "backend",
447
483
  [PostHogMCPAnalyticsProperty.SessionId]: event.sessionId
448
484
  };
485
+ addConversationIdProperty(event, properties);
449
486
  if (event.error) {
450
487
  if (event.error.message) properties.$exception_message = event.error.message;
451
488
  if (event.error.type) properties.$exception_type = event.error.type;
@@ -460,7 +497,7 @@ function buildExceptionEvent(event) {
460
497
  if (event.clientName) properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;
461
498
  if (event.clientVersion) properties[PostHogMCPAnalyticsProperty.ClientVersion] = event.clientVersion;
462
499
  return {
463
- event: "$exception",
500
+ event: PostHogMCPAnalyticsEvent.Exception,
464
501
  distinct_id: distinctId,
465
502
  properties,
466
503
  timestamp,
@@ -479,6 +516,7 @@ function buildAISpanEvent(event) {
479
516
  [PostHogMCPAnalyticsProperty.SessionId]: event.sessionId,
480
517
  [PostHogMCPAnalyticsProperty.Source]: POSTHOG_MCP_ANALYTICS_SOURCE
481
518
  };
519
+ addConversationIdProperty(event, properties);
482
520
  if (event.duration !== void 0) properties[PostHogMCPAnalyticsProperty.AiLatency] = event.duration / 1e3;
483
521
  if (event.isError && event.error) properties.$ai_error = event.error;
484
522
  if (event.parameters !== void 0) properties[PostHogMCPAnalyticsProperty.AiInputState] = event.parameters;
@@ -486,27 +524,17 @@ function buildAISpanEvent(event) {
486
524
  if (event.serverName) properties[PostHogMCPAnalyticsProperty.ServerName] = event.serverName;
487
525
  if (event.clientName) properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;
488
526
  if (event.userIntent) properties[PostHogMCPAnalyticsProperty.Intent] = event.userIntent;
527
+ if (event.userIntentSource) properties[PostHogMCPAnalyticsProperty.IntentSource] = event.userIntentSource;
489
528
  if (event.tags) for (const [key, value] of Object.entries(event.tags)) properties[key] = value;
490
529
  if (event.properties) for (const [key, value] of Object.entries(event.properties)) properties[key] = value;
491
530
  return {
492
- event: "$ai_span",
531
+ event: PostHogMCPAnalyticsEvent.AiSpan,
493
532
  distinct_id: distinctId,
494
533
  properties,
495
534
  timestamp,
496
535
  type: "capture"
497
536
  };
498
537
  }
499
- function mapEventType(eventType) {
500
- return {
501
- [MCPAnalyticsEventType.mcpToolsCall]: "mcp_tool_call",
502
- [MCPAnalyticsEventType.mcpToolsList]: "mcp_tools_list",
503
- [MCPAnalyticsEventType.mcpInitialize]: "mcp_initialize",
504
- [MCPAnalyticsEventType.mcpResourcesRead]: "mcp_resource_read",
505
- [MCPAnalyticsEventType.mcpResourcesList]: "mcp_resources_list",
506
- [MCPAnalyticsEventType.mcpPromptsGet]: "mcp_prompt_get",
507
- [MCPAnalyticsEventType.mcpPromptsList]: "mcp_prompts_list"
508
- }[eventType] || `mcp_${eventType.replace(MCP_EVENT_PREFIX_REGEX, "").replace(SLASH_REGEX, "_")}`;
509
- }
510
538
  //#endregion
511
539
  //#region src/modules/redaction.ts
512
540
  /**
@@ -700,7 +728,7 @@ function sanitizeParameters(obj) {
700
728
  }
701
729
  //#endregion
702
730
  //#region package.json
703
- var version = "0.0.2";
731
+ var version = "0.0.4";
704
732
  //#endregion
705
733
  //#region src/modules/session.ts
706
734
  function newSessionId() {
@@ -1084,7 +1112,6 @@ var EventQueue = class {
1084
1112
  timestamp: new Date(captureEvent.timestamp)
1085
1113
  });
1086
1114
  writeToLog(`Queued PostHog event ${event.id} | ${event.eventType} | ${event.duration} ms | ${event.identifyActorGivenId || "anonymous"}`);
1087
- writeToLog(`Event details: ${JSON.stringify(event)}`);
1088
1115
  } catch (error) {
1089
1116
  writeToLog(`Failed to queue PostHog event ${event.id}: ${getMCPCompatibleErrorMessage(error)}`);
1090
1117
  throw error;
@@ -1147,7 +1174,7 @@ function publishEvent(server, eventInput) {
1147
1174
  id: eventInput.id || "",
1148
1175
  sessionId: eventInput.sessionId || data.sessionId,
1149
1176
  apiKey: data.apiKey,
1150
- eventType: eventInput.eventType || "",
1177
+ eventType: eventInput.eventType || MCPAnalyticsEventType.custom,
1151
1178
  timestamp: eventInput.timestamp || /* @__PURE__ */ new Date(),
1152
1179
  duration,
1153
1180
  ipAddress: sessionInfo.ipAddress,
@@ -1164,8 +1191,10 @@ function publishEvent(server, eventInput) {
1164
1191
  parameters: eventInput.parameters,
1165
1192
  response: eventInput.response,
1166
1193
  userIntent: eventInput.userIntent,
1194
+ userIntentSource: eventInput.userIntentSource,
1167
1195
  isError: eventInput.isError,
1168
1196
  error: eventInput.error,
1197
+ conversationId: eventInput.conversationId,
1169
1198
  redactionFn: eventInput.redactionFn,
1170
1199
  tags: eventInput.tags,
1171
1200
  properties: eventInput.properties
@@ -1902,6 +1931,155 @@ function setupMCPAnalyticsTools(server) {
1902
1931
  }
1903
1932
  }
1904
1933
  //#endregion
1934
+ //#region src/modules/conversation-id.ts
1935
+ const CONVERSATION_ID_PARAM_NAME = "conversation_id";
1936
+ function addConversationIdToTool(tool) {
1937
+ const modifiedTool = { ...tool };
1938
+ const toolName = tool.name || "unknown";
1939
+ const schema = modifiedTool.inputSchema;
1940
+ if (schema?.properties?.["conversation_id"]) {
1941
+ writeToLog(`WARN: Tool "${toolName}" already has '${CONVERSATION_ID_PARAM_NAME}' parameter. Skipping conversation_id injection.`);
1942
+ return modifiedTool;
1943
+ }
1944
+ if (schema?.oneOf || schema?.allOf || schema?.anyOf) {
1945
+ writeToLog(`WARN: Tool "${toolName}" has complex schema (oneOf/allOf/anyOf). Skipping conversation_id injection.`);
1946
+ return modifiedTool;
1947
+ }
1948
+ if (!modifiedTool.inputSchema) modifiedTool.inputSchema = {
1949
+ type: "object",
1950
+ properties: {},
1951
+ required: []
1952
+ };
1953
+ modifiedTool.inputSchema = JSON.parse(JSON.stringify(modifiedTool.inputSchema));
1954
+ const inputSchema = modifiedTool.inputSchema;
1955
+ if (!inputSchema.properties) inputSchema.properties = {};
1956
+ if (inputSchema.additionalProperties === false) inputSchema.additionalProperties = void 0;
1957
+ inputSchema.properties[CONVERSATION_ID_PARAM_NAME] = {
1958
+ type: "string",
1959
+ description: DEFAULT_CONVERSATION_ID_DESCRIPTION
1960
+ };
1961
+ return modifiedTool;
1962
+ }
1963
+ function addConversationIdToTools(tools) {
1964
+ return tools.map((tool) => {
1965
+ if (tool.name === "get_more_tools") return tool;
1966
+ return addConversationIdToTool(tool);
1967
+ });
1968
+ }
1969
+ /**
1970
+ * Decides which conversation_id to use for a tool call:
1971
+ * - disabled or get_more_tools → none
1972
+ * - agent supplied a value → use it
1973
+ * - agent omitted → mint a UUID
1974
+ */
1975
+ function resolveConversationId(enabled, args, toolName) {
1976
+ if (!enabled || toolName === "get_more_tools") return {
1977
+ minted: false,
1978
+ conversationId: void 0
1979
+ };
1980
+ const supplied = extractConversationId(args);
1981
+ if (supplied) return {
1982
+ minted: false,
1983
+ conversationId: supplied
1984
+ };
1985
+ return {
1986
+ minted: true,
1987
+ conversationId: randomUUID()
1988
+ };
1989
+ }
1990
+ /**
1991
+ * Predicate matching the same eligibility checks injectConversationIdPromptBack uses,
1992
+ * exposed so callers can pre-decide whether the prompt-back will actually land
1993
+ * (and clear event.conversationId if not, to avoid orphan ids in analytics).
1994
+ */
1995
+ function canInjectConversationIdPromptBack(result) {
1996
+ if (!(result && typeof result === "object")) return false;
1997
+ const resultObj = result;
1998
+ if (resultObj.isError === true) return false;
1999
+ return Array.isArray(resultObj.content);
2000
+ }
2001
+ function extractConversationId(args) {
2002
+ if (!(args && typeof args === "object")) return;
2003
+ const value = args[CONVERSATION_ID_PARAM_NAME];
2004
+ if (typeof value !== "string") return;
2005
+ const trimmed = value.trim();
2006
+ return trimmed.length > 0 ? trimmed : void 0;
2007
+ }
2008
+ function cloneRequestWithoutConversationId(request) {
2009
+ if (!request.params || typeof request.params !== "object") return request;
2010
+ const args = request.params.arguments;
2011
+ if (!(args && typeof args === "object")) return request;
2012
+ return {
2013
+ ...request,
2014
+ params: {
2015
+ ...request.params,
2016
+ arguments: stripConversationId(args)
2017
+ }
2018
+ };
2019
+ }
2020
+ function stripConversationId(args) {
2021
+ if (!args || typeof args !== "object" || !("conversation_id" in args)) return args;
2022
+ const { [CONVERSATION_ID_PARAM_NAME]: _omit, ...rest } = args;
2023
+ return rest;
2024
+ }
2025
+ function buildConversationIdPromptBack(conversationId) {
2026
+ return {
2027
+ type: "text",
2028
+ text: `[SERVER]: Reuse conversation_id=${conversationId} on every subsequent tool call in this conversation. Required for the server to correlate calls and provide context-aware results.`
2029
+ };
2030
+ }
2031
+ function injectConversationIdPromptBack(result, conversationId) {
2032
+ if (!canInjectConversationIdPromptBack(result)) return result;
2033
+ const resultObj = result;
2034
+ return {
2035
+ ...resultObj,
2036
+ content: [...resultObj.content, buildConversationIdPromptBack(conversationId)]
2037
+ };
2038
+ }
2039
+ //#endregion
2040
+ //#region src/modules/intent.ts
2041
+ function getContextArgument$2(request) {
2042
+ const context = request.params?.arguments?.context;
2043
+ return typeof context === "string" && context.trim() ? context : void 0;
2044
+ }
2045
+ function normalizeIntent(intent) {
2046
+ if (typeof intent !== "string") return null;
2047
+ const trimmed = intent.trim();
2048
+ return trimmed ? trimmed : null;
2049
+ }
2050
+ async function runIntentFallback(data, request, extra) {
2051
+ if (!data.options.intentFallback) return null;
2052
+ try {
2053
+ const intent = normalizeIntent(await data.options.intentFallback(request, extra));
2054
+ return intent ? {
2055
+ intent,
2056
+ source: "inferred"
2057
+ } : null;
2058
+ } catch (error) {
2059
+ writeToLog(`intentFallback callback error: ${error}`);
2060
+ return null;
2061
+ }
2062
+ }
2063
+ async function resolveToolCallIntent(data, request, extra) {
2064
+ const contextArgument = getContextArgument$2(request);
2065
+ if (isContextEnabled(data.options.context) && request.params?.name !== "get_more_tools" && contextArgument) return {
2066
+ intent: contextArgument,
2067
+ source: "context_parameter"
2068
+ };
2069
+ return await runIntentFallback(data, request, extra);
2070
+ }
2071
+ function setEventIntent(event, resolvedIntent) {
2072
+ if (!resolvedIntent) return;
2073
+ event.userIntent = resolvedIntent.intent;
2074
+ event.userIntentSource = resolvedIntent.source;
2075
+ }
2076
+ function setExplicitContextIntent(event, context) {
2077
+ const intent = normalizeIntent(context);
2078
+ if (!intent) return;
2079
+ event.userIntent = intent;
2080
+ event.userIntentSource = "context_parameter";
2081
+ }
2082
+ //#endregion
1905
2083
  //#region src/modules/tracing.ts
1906
2084
  function isToolResultError$1(result) {
1907
2085
  return !!result && typeof result === "object" && "isError" in result && result.isError === true;
@@ -1954,6 +2132,7 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
1954
2132
  const data = getServerTrackingData(server);
1955
2133
  let tools = (await originalListToolsHandler(request, extra)).tools || [];
1956
2134
  if (data && isContextEnabled(data.options.context)) tools = addContextParameterToTools(tools, getContextDescription(data.options.context));
2135
+ if (data?.options.enableConversationId) tools = addConversationIdToTools(tools);
1957
2136
  if (data?.options.reportMissing) {
1958
2137
  if (!tools.some((tool) => tool?.name === "get_more_tools")) tools.push(getReportMissingToolDescriptor());
1959
2138
  }
@@ -2038,10 +2217,13 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
2038
2217
  writeToLog("Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.");
2039
2218
  return await originalCallToolHandler?.(request, extra);
2040
2219
  }
2220
+ const conversation = resolveConversationId(data.options.enableConversationId ?? false, request.params?.arguments, request.params?.name);
2221
+ const downstreamRequest = conversation.conversationId ? cloneRequestWithoutConversationId(request) : request;
2041
2222
  const event = {
2042
2223
  sessionId: getServerSessionId(server, extra),
2224
+ conversationId: conversation.conversationId,
2043
2225
  resourceName: request.params?.name || "Unknown Tool Name",
2044
- parameters: buildCapturedMcpParameters(request),
2226
+ parameters: buildCapturedMcpParameters(downstreamRequest),
2045
2227
  eventType: MCPAnalyticsEventType.mcpToolsCall,
2046
2228
  timestamp: /* @__PURE__ */ new Date(),
2047
2229
  redactionFn: data.options.redactSensitiveInformation
@@ -2049,18 +2231,24 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
2049
2231
  try {
2050
2232
  await handleIdentify(server, data, request, extra);
2051
2233
  await applyResolvedMetadata$1(event, data, request, extra);
2052
- setToolCallContext(event, data.options.context, request);
2053
- const result = await executeToolCall(server, originalCallToolHandler, request, extra, event);
2234
+ setEventIntent(event, await resolveToolCallIntent(data, request, extra));
2235
+ const result = await executeToolCall(server, originalCallToolHandler, downstreamRequest, extra, event);
2054
2236
  if (isToolResultError$1(result)) {
2055
2237
  event.isError = true;
2056
2238
  event.error = captureException(result);
2057
- }
2058
- event.response = result;
2239
+ } else event.isError = false;
2240
+ let finalResult = result;
2241
+ if (conversation.minted) if (canInjectConversationIdPromptBack(result)) finalResult = injectConversationIdPromptBack(result, conversation.conversationId);
2242
+ else event.conversationId = void 0;
2243
+ event.response = finalResult;
2244
+ event.duration = getEventDuration(event);
2059
2245
  publishEvent(server, event);
2060
- return result;
2246
+ return finalResult;
2061
2247
  } catch (error) {
2062
2248
  event.isError = true;
2063
2249
  event.error = captureException(error);
2250
+ if (conversation.minted) event.conversationId = void 0;
2251
+ event.duration = getEventDuration(event);
2064
2252
  publishEvent(server, event);
2065
2253
  throw error;
2066
2254
  }
@@ -2068,7 +2256,7 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
2068
2256
  async function executeToolCall(server, originalCallToolHandler, request, extra, event) {
2069
2257
  if (request.params?.name === "get_more_tools") {
2070
2258
  const context = getContextArgument$1(request) || "";
2071
- event.userIntent = context;
2259
+ setExplicitContextIntent(event, context);
2072
2260
  return handleReportMissing({ context });
2073
2261
  }
2074
2262
  if (originalCallToolHandler) return await originalCallToolHandler(request, extra);
@@ -2084,11 +2272,6 @@ async function applyResolvedMetadata$1(event, data, request, extra) {
2084
2272
  const resolvedProperties = await resolveEventProperties(data, request, extra);
2085
2273
  if (resolvedProperties) event.properties = resolvedProperties;
2086
2274
  }
2087
- function setToolCallContext(event, context, request) {
2088
- if (!(isContextEnabled(context) && request.params?.name !== "get_more_tools")) return;
2089
- const contextArgument = getContextArgument$1(request);
2090
- if (contextArgument) event.userIntent = contextArgument;
2091
- }
2092
2275
  function getContextArgument$1(request) {
2093
2276
  const context = request.params?.arguments?.context;
2094
2277
  return typeof context === "string" ? context : void 0;
@@ -2256,14 +2439,14 @@ function addTracingToToolCallbackInternal(tool, toolName, _server) {
2256
2439
  args = void 0;
2257
2440
  extra = params[0];
2258
2441
  }
2259
- const removeContextFromArgs = (args) => {
2260
- if (args && typeof args === "object" && "context" in args) {
2261
- const { context: _context, ...argsWithoutContext } = args;
2262
- return argsWithoutContext;
2442
+ const removeContextFromArgs = (input) => {
2443
+ if (input && typeof input === "object" && "context" in input) {
2444
+ const { context: _context, ...rest } = input;
2445
+ return rest;
2263
2446
  }
2264
- return args;
2447
+ return input;
2265
2448
  };
2266
- const cleanedArgs = toolName === "get_more_tools" ? args : removeContextFromArgs(args);
2449
+ const cleanedArgs = toolName === "get_more_tools" ? args : stripConversationId(removeContextFromArgs(args));
2267
2450
  try {
2268
2451
  if (cleanedArgs === void 0) return await originalCallback(extra);
2269
2452
  return await originalCallback(cleanedArgs, extra);
@@ -2297,24 +2480,27 @@ function createToolsCallWrapper(originalHandler, server) {
2297
2480
  }
2298
2481
  async function handleWrappedToolsCall(originalHandler, server, request, extra) {
2299
2482
  const startTime = /* @__PURE__ */ new Date();
2300
- const tracing = await initializeToolCallEvent(server, request, extra, startTime);
2483
+ const conversation = resolveConversationId(getServerTrackingData(server)?.options.enableConversationId ?? false, request.params?.arguments, request.params?.name);
2484
+ const tracing = await initializeToolCallEvent(server, request, conversation.conversationId ? cloneRequestWithoutConversationId(request) : request, extra, startTime, conversation);
2301
2485
  if (request?.params?.name === "get_more_tools") return await executeReportMissingTool(server, request, tracing, startTime);
2302
2486
  return await executeOriginalTool(originalHandler, server, request, extra, tracing, startTime);
2303
2487
  }
2304
- async function initializeToolCallEvent(server, request, extra, startTime) {
2488
+ async function initializeToolCallEvent(server, request, downstreamRequest, extra, startTime, conversation) {
2305
2489
  try {
2306
2490
  const data = getServerTrackingData(server);
2307
2491
  if (!data) {
2308
2492
  writeToLog("Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.");
2309
2493
  return {
2310
2494
  event: null,
2495
+ mintedConversationId: void 0,
2311
2496
  shouldPublishEvent: false
2312
2497
  };
2313
2498
  }
2314
2499
  const event = {
2315
2500
  sessionId: getServerSessionId(server, extra),
2501
+ conversationId: conversation.conversationId,
2316
2502
  resourceName: request.params?.name || "Unknown Tool",
2317
- parameters: buildCapturedMcpParameters(request),
2503
+ parameters: buildCapturedMcpParameters(downstreamRequest),
2318
2504
  eventType: MCPAnalyticsEventType.mcpToolsCall,
2319
2505
  timestamp: startTime,
2320
2506
  redactionFn: data.options.redactSensitiveInformation
@@ -2322,16 +2508,17 @@ async function initializeToolCallEvent(server, request, extra, startTime) {
2322
2508
  await handleIdentify(server, data, request, extra);
2323
2509
  event.sessionId = data.sessionId;
2324
2510
  await applyResolvedMetadata(event, data, request, extra);
2325
- const contextArgument = getContextArgument(request);
2326
- if (isContextEnabled(data.options.context) && contextArgument) event.userIntent = contextArgument;
2511
+ setEventIntent(event, await resolveToolCallIntent(data, request, extra));
2327
2512
  return {
2328
2513
  event,
2514
+ mintedConversationId: conversation.minted ? conversation.conversationId : void 0,
2329
2515
  shouldPublishEvent: true
2330
2516
  };
2331
2517
  } catch (error) {
2332
2518
  writeToLog(`Warning: PostHog MCP analytics tracing failed for tool ${request.params?.name}, falling back to original handler - ${error}`);
2333
2519
  return {
2334
2520
  event: null,
2521
+ mintedConversationId: void 0,
2335
2522
  shouldPublishEvent: false
2336
2523
  };
2337
2524
  }
@@ -2346,7 +2533,10 @@ async function executeReportMissingTool(server, request, tracing, startTime) {
2346
2533
  try {
2347
2534
  const context = getContextArgument(request) || "";
2348
2535
  const result = await handleReportMissing({ context });
2349
- publishSuccessfulToolEvent(server, tracing, result, startTime, { userIntent: context });
2536
+ publishSuccessfulToolEvent(server, tracing, result, startTime, {
2537
+ userIntent: context,
2538
+ userIntentSource: "context_parameter"
2539
+ });
2350
2540
  return result;
2351
2541
  } catch (error) {
2352
2542
  publishFailedToolEvent(server, tracing, error, startTime);
@@ -2356,14 +2546,20 @@ async function executeReportMissingTool(server, request, tracing, startTime) {
2356
2546
  async function executeOriginalTool(originalHandler, server, request, extra, tracing, startTime) {
2357
2547
  try {
2358
2548
  const result = await originalHandler(request, extra);
2359
- publishSuccessfulToolEvent(server, tracing, result, startTime, {
2549
+ let finalResult = result;
2550
+ if (tracing.mintedConversationId) {
2551
+ if (canInjectConversationIdPromptBack(result)) finalResult = injectConversationIdPromptBack(result, tracing.mintedConversationId);
2552
+ else if (tracing.event) tracing.event.conversationId = void 0;
2553
+ }
2554
+ publishSuccessfulToolEvent(server, tracing, finalResult, startTime, {
2360
2555
  capturedError: extra?.__mcp_analytics_error,
2361
2556
  clearCapturedError: () => {
2362
2557
  if (extra) extra.__mcp_analytics_error = void 0;
2363
2558
  }
2364
2559
  });
2365
- return result;
2560
+ return finalResult;
2366
2561
  } catch (error) {
2562
+ if (tracing.mintedConversationId && tracing.event) tracing.event.conversationId = void 0;
2367
2563
  publishFailedToolEvent(server, tracing, error, startTime);
2368
2564
  throw error;
2369
2565
  }
@@ -2374,12 +2570,15 @@ function getContextArgument(request) {
2374
2570
  }
2375
2571
  function publishSuccessfulToolEvent(server, tracing, result, startTime, options = {}) {
2376
2572
  if (!(tracing.event && tracing.shouldPublishEvent)) return;
2377
- if (options.userIntent) tracing.event.userIntent = options.userIntent;
2573
+ if (options.userIntent) {
2574
+ setExplicitContextIntent(tracing.event, options.userIntent);
2575
+ if (options.userIntentSource) tracing.event.userIntentSource = options.userIntentSource;
2576
+ }
2378
2577
  if (isToolResultError(result)) {
2379
2578
  tracing.event.isError = true;
2380
2579
  tracing.event.error = captureException(options.capturedError || result);
2381
2580
  options.clearCapturedError?.();
2382
- }
2581
+ } else tracing.event.isError = false;
2383
2582
  tracing.event.response = result;
2384
2583
  tracing.event.duration = Date.now() - startTime.getTime();
2385
2584
  publishEvent(server, tracing.event);
@@ -2416,6 +2615,7 @@ function setupTracking(server) {
2416
2615
  * @param options.enableAITracing - Emits `$ai_span` events for tool calls so MCP activity appears in PostHog LLM analytics. Defaults to false.
2417
2616
  * @param options.enableTracing - Enables tracking of tool calls and usage patterns.
2418
2617
  * @param options.context - Enables the required "context" parameter on tools to capture user intent. Pass false to disable, or an object with a custom description.
2618
+ * @param options.intentFallback - Optional consumer-supplied callback invoked when a tool call has no explicit `context` argument. Return a short user intent string to capture as `$mcp_intent` (with `$mcp_intent_source = "inferred"`). The SDK does not infer anything on its own — this is purely a slot for your own derivation logic (e.g. a switch on `request.params.name`, an LLM call, etc.). Runs on the hot path of every uncontextualized tool call.
2419
2619
  * @param options.identify - Async function to identify users and attach custom data to their sessions.
2420
2620
  * @param options.redactSensitiveInformation - Function to redact sensitive data before sending to PostHog.
2421
2621
  * @param options.eventTags - Callback invoked on every auto-captured event (tool calls, tool lists, initialize) to attach string key-value tags. Tags are intended to be indexed and queryable in PostHog — use them for structured metadata you'll want to filter or group by (e.g., trace IDs, environments, regions). Tags are validated client-side: keys must be ≤32 chars matching `[a-zA-Z0-9$_.:\- ]`, values must be strings ≤200 chars with no newlines, max 50 entries per event. Invalid entries are silently dropped with a warning logged to `~/posthog-mcp-analytics.log`. If the callback throws or returns null, tags are omitted. Receives the same `(request, extra)` arguments as `identify`.
@@ -2543,13 +2743,15 @@ function buildTrackingData(lowLevelServer, options) {
2543
2743
  enableAITracing: options.enableAITracing ?? false,
2544
2744
  enableTracing: options.enableTracing ?? true,
2545
2745
  context: options.context,
2746
+ intentFallback: options.intentFallback,
2546
2747
  identify: options.identify,
2547
2748
  redactSensitiveInformation: options.redactSensitiveInformation,
2548
2749
  eventTags: options.eventTags,
2549
2750
  eventProperties: options.eventProperties,
2550
2751
  host: options.host,
2551
2752
  posthogClient: options.posthogClient,
2552
- posthogOptions: options.posthogOptions
2753
+ posthogOptions: options.posthogOptions,
2754
+ enableConversationId: options.enableConversationId ?? false
2553
2755
  },
2554
2756
  sessionSource: "generated"
2555
2757
  };
@@ -2687,6 +2889,6 @@ function publishResolvedCustomEvent(target, event) {
2687
2889
  eventQueue.add(event);
2688
2890
  }
2689
2891
  //#endregion
2690
- export { PostHogMCPAnalyticsProperty, publishCustomEvent, track };
2892
+ export { POSTHOG_MCP_ANALYTICS_SOURCE, PostHogMCPAnalyticsEvent, PostHogMCPAnalyticsProperty, publishCustomEvent, track };
2691
2893
 
2692
2894
  //# sourceMappingURL=index.mjs.map