@posthog/mcp 0.0.2 → 0.0.3
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 +45 -0
- package/dist/index.cjs +110 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.mts +21 -1
- package/dist/index.mjs +109 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,21 @@ track(server, {
|
|
|
34
34
|
With `context: true`, the SDK adds a required `context` argument to every tool call, strips it before invoking your handler, and captures it as `$mcp_intent` on PostHog events.
|
|
35
35
|
Captured tool parameters omit the duplicated `context` value and MCP transport internals.
|
|
36
36
|
|
|
37
|
+
Use `intentFallback` when you want a fallback for clients that call tools without the `context` argument.
|
|
38
|
+
This is a consumer-supplied callback — the SDK does no inference of its own; whatever string you return becomes `$mcp_intent`.
|
|
39
|
+
The explicit `context` argument always wins; fallback values are marked with `$mcp_intent_source = "inferred"`.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
track(server, {
|
|
43
|
+
apiKey: process.env.POSTHOG_API_KEY,
|
|
44
|
+
context: true,
|
|
45
|
+
intentFallback: (request) => {
|
|
46
|
+
const toolName = request.params?.name;
|
|
47
|
+
return toolName ? `Calling ${toolName}` : undefined;
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
37
52
|
With `enableAITracing: true`, tool calls also emit `$ai_span` events with `$ai_trace_id` and `$ai_span_id`.
|
|
38
53
|
The regular `mcp_tool_call` event includes the same trace/span IDs so it can be joined back to the LLM analytics span.
|
|
39
54
|
|
|
@@ -52,6 +67,36 @@ track(server, {
|
|
|
52
67
|
});
|
|
53
68
|
```
|
|
54
69
|
|
|
70
|
+
## Event schema
|
|
71
|
+
|
|
72
|
+
The SDK emits PostHog events using a stable MCP-specific schema.
|
|
73
|
+
The package exports `PostHogMCPAnalyticsEvent`, `PostHogMCPAnalyticsProperty`, and `POSTHOG_MCP_ANALYTICS_SOURCE` constants so product code can query the same contract without hard-coded strings.
|
|
74
|
+
|
|
75
|
+
Canonical event names:
|
|
76
|
+
|
|
77
|
+
- `mcp_tool_call` for each MCP tool call
|
|
78
|
+
- `mcp_tools_list` when clients list available tools
|
|
79
|
+
- `mcp_initialize` when clients initialize a session
|
|
80
|
+
- `$ai_span` for tool-call spans when `enableAITracing: true`
|
|
81
|
+
- `$exception` for captured tool errors
|
|
82
|
+
|
|
83
|
+
Important properties:
|
|
84
|
+
|
|
85
|
+
- `$mcp_source = "posthog_mcp_analytics"`
|
|
86
|
+
- `$mcp_intent` from the `context` argument, or from `intentFallback` when no context was provided
|
|
87
|
+
- `$mcp_intent_source` as `context_parameter` or `inferred`
|
|
88
|
+
- `$mcp_tool_name` and `$mcp_resource_name`
|
|
89
|
+
- `$mcp_parameters` and `$mcp_response`, after redaction and truncation
|
|
90
|
+
- `$mcp_duration_ms`
|
|
91
|
+
- `$mcp_is_error`
|
|
92
|
+
- `$session_id`
|
|
93
|
+
- `$ai_trace_id`, `$ai_span_id`, and `$ai_session_id` when AI tracing is enabled
|
|
94
|
+
|
|
95
|
+
The SDK does not emit `$mcp_context`.
|
|
96
|
+
Use `$mcp_intent` for agent/user intent.
|
|
97
|
+
|
|
98
|
+
See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) for the full architecture, property catalog, sample queries, and migration notes vs the upstream mcpcat schema.
|
|
99
|
+
|
|
55
100
|
## Development
|
|
56
101
|
|
|
57
102
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -120,15 +120,14 @@ function getMCPCompatibleErrorMessage(error) {
|
|
|
120
120
|
return "Unknown error";
|
|
121
121
|
}
|
|
122
122
|
//#endregion
|
|
123
|
-
//#region src/modules/ids.ts
|
|
124
|
-
function newPrefixedId(prefix) {
|
|
125
|
-
return `${prefix}_${(0, node_crypto.randomUUID)()}`;
|
|
126
|
-
}
|
|
127
|
-
function deterministicPrefixedId(prefix, input) {
|
|
128
|
-
return `${prefix}_${(0, node_crypto.createHash)("sha256").update(input).digest("hex").slice(0, 32)}`;
|
|
129
|
-
}
|
|
130
|
-
//#endregion
|
|
131
123
|
//#region src/modules/event-types.ts
|
|
124
|
+
/**
|
|
125
|
+
* Internal SDK event vocabulary.
|
|
126
|
+
*
|
|
127
|
+
* These values are not imported from `@modelcontextprotocol/sdk`; they are the
|
|
128
|
+
* protocol-shaped event types this SDK observes before mapping them to PostHog
|
|
129
|
+
* event names.
|
|
130
|
+
*/
|
|
132
131
|
const MCPAnalyticsEventType = {
|
|
133
132
|
identify: "posthog:identify",
|
|
134
133
|
custom: "posthog:custom",
|
|
@@ -141,6 +140,14 @@ const MCPAnalyticsEventType = {
|
|
|
141
140
|
mcpToolsList: "mcp:tools/list"
|
|
142
141
|
};
|
|
143
142
|
//#endregion
|
|
143
|
+
//#region src/modules/ids.ts
|
|
144
|
+
function newPrefixedId(prefix) {
|
|
145
|
+
return `${prefix}_${(0, node_crypto.randomUUID)()}`;
|
|
146
|
+
}
|
|
147
|
+
function deterministicPrefixedId(prefix, input) {
|
|
148
|
+
return `${prefix}_${(0, node_crypto.createHash)("sha256").update(input).digest("hex").slice(0, 32)}`;
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
144
151
|
//#region src/modules/validation.ts
|
|
145
152
|
const TAG_KEY_REGEX = /^[a-zA-Z0-9$_.:\- ]+$/;
|
|
146
153
|
const MAX_TAG_KEY_LENGTH = 32;
|
|
@@ -344,6 +351,19 @@ function getRequestResourceName(request) {
|
|
|
344
351
|
//#region src/modules/constants.ts
|
|
345
352
|
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."`;
|
|
346
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
|
+
};
|
|
347
367
|
const PostHogMCPAnalyticsProperty = {
|
|
348
368
|
AiInputState: "$ai_input_state",
|
|
349
369
|
AiIsError: "$ai_is_error",
|
|
@@ -359,6 +379,7 @@ const PostHogMCPAnalyticsProperty = {
|
|
|
359
379
|
DurationMs: "$mcp_duration_ms",
|
|
360
380
|
IsError: "$mcp_is_error",
|
|
361
381
|
Intent: "$mcp_intent",
|
|
382
|
+
IntentSource: "$mcp_intent_source",
|
|
362
383
|
Parameters: "$mcp_parameters",
|
|
363
384
|
ResourceName: "$mcp_resource_name",
|
|
364
385
|
Response: "$mcp_response",
|
|
@@ -370,8 +391,17 @@ const PostHogMCPAnalyticsProperty = {
|
|
|
370
391
|
};
|
|
371
392
|
//#endregion
|
|
372
393
|
//#region src/modules/posthog-events.ts
|
|
373
|
-
const
|
|
374
|
-
|
|
394
|
+
const BUILT_IN_EVENT_NAME_BY_TYPE = {
|
|
395
|
+
[MCPAnalyticsEventType.custom]: PostHogMCPAnalyticsEvent.Custom,
|
|
396
|
+
[MCPAnalyticsEventType.identify]: PostHogMCPAnalyticsEvent.Identify,
|
|
397
|
+
[MCPAnalyticsEventType.mcpInitialize]: PostHogMCPAnalyticsEvent.Initialize,
|
|
398
|
+
[MCPAnalyticsEventType.mcpPromptsGet]: PostHogMCPAnalyticsEvent.PromptGet,
|
|
399
|
+
[MCPAnalyticsEventType.mcpPromptsList]: PostHogMCPAnalyticsEvent.PromptsList,
|
|
400
|
+
[MCPAnalyticsEventType.mcpResourcesList]: PostHogMCPAnalyticsEvent.ResourcesList,
|
|
401
|
+
[MCPAnalyticsEventType.mcpResourcesRead]: PostHogMCPAnalyticsEvent.ResourceRead,
|
|
402
|
+
[MCPAnalyticsEventType.mcpToolsCall]: PostHogMCPAnalyticsEvent.ToolCall,
|
|
403
|
+
[MCPAnalyticsEventType.mcpToolsList]: PostHogMCPAnalyticsEvent.ToolsList
|
|
404
|
+
};
|
|
375
405
|
function getDistinctId(event) {
|
|
376
406
|
return event.identifyActorGivenId || event.sessionId || "anonymous";
|
|
377
407
|
}
|
|
@@ -386,7 +416,6 @@ function buildPostHogCaptureEvents(event, options = {}) {
|
|
|
386
416
|
}
|
|
387
417
|
function buildCaptureEvent(event, options) {
|
|
388
418
|
const distinctId = getDistinctId(event);
|
|
389
|
-
const eventName = mapEventType(event.eventType);
|
|
390
419
|
const timestamp = getTimestamp(event);
|
|
391
420
|
const properties = {
|
|
392
421
|
[PostHogMCPAnalyticsProperty.SessionId]: event.sessionId,
|
|
@@ -396,7 +425,7 @@ function buildCaptureEvent(event, options) {
|
|
|
396
425
|
addTraceReferenceProperties(event, properties, options);
|
|
397
426
|
addCustomEventProperties(event, properties);
|
|
398
427
|
return {
|
|
399
|
-
event:
|
|
428
|
+
event: BUILT_IN_EVENT_NAME_BY_TYPE[event.eventType],
|
|
400
429
|
distinct_id: distinctId,
|
|
401
430
|
properties,
|
|
402
431
|
timestamp,
|
|
@@ -428,6 +457,7 @@ function addCommonEventProperties(event, properties) {
|
|
|
428
457
|
if (event.clientName) properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;
|
|
429
458
|
if (event.clientVersion) properties[PostHogMCPAnalyticsProperty.ClientVersion] = event.clientVersion;
|
|
430
459
|
if (event.userIntent) properties[PostHogMCPAnalyticsProperty.Intent] = event.userIntent;
|
|
460
|
+
if (event.userIntentSource) properties[PostHogMCPAnalyticsProperty.IntentSource] = event.userIntentSource;
|
|
431
461
|
if (event.isError !== void 0) properties[PostHogMCPAnalyticsProperty.IsError] = event.isError;
|
|
432
462
|
if (event.parameters !== void 0) properties[PostHogMCPAnalyticsProperty.Parameters] = event.parameters;
|
|
433
463
|
if (event.response !== void 0) properties[PostHogMCPAnalyticsProperty.Response] = event.response;
|
|
@@ -461,7 +491,7 @@ function buildExceptionEvent(event) {
|
|
|
461
491
|
if (event.clientName) properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;
|
|
462
492
|
if (event.clientVersion) properties[PostHogMCPAnalyticsProperty.ClientVersion] = event.clientVersion;
|
|
463
493
|
return {
|
|
464
|
-
event:
|
|
494
|
+
event: PostHogMCPAnalyticsEvent.Exception,
|
|
465
495
|
distinct_id: distinctId,
|
|
466
496
|
properties,
|
|
467
497
|
timestamp,
|
|
@@ -487,27 +517,17 @@ function buildAISpanEvent(event) {
|
|
|
487
517
|
if (event.serverName) properties[PostHogMCPAnalyticsProperty.ServerName] = event.serverName;
|
|
488
518
|
if (event.clientName) properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;
|
|
489
519
|
if (event.userIntent) properties[PostHogMCPAnalyticsProperty.Intent] = event.userIntent;
|
|
520
|
+
if (event.userIntentSource) properties[PostHogMCPAnalyticsProperty.IntentSource] = event.userIntentSource;
|
|
490
521
|
if (event.tags) for (const [key, value] of Object.entries(event.tags)) properties[key] = value;
|
|
491
522
|
if (event.properties) for (const [key, value] of Object.entries(event.properties)) properties[key] = value;
|
|
492
523
|
return {
|
|
493
|
-
event:
|
|
524
|
+
event: PostHogMCPAnalyticsEvent.AiSpan,
|
|
494
525
|
distinct_id: distinctId,
|
|
495
526
|
properties,
|
|
496
527
|
timestamp,
|
|
497
528
|
type: "capture"
|
|
498
529
|
};
|
|
499
530
|
}
|
|
500
|
-
function mapEventType(eventType) {
|
|
501
|
-
return {
|
|
502
|
-
[MCPAnalyticsEventType.mcpToolsCall]: "mcp_tool_call",
|
|
503
|
-
[MCPAnalyticsEventType.mcpToolsList]: "mcp_tools_list",
|
|
504
|
-
[MCPAnalyticsEventType.mcpInitialize]: "mcp_initialize",
|
|
505
|
-
[MCPAnalyticsEventType.mcpResourcesRead]: "mcp_resource_read",
|
|
506
|
-
[MCPAnalyticsEventType.mcpResourcesList]: "mcp_resources_list",
|
|
507
|
-
[MCPAnalyticsEventType.mcpPromptsGet]: "mcp_prompt_get",
|
|
508
|
-
[MCPAnalyticsEventType.mcpPromptsList]: "mcp_prompts_list"
|
|
509
|
-
}[eventType] || `mcp_${eventType.replace(MCP_EVENT_PREFIX_REGEX, "").replace(SLASH_REGEX, "_")}`;
|
|
510
|
-
}
|
|
511
531
|
//#endregion
|
|
512
532
|
//#region src/modules/redaction.ts
|
|
513
533
|
/**
|
|
@@ -701,7 +721,7 @@ function sanitizeParameters(obj) {
|
|
|
701
721
|
}
|
|
702
722
|
//#endregion
|
|
703
723
|
//#region package.json
|
|
704
|
-
var version = "0.0.
|
|
724
|
+
var version = "0.0.3";
|
|
705
725
|
//#endregion
|
|
706
726
|
//#region src/modules/session.ts
|
|
707
727
|
function newSessionId() {
|
|
@@ -1085,7 +1105,6 @@ var EventQueue = class {
|
|
|
1085
1105
|
timestamp: new Date(captureEvent.timestamp)
|
|
1086
1106
|
});
|
|
1087
1107
|
writeToLog(`Queued PostHog event ${event.id} | ${event.eventType} | ${event.duration} ms | ${event.identifyActorGivenId || "anonymous"}`);
|
|
1088
|
-
writeToLog(`Event details: ${JSON.stringify(event)}`);
|
|
1089
1108
|
} catch (error) {
|
|
1090
1109
|
writeToLog(`Failed to queue PostHog event ${event.id}: ${getMCPCompatibleErrorMessage(error)}`);
|
|
1091
1110
|
throw error;
|
|
@@ -1148,7 +1167,7 @@ function publishEvent(server, eventInput) {
|
|
|
1148
1167
|
id: eventInput.id || "",
|
|
1149
1168
|
sessionId: eventInput.sessionId || data.sessionId,
|
|
1150
1169
|
apiKey: data.apiKey,
|
|
1151
|
-
eventType: eventInput.eventType ||
|
|
1170
|
+
eventType: eventInput.eventType || MCPAnalyticsEventType.custom,
|
|
1152
1171
|
timestamp: eventInput.timestamp || /* @__PURE__ */ new Date(),
|
|
1153
1172
|
duration,
|
|
1154
1173
|
ipAddress: sessionInfo.ipAddress,
|
|
@@ -1165,6 +1184,7 @@ function publishEvent(server, eventInput) {
|
|
|
1165
1184
|
parameters: eventInput.parameters,
|
|
1166
1185
|
response: eventInput.response,
|
|
1167
1186
|
userIntent: eventInput.userIntent,
|
|
1187
|
+
userIntentSource: eventInput.userIntentSource,
|
|
1168
1188
|
isError: eventInput.isError,
|
|
1169
1189
|
error: eventInput.error,
|
|
1170
1190
|
redactionFn: eventInput.redactionFn,
|
|
@@ -1903,6 +1923,49 @@ function setupMCPAnalyticsTools(server) {
|
|
|
1903
1923
|
}
|
|
1904
1924
|
}
|
|
1905
1925
|
//#endregion
|
|
1926
|
+
//#region src/modules/intent.ts
|
|
1927
|
+
function getContextArgument$2(request) {
|
|
1928
|
+
const context = request.params?.arguments?.context;
|
|
1929
|
+
return typeof context === "string" && context.trim() ? context : void 0;
|
|
1930
|
+
}
|
|
1931
|
+
function normalizeIntent(intent) {
|
|
1932
|
+
if (typeof intent !== "string") return null;
|
|
1933
|
+
const trimmed = intent.trim();
|
|
1934
|
+
return trimmed ? trimmed : null;
|
|
1935
|
+
}
|
|
1936
|
+
async function runIntentFallback(data, request, extra) {
|
|
1937
|
+
if (!data.options.intentFallback) return null;
|
|
1938
|
+
try {
|
|
1939
|
+
const intent = normalizeIntent(await data.options.intentFallback(request, extra));
|
|
1940
|
+
return intent ? {
|
|
1941
|
+
intent,
|
|
1942
|
+
source: "inferred"
|
|
1943
|
+
} : null;
|
|
1944
|
+
} catch (error) {
|
|
1945
|
+
writeToLog(`intentFallback callback error: ${error}`);
|
|
1946
|
+
return null;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
async function resolveToolCallIntent(data, request, extra) {
|
|
1950
|
+
const contextArgument = getContextArgument$2(request);
|
|
1951
|
+
if (isContextEnabled(data.options.context) && request.params?.name !== "get_more_tools" && contextArgument) return {
|
|
1952
|
+
intent: contextArgument,
|
|
1953
|
+
source: "context_parameter"
|
|
1954
|
+
};
|
|
1955
|
+
return await runIntentFallback(data, request, extra);
|
|
1956
|
+
}
|
|
1957
|
+
function setEventIntent(event, resolvedIntent) {
|
|
1958
|
+
if (!resolvedIntent) return;
|
|
1959
|
+
event.userIntent = resolvedIntent.intent;
|
|
1960
|
+
event.userIntentSource = resolvedIntent.source;
|
|
1961
|
+
}
|
|
1962
|
+
function setExplicitContextIntent(event, context) {
|
|
1963
|
+
const intent = normalizeIntent(context);
|
|
1964
|
+
if (!intent) return;
|
|
1965
|
+
event.userIntent = intent;
|
|
1966
|
+
event.userIntentSource = "context_parameter";
|
|
1967
|
+
}
|
|
1968
|
+
//#endregion
|
|
1906
1969
|
//#region src/modules/tracing.ts
|
|
1907
1970
|
function isToolResultError$1(result) {
|
|
1908
1971
|
return !!result && typeof result === "object" && "isError" in result && result.isError === true;
|
|
@@ -2050,18 +2113,20 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
|
|
|
2050
2113
|
try {
|
|
2051
2114
|
await handleIdentify(server, data, request, extra);
|
|
2052
2115
|
await applyResolvedMetadata$1(event, data, request, extra);
|
|
2053
|
-
|
|
2116
|
+
setEventIntent(event, await resolveToolCallIntent(data, request, extra));
|
|
2054
2117
|
const result = await executeToolCall(server, originalCallToolHandler, request, extra, event);
|
|
2055
2118
|
if (isToolResultError$1(result)) {
|
|
2056
2119
|
event.isError = true;
|
|
2057
2120
|
event.error = captureException(result);
|
|
2058
|
-
}
|
|
2121
|
+
} else event.isError = false;
|
|
2059
2122
|
event.response = result;
|
|
2123
|
+
event.duration = getEventDuration(event);
|
|
2060
2124
|
publishEvent(server, event);
|
|
2061
2125
|
return result;
|
|
2062
2126
|
} catch (error) {
|
|
2063
2127
|
event.isError = true;
|
|
2064
2128
|
event.error = captureException(error);
|
|
2129
|
+
event.duration = getEventDuration(event);
|
|
2065
2130
|
publishEvent(server, event);
|
|
2066
2131
|
throw error;
|
|
2067
2132
|
}
|
|
@@ -2069,7 +2134,7 @@ async function handleToolCallRequest(server, originalCallToolHandler, request, e
|
|
|
2069
2134
|
async function executeToolCall(server, originalCallToolHandler, request, extra, event) {
|
|
2070
2135
|
if (request.params?.name === "get_more_tools") {
|
|
2071
2136
|
const context = getContextArgument$1(request) || "";
|
|
2072
|
-
event
|
|
2137
|
+
setExplicitContextIntent(event, context);
|
|
2073
2138
|
return handleReportMissing({ context });
|
|
2074
2139
|
}
|
|
2075
2140
|
if (originalCallToolHandler) return await originalCallToolHandler(request, extra);
|
|
@@ -2085,11 +2150,6 @@ async function applyResolvedMetadata$1(event, data, request, extra) {
|
|
|
2085
2150
|
const resolvedProperties = await resolveEventProperties(data, request, extra);
|
|
2086
2151
|
if (resolvedProperties) event.properties = resolvedProperties;
|
|
2087
2152
|
}
|
|
2088
|
-
function setToolCallContext(event, context, request) {
|
|
2089
|
-
if (!(isContextEnabled(context) && request.params?.name !== "get_more_tools")) return;
|
|
2090
|
-
const contextArgument = getContextArgument$1(request);
|
|
2091
|
-
if (contextArgument) event.userIntent = contextArgument;
|
|
2092
|
-
}
|
|
2093
2153
|
function getContextArgument$1(request) {
|
|
2094
2154
|
const context = request.params?.arguments?.context;
|
|
2095
2155
|
return typeof context === "string" ? context : void 0;
|
|
@@ -2323,8 +2383,7 @@ async function initializeToolCallEvent(server, request, extra, startTime) {
|
|
|
2323
2383
|
await handleIdentify(server, data, request, extra);
|
|
2324
2384
|
event.sessionId = data.sessionId;
|
|
2325
2385
|
await applyResolvedMetadata(event, data, request, extra);
|
|
2326
|
-
|
|
2327
|
-
if (isContextEnabled(data.options.context) && contextArgument) event.userIntent = contextArgument;
|
|
2386
|
+
setEventIntent(event, await resolveToolCallIntent(data, request, extra));
|
|
2328
2387
|
return {
|
|
2329
2388
|
event,
|
|
2330
2389
|
shouldPublishEvent: true
|
|
@@ -2347,7 +2406,10 @@ async function executeReportMissingTool(server, request, tracing, startTime) {
|
|
|
2347
2406
|
try {
|
|
2348
2407
|
const context = getContextArgument(request) || "";
|
|
2349
2408
|
const result = await handleReportMissing({ context });
|
|
2350
|
-
publishSuccessfulToolEvent(server, tracing, result, startTime, {
|
|
2409
|
+
publishSuccessfulToolEvent(server, tracing, result, startTime, {
|
|
2410
|
+
userIntent: context,
|
|
2411
|
+
userIntentSource: "context_parameter"
|
|
2412
|
+
});
|
|
2351
2413
|
return result;
|
|
2352
2414
|
} catch (error) {
|
|
2353
2415
|
publishFailedToolEvent(server, tracing, error, startTime);
|
|
@@ -2375,12 +2437,15 @@ function getContextArgument(request) {
|
|
|
2375
2437
|
}
|
|
2376
2438
|
function publishSuccessfulToolEvent(server, tracing, result, startTime, options = {}) {
|
|
2377
2439
|
if (!(tracing.event && tracing.shouldPublishEvent)) return;
|
|
2378
|
-
if (options.userIntent)
|
|
2440
|
+
if (options.userIntent) {
|
|
2441
|
+
setExplicitContextIntent(tracing.event, options.userIntent);
|
|
2442
|
+
if (options.userIntentSource) tracing.event.userIntentSource = options.userIntentSource;
|
|
2443
|
+
}
|
|
2379
2444
|
if (isToolResultError(result)) {
|
|
2380
2445
|
tracing.event.isError = true;
|
|
2381
2446
|
tracing.event.error = captureException(options.capturedError || result);
|
|
2382
2447
|
options.clearCapturedError?.();
|
|
2383
|
-
}
|
|
2448
|
+
} else tracing.event.isError = false;
|
|
2384
2449
|
tracing.event.response = result;
|
|
2385
2450
|
tracing.event.duration = Date.now() - startTime.getTime();
|
|
2386
2451
|
publishEvent(server, tracing.event);
|
|
@@ -2417,6 +2482,7 @@ function setupTracking(server) {
|
|
|
2417
2482
|
* @param options.enableAITracing - Emits `$ai_span` events for tool calls so MCP activity appears in PostHog LLM analytics. Defaults to false.
|
|
2418
2483
|
* @param options.enableTracing - Enables tracking of tool calls and usage patterns.
|
|
2419
2484
|
* @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.
|
|
2485
|
+
* @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.
|
|
2420
2486
|
* @param options.identify - Async function to identify users and attach custom data to their sessions.
|
|
2421
2487
|
* @param options.redactSensitiveInformation - Function to redact sensitive data before sending to PostHog.
|
|
2422
2488
|
* @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`.
|
|
@@ -2544,6 +2610,7 @@ function buildTrackingData(lowLevelServer, options) {
|
|
|
2544
2610
|
enableAITracing: options.enableAITracing ?? false,
|
|
2545
2611
|
enableTracing: options.enableTracing ?? true,
|
|
2546
2612
|
context: options.context,
|
|
2613
|
+
intentFallback: options.intentFallback,
|
|
2547
2614
|
identify: options.identify,
|
|
2548
2615
|
redactSensitiveInformation: options.redactSensitiveInformation,
|
|
2549
2616
|
eventTags: options.eventTags,
|
|
@@ -2688,6 +2755,8 @@ function publishResolvedCustomEvent(target, event) {
|
|
|
2688
2755
|
eventQueue.add(event);
|
|
2689
2756
|
}
|
|
2690
2757
|
//#endregion
|
|
2758
|
+
exports.POSTHOG_MCP_ANALYTICS_SOURCE = POSTHOG_MCP_ANALYTICS_SOURCE;
|
|
2759
|
+
exports.PostHogMCPAnalyticsEvent = PostHogMCPAnalyticsEvent;
|
|
2691
2760
|
exports.PostHogMCPAnalyticsProperty = PostHogMCPAnalyticsProperty;
|
|
2692
2761
|
exports.publishCustomEvent = publishCustomEvent;
|
|
2693
2762
|
exports.track = track;
|