@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/README.md +61 -0
- package/dist/index.cjs +261 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/dist/index.d.mts +23 -1
- package/dist/index.mjs +260 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
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
|
|
373
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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(
|
|
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
|
-
|
|
2053
|
-
const result = await executeToolCall(server, originalCallToolHandler,
|
|
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
|
-
|
|
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
|
|
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
|
|
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 = (
|
|
2260
|
-
if (
|
|
2261
|
-
const { context: _context, ...
|
|
2262
|
-
return
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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, {
|
|
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
|
-
|
|
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
|
|
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)
|
|
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
|