@posthog/mcp 0.4.2 → 0.4.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/extensions/instrument-highlevel.d.ts.map +1 -1
- package/dist/extensions/instrument-highlevel.js +11 -29
- package/dist/extensions/instrument-highlevel.mjs +13 -31
- package/dist/extensions/instrument-lowlevel.d.ts.map +1 -1
- package/dist/extensions/instrument-lowlevel.js +5 -2
- package/dist/extensions/instrument-lowlevel.mjs +6 -3
- package/dist/extensions/instrumentation.d.ts +31 -16
- package/dist/extensions/instrumentation.d.ts.map +1 -1
- package/dist/extensions/instrumentation.js +41 -48
- package/dist/extensions/instrumentation.mjs +33 -43
- package/dist/extensions/sink.d.ts.map +1 -1
- package/dist/extensions/sink.js +13 -7
- package/dist/extensions/sink.mjs +13 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +4 -4
- package/src/extensions/instrument-highlevel.ts +19 -46
- package/src/extensions/instrument-lowlevel.ts +12 -3
- package/src/extensions/instrumentation.ts +67 -79
- package/src/extensions/sink.ts +9 -0
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiC,sBAAsB,EAAiC,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiC,sBAAsB,EAAiC,MAAM,UAAU,CAAA;AAqPpH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAwB9E"}
|
|
@@ -63,7 +63,6 @@ function setupListenerToRegisteredTools(server) {
|
|
|
63
63
|
return Reflect.set(target, property, value);
|
|
64
64
|
}
|
|
65
65
|
const nextValue = addTracingToToolCallbackInternal(value, property, server);
|
|
66
|
-
(0, external_instrumentation_js_namespaceObject.instrumentToolsListHandler)(server.server);
|
|
67
66
|
if ('function' == typeof nextValue.update) {
|
|
68
67
|
const originalUpdate = nextValue.update;
|
|
69
68
|
nextValue.update = function(...updateArgs) {
|
|
@@ -151,32 +150,11 @@ function addTracingToToolCallbackInternal(tool, toolName, server) {
|
|
|
151
150
|
wrappedTool[MCP_ANALYTICS_PROCESSED] = true;
|
|
152
151
|
return wrappedTool;
|
|
153
152
|
}
|
|
154
|
-
function
|
|
155
|
-
const lowLevelServer = server.server;
|
|
156
|
-
const existingHandler = lowLevelServer._requestHandlers.get('tools/call');
|
|
157
|
-
if (existingHandler) {
|
|
158
|
-
const wrappedHandler = createToolsCallWrapper(existingHandler, lowLevelServer);
|
|
159
|
-
lowLevelServer._requestHandlers.set('tools/call', wrappedHandler);
|
|
160
|
-
}
|
|
161
|
-
const originalSetRequestHandler = lowLevelServer.setRequestHandler.bind(lowLevelServer);
|
|
162
|
-
lowLevelServer.setRequestHandler = (requestSchema, handler)=>{
|
|
163
|
-
const shape = (0, external_mcp_sdk_compat_js_namespaceObject.getObjectShape)(requestSchema);
|
|
164
|
-
const method = shape?.method ? (0, external_mcp_sdk_compat_js_namespaceObject.getLiteralValue)(shape.method) : void 0;
|
|
165
|
-
if ('tools/call' === method) {
|
|
166
|
-
const wrappedHandler = createToolsCallWrapper(handler, lowLevelServer);
|
|
167
|
-
return originalSetRequestHandler(requestSchema, wrappedHandler);
|
|
168
|
-
}
|
|
169
|
-
return originalSetRequestHandler(requestSchema, handler);
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
function createToolsCallWrapper(originalHandler, server) {
|
|
173
|
-
return async (request, extra)=>await handleWrappedToolsCall(originalHandler, server, request, extra);
|
|
174
|
-
}
|
|
175
|
-
async function handleWrappedToolsCall(originalHandler, server, request, extra) {
|
|
153
|
+
async function handleToolCallRequest(server, originalCallToolHandler, request, extra) {
|
|
176
154
|
const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
|
|
177
155
|
if (!data) {
|
|
178
156
|
(0, external_logger_js_namespaceObject.log)('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.');
|
|
179
|
-
return await
|
|
157
|
+
return await originalCallToolHandler(request, extra);
|
|
180
158
|
}
|
|
181
159
|
if (request.params?.name === (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options)) {
|
|
182
160
|
const context = (0, external_tracing_helpers_js_namespaceObject.getContextArgument)(request) || '';
|
|
@@ -197,7 +175,7 @@ async function handleWrappedToolsCall(originalHandler, server, request, extra) {
|
|
|
197
175
|
data,
|
|
198
176
|
request,
|
|
199
177
|
extra,
|
|
200
|
-
execute: ()=>
|
|
178
|
+
execute: ()=>originalCallToolHandler(request, extra),
|
|
201
179
|
takeCapturedError: ()=>{
|
|
202
180
|
const captured = extra?.__mcp_analytics_error;
|
|
203
181
|
if (extra) extra.__mcp_analytics_error = void 0;
|
|
@@ -207,15 +185,19 @@ async function handleWrappedToolsCall(originalHandler, server, request, extra) {
|
|
|
207
185
|
}
|
|
208
186
|
function instrumentHighLevelServer(server) {
|
|
209
187
|
try {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
188
|
+
const lowLevelServer = server.server;
|
|
189
|
+
const mcpAnalyticsData = (0, external_internal_js_namespaceObject.getServerTrackingData)(lowLevelServer);
|
|
190
|
+
const handlers = {
|
|
191
|
+
initialize: external_instrumentation_js_namespaceObject.handleInitializeRequest,
|
|
192
|
+
'tools/list': external_instrumentation_js_namespaceObject.handleListToolsRequest,
|
|
193
|
+
'tools/call': handleToolCallRequest
|
|
194
|
+
};
|
|
195
|
+
(0, external_instrumentation_js_namespaceObject.patchRequestHandlers)(lowLevelServer, handlers);
|
|
213
196
|
server._registeredTools = addTracingToToolRegistry(server._registeredTools, server);
|
|
214
197
|
if (mcpAnalyticsData) {
|
|
215
198
|
seedToolDescriptionsFromRegistry(mcpAnalyticsData.toolDescriptions, server._registeredTools);
|
|
216
199
|
seedToolCategoriesFromRegistry(mcpAnalyticsData.toolCategories, server._registeredTools);
|
|
217
200
|
}
|
|
218
|
-
(0, external_instrumentation_js_namespaceObject.instrumentToolsListHandler)(server.server);
|
|
219
201
|
setupListenerToRegisteredTools(server);
|
|
220
202
|
} catch (error) {
|
|
221
203
|
(0, external_logger_js_namespaceObject.log)(`Warning: Failed to setup tool call instrumentation - ${error}`);
|
|
@@ -2,9 +2,9 @@ import { stripConversationId } from "./conversation-id.mjs";
|
|
|
2
2
|
import { MCPAnalyticsEventType } from "./event-types.mjs";
|
|
3
3
|
import { getServerTrackingData } from "./internal.mjs";
|
|
4
4
|
import { log } from "./logger.mjs";
|
|
5
|
-
import { createWrappedTool,
|
|
5
|
+
import { createWrappedTool, getToolFunction, hasToolFunction } from "./mcp-sdk-compat.mjs";
|
|
6
6
|
import { handleReportMissing, resolveMissingCapabilityToolName } from "./tools.mjs";
|
|
7
|
-
import { captureToolCall,
|
|
7
|
+
import { captureToolCall, handleInitializeRequest, handleListToolsRequest, patchRequestHandlers, readToolMetaCategory } from "./instrumentation.mjs";
|
|
8
8
|
import { getContextArgument } from "./tracing-helpers.mjs";
|
|
9
9
|
const wrappedCallbacks = new WeakMap();
|
|
10
10
|
const MCP_ANALYTICS_PROCESSED = Symbol('__posthog_mcp_analytics_processed__');
|
|
@@ -35,7 +35,6 @@ function setupListenerToRegisteredTools(server) {
|
|
|
35
35
|
return Reflect.set(target, property, value);
|
|
36
36
|
}
|
|
37
37
|
const nextValue = addTracingToToolCallbackInternal(value, property, server);
|
|
38
|
-
instrumentToolsListHandler(server.server);
|
|
39
38
|
if ('function' == typeof nextValue.update) {
|
|
40
39
|
const originalUpdate = nextValue.update;
|
|
41
40
|
nextValue.update = function(...updateArgs) {
|
|
@@ -123,32 +122,11 @@ function addTracingToToolCallbackInternal(tool, toolName, server) {
|
|
|
123
122
|
wrappedTool[MCP_ANALYTICS_PROCESSED] = true;
|
|
124
123
|
return wrappedTool;
|
|
125
124
|
}
|
|
126
|
-
function
|
|
127
|
-
const lowLevelServer = server.server;
|
|
128
|
-
const existingHandler = lowLevelServer._requestHandlers.get('tools/call');
|
|
129
|
-
if (existingHandler) {
|
|
130
|
-
const wrappedHandler = createToolsCallWrapper(existingHandler, lowLevelServer);
|
|
131
|
-
lowLevelServer._requestHandlers.set('tools/call', wrappedHandler);
|
|
132
|
-
}
|
|
133
|
-
const originalSetRequestHandler = lowLevelServer.setRequestHandler.bind(lowLevelServer);
|
|
134
|
-
lowLevelServer.setRequestHandler = (requestSchema, handler)=>{
|
|
135
|
-
const shape = getObjectShape(requestSchema);
|
|
136
|
-
const method = shape?.method ? getLiteralValue(shape.method) : void 0;
|
|
137
|
-
if ('tools/call' === method) {
|
|
138
|
-
const wrappedHandler = createToolsCallWrapper(handler, lowLevelServer);
|
|
139
|
-
return originalSetRequestHandler(requestSchema, wrappedHandler);
|
|
140
|
-
}
|
|
141
|
-
return originalSetRequestHandler(requestSchema, handler);
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
function createToolsCallWrapper(originalHandler, server) {
|
|
145
|
-
return async (request, extra)=>await handleWrappedToolsCall(originalHandler, server, request, extra);
|
|
146
|
-
}
|
|
147
|
-
async function handleWrappedToolsCall(originalHandler, server, request, extra) {
|
|
125
|
+
async function handleToolCallRequest(server, originalCallToolHandler, request, extra) {
|
|
148
126
|
const data = getServerTrackingData(server);
|
|
149
127
|
if (!data) {
|
|
150
128
|
log('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.');
|
|
151
|
-
return await
|
|
129
|
+
return await originalCallToolHandler(request, extra);
|
|
152
130
|
}
|
|
153
131
|
if (request.params?.name === resolveMissingCapabilityToolName(data.options)) {
|
|
154
132
|
const context = getContextArgument(request) || '';
|
|
@@ -169,7 +147,7 @@ async function handleWrappedToolsCall(originalHandler, server, request, extra) {
|
|
|
169
147
|
data,
|
|
170
148
|
request,
|
|
171
149
|
extra,
|
|
172
|
-
execute: ()=>
|
|
150
|
+
execute: ()=>originalCallToolHandler(request, extra),
|
|
173
151
|
takeCapturedError: ()=>{
|
|
174
152
|
const captured = extra?.__mcp_analytics_error;
|
|
175
153
|
if (extra) extra.__mcp_analytics_error = void 0;
|
|
@@ -179,15 +157,19 @@ async function handleWrappedToolsCall(originalHandler, server, request, extra) {
|
|
|
179
157
|
}
|
|
180
158
|
function instrumentHighLevelServer(server) {
|
|
181
159
|
try {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
160
|
+
const lowLevelServer = server.server;
|
|
161
|
+
const mcpAnalyticsData = getServerTrackingData(lowLevelServer);
|
|
162
|
+
const handlers = {
|
|
163
|
+
initialize: handleInitializeRequest,
|
|
164
|
+
'tools/list': handleListToolsRequest,
|
|
165
|
+
'tools/call': handleToolCallRequest
|
|
166
|
+
};
|
|
167
|
+
patchRequestHandlers(lowLevelServer, handlers);
|
|
185
168
|
server._registeredTools = addTracingToToolRegistry(server._registeredTools, server);
|
|
186
169
|
if (mcpAnalyticsData) {
|
|
187
170
|
seedToolDescriptionsFromRegistry(mcpAnalyticsData.toolDescriptions, server._registeredTools);
|
|
188
171
|
seedToolCategoriesFromRegistry(mcpAnalyticsData.toolCategories, server._registeredTools);
|
|
189
172
|
}
|
|
190
|
-
instrumentToolsListHandler(server.server);
|
|
191
173
|
setupListenerToRegisteredTools(server);
|
|
192
174
|
} catch (error) {
|
|
193
175
|
log(`Warning: Failed to setup tool call instrumentation - ${error}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-lowlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-lowlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiD,aAAa,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"instrument-lowlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-lowlevel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiD,aAAa,EAAE,MAAM,UAAU,CAAA;AAmB5F;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAkBpE"}
|
|
@@ -35,8 +35,11 @@ const external_instrumentation_js_namespaceObject = require("./instrumentation.j
|
|
|
35
35
|
const external_tracing_helpers_js_namespaceObject = require("./tracing-helpers.js");
|
|
36
36
|
function instrumentLowLevelServer(server) {
|
|
37
37
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const handlers = {
|
|
39
|
+
initialize: external_instrumentation_js_namespaceObject.handleInitializeRequest,
|
|
40
|
+
'tools/list': external_instrumentation_js_namespaceObject.handleListToolsRequest
|
|
41
|
+
};
|
|
42
|
+
(0, external_instrumentation_js_namespaceObject.patchRequestHandlers)(server, handlers);
|
|
40
43
|
const originalCallToolHandler = server._requestHandlers.get('tools/call');
|
|
41
44
|
server.setRequestHandler(types_js_namespaceObject.CallToolRequestSchema, async (request, extra)=>await handleToolCallRequest(server, originalCallToolHandler, request, extra));
|
|
42
45
|
} catch (error) {
|
|
@@ -3,12 +3,15 @@ import { MCPAnalyticsEventType } from "./event-types.mjs";
|
|
|
3
3
|
import { getServerTrackingData } from "./internal.mjs";
|
|
4
4
|
import { log } from "./logger.mjs";
|
|
5
5
|
import { handleReportMissing, resolveMissingCapabilityToolName } from "./tools.mjs";
|
|
6
|
-
import { captureToolCall,
|
|
6
|
+
import { captureToolCall, handleInitializeRequest, handleListToolsRequest, patchRequestHandlers } from "./instrumentation.mjs";
|
|
7
7
|
import { getContextArgument } from "./tracing-helpers.mjs";
|
|
8
8
|
function instrumentLowLevelServer(server) {
|
|
9
9
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const handlers = {
|
|
11
|
+
initialize: handleInitializeRequest,
|
|
12
|
+
'tools/list': handleListToolsRequest
|
|
13
|
+
};
|
|
14
|
+
patchRequestHandlers(server, handlers);
|
|
12
15
|
const originalCallToolHandler = server._requestHandlers.get('tools/call');
|
|
13
16
|
server.setRequestHandler(CallToolRequestSchema, async (request, extra)=>await handleToolCallRequest(server, originalCallToolHandler, request, extra));
|
|
14
17
|
} catch (error) {
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import type { CompatibleRequestHandlerExtra, MCPAnalyticsData, MCPRequestLike, MCPServerLike } from '../types';
|
|
3
3
|
import { MCPAnalyticsEventType } from './event-types';
|
|
4
|
+
/**
|
|
5
|
+
* Single instrumentation core shared by the low-level (`Server`) and high-level
|
|
6
|
+
* (`McpServer`) wrappers. The two entrypoints differ only in how they reach the
|
|
7
|
+
* underlying tool — they both funnel the tool-call lifecycle through
|
|
8
|
+
* {@link captureToolCall}, so error handling, conversation-id minting, session
|
|
9
|
+
* attribution, and event capture are defined exactly once.
|
|
10
|
+
*/
|
|
11
|
+
type MCPRequestHandler = (request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra) => Promise<unknown>;
|
|
4
12
|
/**
|
|
5
13
|
* Runs the underlying tool. Receives the request with the SDK-injected
|
|
6
14
|
* `conversation_id` stripped; an adapter is free to ignore it (the high-level
|
|
@@ -43,19 +51,26 @@ interface TraceToolCallParams {
|
|
|
43
51
|
*/
|
|
44
52
|
export declare function captureToolCall(params: TraceToolCallParams): Promise<unknown>;
|
|
45
53
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
* A method's patch: runs the original handler and captures analytics. `server`
|
|
55
|
+
* and `originalHandler` are bound by {@link patchRequestHandlers}; the SDK
|
|
56
|
+
* supplies `request` and `extra` per call.
|
|
57
|
+
*/
|
|
58
|
+
export type HandlerPatch = (server: MCPServerLike, originalHandler: MCPRequestHandler, request: MCPRequestLike, extra: CompatibleRequestHandlerExtra | undefined) => Promise<unknown>;
|
|
59
|
+
/**
|
|
60
|
+
* Applies the `patches` (keyed by method, e.g. `initialize`, `tools/list`) to the
|
|
61
|
+
* handlers already registered, and patches `setRequestHandler` so matching
|
|
62
|
+
* handlers registered later are patched too. The latter is what makes adapters
|
|
63
|
+
* that register handlers post-construction work — e.g. `@rekog/mcp-nest` hands a
|
|
64
|
+
* bare server to instrument() and only then registers its handlers.
|
|
65
|
+
*/
|
|
66
|
+
export declare function patchRequestHandlers(server: MCPServerLike, patches: Record<string, HandlerPatch>): void;
|
|
67
|
+
/**
|
|
68
|
+
* Captures each `tools/list` and injects the SDK-managed tools (context
|
|
69
|
+
* parameter, conversation id, `get_more_tools`) into the returned list.
|
|
57
70
|
*/
|
|
58
|
-
export declare function
|
|
71
|
+
export declare function handleListToolsRequest(server: MCPServerLike, originalListToolsHandler: MCPRequestHandler, request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra): Promise<{
|
|
72
|
+
tools: ListToolsResult['tools'];
|
|
73
|
+
}>;
|
|
59
74
|
export declare function cacheToolDescriptions(cache: Map<string, string>, tools: ListToolsResult['tools'] | undefined): void;
|
|
60
75
|
/**
|
|
61
76
|
* Category declared on a tool's `_meta` block (the MCP spec allows arbitrary
|
|
@@ -65,9 +80,9 @@ export declare function cacheToolDescriptions(cache: Map<string, string>, tools:
|
|
|
65
80
|
export declare function readToolMetaCategory(meta: unknown): string | undefined;
|
|
66
81
|
export declare function cacheToolCategories(cache: Map<string, string>, tools: ListToolsResult['tools'] | undefined): void;
|
|
67
82
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
83
|
+
* Captures the connection handshake (and resolves identity) on `initialize`
|
|
84
|
+
* before the original handler runs.
|
|
70
85
|
*/
|
|
71
|
-
export declare function
|
|
86
|
+
export declare function handleInitializeRequest(server: MCPServerLike, originalInitializeHandler: MCPRequestHandler, request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra): Promise<unknown>;
|
|
72
87
|
export {};
|
|
73
88
|
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,KAAK,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAY,MAAM,UAAU,CAAA;AAWxH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAWrD;;;;;;GAMG;AAEH,KAAK,iBAAiB,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,6BAA6B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7G;;;;GAIG;AACH,KAAK,YAAY,GAAG,CAAC,iBAAiB,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE3E,UAAU,mBAAmB;IAC3B,MAAM,EAAE,aAAa,CAAA;IACrB,IAAI,EAAE,gBAAgB,CAAA;IACtB,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,CAAC,EAAE,6BAA6B,CAAA;IACrC,OAAO,EAAE,YAAY,CAAA;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,qBAAqB,CAAA;IACjC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAA;CAClC;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAuCnF;AAgHD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,MAAM,EAAE,aAAa,EACrB,eAAe,EAAE,iBAAiB,EAClC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,6BAA6B,GAAG,SAAS,KAC7C,OAAO,CAAC,OAAO,CAAC,CAAA;AAErB;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,IAAI,CAqBvG;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,aAAa,EACrB,wBAAwB,EAAE,iBAAiB,EAC3C,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC;IAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAwC9C;AAwDD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CASnH;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGtE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAUjH;AAID;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,aAAa,EACrB,yBAAyB,EAAE,iBAAiB,EAC5C,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,OAAO,CAAC,CA0BlB"}
|
|
@@ -27,11 +27,11 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
27
27
|
readToolMetaCategory: ()=>readToolMetaCategory,
|
|
28
28
|
cacheToolDescriptions: ()=>cacheToolDescriptions,
|
|
29
29
|
cacheToolCategories: ()=>cacheToolCategories,
|
|
30
|
+
handleInitializeRequest: ()=>handleInitializeRequest,
|
|
30
31
|
captureToolCall: ()=>captureToolCall,
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
handleListToolsRequest: ()=>handleListToolsRequest,
|
|
33
|
+
patchRequestHandlers: ()=>patchRequestHandlers
|
|
33
34
|
});
|
|
34
|
-
const types_js_namespaceObject = require("@modelcontextprotocol/sdk/types.js");
|
|
35
35
|
const external_context_parameters_js_namespaceObject = require("./context-parameters.js");
|
|
36
36
|
const external_conversation_id_js_namespaceObject = require("./conversation-id.js");
|
|
37
37
|
const external_capture_js_namespaceObject = require("./capture.js");
|
|
@@ -119,24 +119,19 @@ function publishFailedToolEvent(server, event, error, startTime, conversation) {
|
|
|
119
119
|
(0, external_logger_js_namespaceObject.log)(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
listToolsTracingSetup.set(server, true);
|
|
127
|
-
try {
|
|
128
|
-
const existingHandler = server._requestHandlers.get('tools/list');
|
|
129
|
-
if (existingHandler) server._requestHandlers.set('tools/list', (request, extra)=>handleListToolsRequest(server, existingHandler, request, extra));
|
|
130
|
-
const originalSetRequestHandler = server.setRequestHandler.bind(server);
|
|
131
|
-
server.setRequestHandler = (requestSchema, handler)=>{
|
|
132
|
-
const shape = (0, external_mcp_sdk_compat_js_namespaceObject.getObjectShape)(requestSchema);
|
|
133
|
-
const method = shape?.method ? (0, external_mcp_sdk_compat_js_namespaceObject.getLiteralValue)(shape.method) : void 0;
|
|
134
|
-
if ('tools/list' === method) return originalSetRequestHandler(requestSchema, (request, extra)=>handleListToolsRequest(server, handler, request, extra));
|
|
135
|
-
return originalSetRequestHandler(requestSchema, handler);
|
|
136
|
-
};
|
|
137
|
-
} catch (error) {
|
|
138
|
-
(0, external_logger_js_namespaceObject.log)(`Warning: Failed to override list tools handler - ${error}`);
|
|
122
|
+
function patchRequestHandlers(server, patches) {
|
|
123
|
+
for (const [handlerName, patch] of Object.entries(patches)){
|
|
124
|
+
const originalHandler = server._requestHandlers.get(handlerName);
|
|
125
|
+
if (originalHandler) server._requestHandlers.set(handlerName, (request, extra)=>patch(server, originalHandler, request, extra));
|
|
139
126
|
}
|
|
127
|
+
const originalSetRequestHandler = server.setRequestHandler.bind(server);
|
|
128
|
+
server.setRequestHandler = (requestSchema, originalHandler)=>{
|
|
129
|
+
const shape = (0, external_mcp_sdk_compat_js_namespaceObject.getObjectShape)(requestSchema);
|
|
130
|
+
const handlerName = shape?.method ? (0, external_mcp_sdk_compat_js_namespaceObject.getLiteralValue)(shape.method) : void 0;
|
|
131
|
+
const patch = 'string' == typeof handlerName ? patches[handlerName] : void 0;
|
|
132
|
+
if (!patch) return originalSetRequestHandler(requestSchema, originalHandler);
|
|
133
|
+
return originalSetRequestHandler(requestSchema, (request, extra)=>patch(server, originalHandler, request, extra));
|
|
134
|
+
};
|
|
140
135
|
}
|
|
141
136
|
async function handleListToolsRequest(server, originalListToolsHandler, request, extra) {
|
|
142
137
|
const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
|
|
@@ -222,43 +217,41 @@ function cacheToolCategories(cache, tools) {
|
|
|
222
217
|
if (category) cache.set(tool.name, category);
|
|
223
218
|
}
|
|
224
219
|
}
|
|
225
|
-
function
|
|
226
|
-
const
|
|
227
|
-
if (!
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
event.response = result;
|
|
246
|
-
(0, external_capture_js_namespaceObject.captureEvent)(server, event);
|
|
247
|
-
return result;
|
|
248
|
-
});
|
|
220
|
+
async function handleInitializeRequest(server, originalInitializeHandler, request, extra) {
|
|
221
|
+
const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
|
|
222
|
+
if (!data) {
|
|
223
|
+
(0, external_logger_js_namespaceObject.log)('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.');
|
|
224
|
+
return await originalInitializeHandler(request, extra);
|
|
225
|
+
}
|
|
226
|
+
const sessionId = (0, external_session_js_namespaceObject.getServerSessionId)(server, extra);
|
|
227
|
+
await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra);
|
|
228
|
+
const event = {
|
|
229
|
+
sessionId,
|
|
230
|
+
resourceName: request.params?.name || 'Unknown Tool Name',
|
|
231
|
+
eventType: external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpInitialize,
|
|
232
|
+
parameters: (0, external_mcp_payloads_js_namespaceObject.buildCapturedMcpParameters)(request),
|
|
233
|
+
timestamp: new Date()
|
|
234
|
+
};
|
|
235
|
+
await (0, external_tracing_helpers_js_namespaceObject.applyResolvedMetadata)(event, data, request, extra);
|
|
236
|
+
const result = await originalInitializeHandler(request, extra);
|
|
237
|
+
event.response = result;
|
|
238
|
+
(0, external_capture_js_namespaceObject.captureEvent)(server, event);
|
|
239
|
+
return result;
|
|
249
240
|
}
|
|
250
241
|
exports.cacheToolCategories = __webpack_exports__.cacheToolCategories;
|
|
251
242
|
exports.cacheToolDescriptions = __webpack_exports__.cacheToolDescriptions;
|
|
252
243
|
exports.captureToolCall = __webpack_exports__.captureToolCall;
|
|
253
|
-
exports.
|
|
254
|
-
exports.
|
|
244
|
+
exports.handleInitializeRequest = __webpack_exports__.handleInitializeRequest;
|
|
245
|
+
exports.handleListToolsRequest = __webpack_exports__.handleListToolsRequest;
|
|
246
|
+
exports.patchRequestHandlers = __webpack_exports__.patchRequestHandlers;
|
|
255
247
|
exports.readToolMetaCategory = __webpack_exports__.readToolMetaCategory;
|
|
256
248
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
257
249
|
"cacheToolCategories",
|
|
258
250
|
"cacheToolDescriptions",
|
|
259
251
|
"captureToolCall",
|
|
260
|
-
"
|
|
261
|
-
"
|
|
252
|
+
"handleInitializeRequest",
|
|
253
|
+
"handleListToolsRequest",
|
|
254
|
+
"patchRequestHandlers",
|
|
262
255
|
"readToolMetaCategory"
|
|
263
256
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
264
257
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { InitializeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
2
1
|
import { addContextParameterToTools, getContextDescription, isContextEnabled } from "./context-parameters.mjs";
|
|
3
2
|
import { addConversationIdToTools, canInjectConversationIdPromptBack, cloneRequestWithoutConversationId, injectConversationIdPromptBack, resolveConversationId } from "./conversation-id.mjs";
|
|
4
3
|
import { captureEvent } from "./capture.mjs";
|
|
@@ -86,24 +85,19 @@ function publishFailedToolEvent(server, event, error, startTime, conversation) {
|
|
|
86
85
|
log(`Warning: PostHog MCP analytics failed to publish failed tool event - ${publishError}`);
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
listToolsTracingSetup.set(server, true);
|
|
94
|
-
try {
|
|
95
|
-
const existingHandler = server._requestHandlers.get('tools/list');
|
|
96
|
-
if (existingHandler) server._requestHandlers.set('tools/list', (request, extra)=>handleListToolsRequest(server, existingHandler, request, extra));
|
|
97
|
-
const originalSetRequestHandler = server.setRequestHandler.bind(server);
|
|
98
|
-
server.setRequestHandler = (requestSchema, handler)=>{
|
|
99
|
-
const shape = getObjectShape(requestSchema);
|
|
100
|
-
const method = shape?.method ? getLiteralValue(shape.method) : void 0;
|
|
101
|
-
if ('tools/list' === method) return originalSetRequestHandler(requestSchema, (request, extra)=>handleListToolsRequest(server, handler, request, extra));
|
|
102
|
-
return originalSetRequestHandler(requestSchema, handler);
|
|
103
|
-
};
|
|
104
|
-
} catch (error) {
|
|
105
|
-
log(`Warning: Failed to override list tools handler - ${error}`);
|
|
88
|
+
function patchRequestHandlers(server, patches) {
|
|
89
|
+
for (const [handlerName, patch] of Object.entries(patches)){
|
|
90
|
+
const originalHandler = server._requestHandlers.get(handlerName);
|
|
91
|
+
if (originalHandler) server._requestHandlers.set(handlerName, (request, extra)=>patch(server, originalHandler, request, extra));
|
|
106
92
|
}
|
|
93
|
+
const originalSetRequestHandler = server.setRequestHandler.bind(server);
|
|
94
|
+
server.setRequestHandler = (requestSchema, originalHandler)=>{
|
|
95
|
+
const shape = getObjectShape(requestSchema);
|
|
96
|
+
const handlerName = shape?.method ? getLiteralValue(shape.method) : void 0;
|
|
97
|
+
const patch = 'string' == typeof handlerName ? patches[handlerName] : void 0;
|
|
98
|
+
if (!patch) return originalSetRequestHandler(requestSchema, originalHandler);
|
|
99
|
+
return originalSetRequestHandler(requestSchema, (request, extra)=>patch(server, originalHandler, request, extra));
|
|
100
|
+
};
|
|
107
101
|
}
|
|
108
102
|
async function handleListToolsRequest(server, originalListToolsHandler, request, extra) {
|
|
109
103
|
const data = getServerTrackingData(server);
|
|
@@ -189,29 +183,25 @@ function cacheToolCategories(cache, tools) {
|
|
|
189
183
|
if (category) cache.set(tool.name, category);
|
|
190
184
|
}
|
|
191
185
|
}
|
|
192
|
-
function
|
|
193
|
-
const
|
|
194
|
-
if (!
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
event.response = result;
|
|
213
|
-
captureEvent(server, event);
|
|
214
|
-
return result;
|
|
215
|
-
});
|
|
186
|
+
async function handleInitializeRequest(server, originalInitializeHandler, request, extra) {
|
|
187
|
+
const data = getServerTrackingData(server);
|
|
188
|
+
if (!data) {
|
|
189
|
+
log('Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.');
|
|
190
|
+
return await originalInitializeHandler(request, extra);
|
|
191
|
+
}
|
|
192
|
+
const sessionId = getServerSessionId(server, extra);
|
|
193
|
+
await handleIdentify(server, data, sessionId, request, extra);
|
|
194
|
+
const event = {
|
|
195
|
+
sessionId,
|
|
196
|
+
resourceName: request.params?.name || 'Unknown Tool Name',
|
|
197
|
+
eventType: MCPAnalyticsEventType.mcpInitialize,
|
|
198
|
+
parameters: buildCapturedMcpParameters(request),
|
|
199
|
+
timestamp: new Date()
|
|
200
|
+
};
|
|
201
|
+
await applyResolvedMetadata(event, data, request, extra);
|
|
202
|
+
const result = await originalInitializeHandler(request, extra);
|
|
203
|
+
event.response = result;
|
|
204
|
+
captureEvent(server, event);
|
|
205
|
+
return result;
|
|
216
206
|
}
|
|
217
|
-
export { cacheToolCategories, cacheToolDescriptions, captureToolCall,
|
|
207
|
+
export { cacheToolCategories, cacheToolDescriptions, captureToolCall, handleInitializeRequest, handleListToolsRequest, patchRequestHandlers, readToolMetaCategory };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../src/extensions/sink.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE7D,OAAO,EAAE,KAAK,mBAAmB,EAA6B,MAAM,kBAAkB,CAAA;AAKtF,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,0BAA0B,EAAE,OAAO,CAAA;IACnC,kFAAkF;IAClF,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CA2BnE;AA4BD;;;;;;;;GAQG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,OAAO;IAE7C;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../src/extensions/sink.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE7D,OAAO,EAAE,KAAK,mBAAmB,EAA6B,MAAM,kBAAkB,CAAA;AAKtF,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,0BAA0B,EAAE,OAAO,CAAA;IACnC,kFAAkF;IAClF,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CA2BnE;AA4BD;;;;;;;;GAQG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,OAAO;IAE7C;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CAmC1E"}
|
package/dist/extensions/sink.js
CHANGED
|
@@ -78,13 +78,19 @@ class McpEventSink {
|
|
|
78
78
|
if (!result) return;
|
|
79
79
|
const { event: fullEvent, captures } = result;
|
|
80
80
|
try {
|
|
81
|
-
for (const captureEvent of captures)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
for (const captureEvent of captures){
|
|
82
|
+
const groups = captureEvent.properties.$groups;
|
|
83
|
+
this.posthog.capture({
|
|
84
|
+
distinctId: captureEvent.distinct_id,
|
|
85
|
+
event: captureEvent.event,
|
|
86
|
+
properties: captureEvent.properties,
|
|
87
|
+
...groups ? {
|
|
88
|
+
groups
|
|
89
|
+
} : {},
|
|
90
|
+
timestamp: new Date(captureEvent.timestamp),
|
|
91
|
+
uuid: (0, core_namespaceObject.uuidv7)()
|
|
92
|
+
});
|
|
93
|
+
}
|
|
88
94
|
(0, external_logger_js_namespaceObject.log)(`Captured PostHog event ${fullEvent.id} | ${fullEvent.eventType} | ${fullEvent.duration} ms | ${fullEvent.identifyActorGivenId || 'anonymous'}`);
|
|
89
95
|
} catch (err) {
|
|
90
96
|
(0, external_logger_js_namespaceObject.log)(`Failed to capture PostHog event ${fullEvent.id}: ${err}`);
|
package/dist/extensions/sink.mjs
CHANGED
|
@@ -49,13 +49,19 @@ class McpEventSink {
|
|
|
49
49
|
if (!result) return;
|
|
50
50
|
const { event: fullEvent, captures } = result;
|
|
51
51
|
try {
|
|
52
|
-
for (const captureEvent of captures)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
for (const captureEvent of captures){
|
|
53
|
+
const groups = captureEvent.properties.$groups;
|
|
54
|
+
this.posthog.capture({
|
|
55
|
+
distinctId: captureEvent.distinct_id,
|
|
56
|
+
event: captureEvent.event,
|
|
57
|
+
properties: captureEvent.properties,
|
|
58
|
+
...groups ? {
|
|
59
|
+
groups
|
|
60
|
+
} : {},
|
|
61
|
+
timestamp: new Date(captureEvent.timestamp),
|
|
62
|
+
uuid: uuidv7()
|
|
63
|
+
});
|
|
64
|
+
}
|
|
59
65
|
log(`Captured PostHog event ${fullEvent.id} | ${fullEvent.eventType} | ${fullEvent.duration} ms | ${fullEvent.identifyActorGivenId || 'anonymous'}`);
|
|
60
66
|
} catch (err) {
|
|
61
67
|
log(`Failed to capture PostHog event ${fullEvent.id}: ${err}`);
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "0.4.
|
|
1
|
+
export declare const version = "0.4.4";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -26,7 +26,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
version: ()=>version
|
|
28
28
|
});
|
|
29
|
-
const version = '0.4.
|
|
29
|
+
const version = '0.4.4';
|
|
30
30
|
exports.version = __webpack_exports__.version;
|
|
31
31
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
32
32
|
"version"
|
package/dist/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const version = '0.4.
|
|
1
|
+
const version = '0.4.4';
|
|
2
2
|
export { version };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"bugs": {
|
|
5
5
|
"url": "https://github.com/PostHog/posthog-js/issues"
|
|
6
6
|
},
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"module": "dist/index.mjs",
|
|
29
29
|
"types": "dist/index.d.ts",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@posthog/core": "^1.
|
|
31
|
+
"@posthog/core": "^1.38.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@babel/preset-env": "^7.27.1",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"@types/node": "^20.0.0",
|
|
40
40
|
"jest": "29.7.0",
|
|
41
41
|
"zod": "^3.25.0",
|
|
42
|
-
"
|
|
43
|
-
"posthog-
|
|
42
|
+
"posthog-node": "^5.38.6",
|
|
43
|
+
"@posthog-tooling/tsconfig-base": "1.1.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@modelcontextprotocol/sdk": ">=1.26.0",
|
|
@@ -8,11 +8,12 @@ import { stripConversationId } from './conversation-id'
|
|
|
8
8
|
import { MCPAnalyticsEventType } from './event-types'
|
|
9
9
|
import { getServerTrackingData } from './internal'
|
|
10
10
|
import { log } from './logger'
|
|
11
|
-
import { createWrappedTool,
|
|
11
|
+
import { createWrappedTool, getToolFunction, hasToolFunction } from './mcp-sdk-compat'
|
|
12
12
|
import { handleReportMissing, resolveMissingCapabilityToolName } from './tools'
|
|
13
13
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
handleInitializeRequest,
|
|
15
|
+
handleListToolsRequest,
|
|
16
|
+
patchRequestHandlers,
|
|
16
17
|
captureToolCall,
|
|
17
18
|
readToolMetaCategory,
|
|
18
19
|
} from './instrumentation'
|
|
@@ -72,8 +73,6 @@ function setupListenerToRegisteredTools(server: HighLevelMCPServerLike): void {
|
|
|
72
73
|
|
|
73
74
|
const nextValue = addTracingToToolCallbackInternal(value, property, server)
|
|
74
75
|
|
|
75
|
-
instrumentToolsListHandler(server.server as MCPServerLike)
|
|
76
|
-
|
|
77
76
|
if (typeof nextValue.update === 'function') {
|
|
78
77
|
const originalUpdate = nextValue.update
|
|
79
78
|
nextValue.update = function (...updateArgs: unknown[]) {
|
|
@@ -130,7 +129,7 @@ function setupListenerToRegisteredTools(server: HighLevelMCPServerLike): void {
|
|
|
130
129
|
* (the high-level SDK turns thrown errors into `isError` results otherwise).
|
|
131
130
|
*
|
|
132
131
|
* This is purely the tool-facing concern; event capture lives in
|
|
133
|
-
* {@link captureToolCall} via {@link
|
|
132
|
+
* {@link captureToolCall} via {@link handleToolCallRequest}.
|
|
134
133
|
*/
|
|
135
134
|
function addTracingToToolCallbackInternal(
|
|
136
135
|
tool: RegisteredTool,
|
|
@@ -202,38 +201,9 @@ function addTracingToToolCallbackInternal(
|
|
|
202
201
|
return wrappedTool
|
|
203
202
|
}
|
|
204
203
|
|
|
205
|
-
function
|
|
206
|
-
const lowLevelServer = server.server as MCPServerLike
|
|
207
|
-
|
|
208
|
-
const existingHandler = lowLevelServer._requestHandlers.get('tools/call')
|
|
209
|
-
if (existingHandler) {
|
|
210
|
-
const wrappedHandler = createToolsCallWrapper(existingHandler, lowLevelServer)
|
|
211
|
-
lowLevelServer._requestHandlers.set('tools/call', wrappedHandler)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const originalSetRequestHandler = lowLevelServer.setRequestHandler.bind(lowLevelServer)
|
|
215
|
-
|
|
216
|
-
lowLevelServer.setRequestHandler = ((requestSchema: unknown, handler: MCPRequestHandler) => {
|
|
217
|
-
const shape = getObjectShape(requestSchema)
|
|
218
|
-
const method = shape?.method ? getLiteralValue(shape.method) : undefined
|
|
219
|
-
|
|
220
|
-
if (method === 'tools/call') {
|
|
221
|
-
const wrappedHandler = createToolsCallWrapper(handler, lowLevelServer)
|
|
222
|
-
return originalSetRequestHandler(requestSchema, wrappedHandler)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return originalSetRequestHandler(requestSchema, handler)
|
|
226
|
-
}) as MCPServerLike['setRequestHandler']
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function createToolsCallWrapper(originalHandler: MCPRequestHandler, server: MCPServerLike): MCPRequestHandler {
|
|
230
|
-
return async (request: MCPRequest, extra: MCPRequestExtra) =>
|
|
231
|
-
await handleWrappedToolsCall(originalHandler, server, request, extra)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async function handleWrappedToolsCall(
|
|
235
|
-
originalHandler: MCPRequestHandler,
|
|
204
|
+
async function handleToolCallRequest(
|
|
236
205
|
server: MCPServerLike,
|
|
206
|
+
originalCallToolHandler: MCPRequestHandler,
|
|
237
207
|
request: MCPRequest,
|
|
238
208
|
extra: MCPRequestExtra
|
|
239
209
|
): Promise<unknown> {
|
|
@@ -242,7 +212,7 @@ async function handleWrappedToolsCall(
|
|
|
242
212
|
log(
|
|
243
213
|
'Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.'
|
|
244
214
|
)
|
|
245
|
-
return await
|
|
215
|
+
return await originalCallToolHandler(request, extra)
|
|
246
216
|
}
|
|
247
217
|
|
|
248
218
|
if (request.params?.name === resolveMissingCapabilityToolName(data.options)) {
|
|
@@ -267,7 +237,7 @@ async function handleWrappedToolsCall(
|
|
|
267
237
|
data,
|
|
268
238
|
request,
|
|
269
239
|
extra,
|
|
270
|
-
execute: () =>
|
|
240
|
+
execute: () => originalCallToolHandler(request, extra),
|
|
271
241
|
takeCapturedError: () => {
|
|
272
242
|
const captured = extra?.__mcp_analytics_error
|
|
273
243
|
if (extra) {
|
|
@@ -280,11 +250,16 @@ async function handleWrappedToolsCall(
|
|
|
280
250
|
|
|
281
251
|
export function instrumentHighLevelServer(server: HighLevelMCPServerLike): void {
|
|
282
252
|
try {
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
253
|
+
const lowLevelServer = server.server
|
|
254
|
+
const mcpAnalyticsData = getServerTrackingData(lowLevelServer)
|
|
255
|
+
|
|
256
|
+
// Patch already existing handlers, and patch setRequestHandler to capture dynamically created handlers.
|
|
257
|
+
const handlers = {
|
|
258
|
+
initialize: handleInitializeRequest,
|
|
259
|
+
'tools/list': handleListToolsRequest,
|
|
260
|
+
'tools/call': handleToolCallRequest,
|
|
261
|
+
}
|
|
262
|
+
patchRequestHandlers(lowLevelServer, handlers)
|
|
288
263
|
|
|
289
264
|
server._registeredTools = addTracingToToolRegistry(server._registeredTools, server)
|
|
290
265
|
|
|
@@ -293,8 +268,6 @@ export function instrumentHighLevelServer(server: HighLevelMCPServerLike): void
|
|
|
293
268
|
seedToolCategoriesFromRegistry(mcpAnalyticsData.toolCategories, server._registeredTools)
|
|
294
269
|
}
|
|
295
270
|
|
|
296
|
-
instrumentToolsListHandler(server.server)
|
|
297
|
-
|
|
298
271
|
setupListenerToRegisteredTools(server)
|
|
299
272
|
} catch (error) {
|
|
300
273
|
log(`Warning: Failed to setup tool call instrumentation - ${error}`)
|
|
@@ -8,7 +8,12 @@ import { MCPAnalyticsEventType } from './event-types'
|
|
|
8
8
|
import { getServerTrackingData } from './internal'
|
|
9
9
|
import { log } from './logger'
|
|
10
10
|
import { handleReportMissing, resolveMissingCapabilityToolName } from './tools'
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
handleInitializeRequest,
|
|
13
|
+
handleListToolsRequest,
|
|
14
|
+
patchRequestHandlers,
|
|
15
|
+
captureToolCall,
|
|
16
|
+
} from './instrumentation'
|
|
12
17
|
import { getContextArgument } from './tracing-helpers'
|
|
13
18
|
|
|
14
19
|
type MCPRequestHandler = NonNullable<
|
|
@@ -24,8 +29,12 @@ type MCPRequestExtra = Parameters<MCPRequestHandler>[1]
|
|
|
24
29
|
*/
|
|
25
30
|
export function instrumentLowLevelServer(server: MCPServerLike): void {
|
|
26
31
|
try {
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
// Patch already existing handlers, and patch setRequestHandler to capture dynamically created handlers.
|
|
33
|
+
const handlers = {
|
|
34
|
+
initialize: handleInitializeRequest,
|
|
35
|
+
'tools/list': handleListToolsRequest,
|
|
36
|
+
}
|
|
37
|
+
patchRequestHandlers(server, handlers)
|
|
29
38
|
|
|
30
39
|
const originalCallToolHandler = server._requestHandlers.get('tools/call')
|
|
31
40
|
server.setRequestHandler(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2025 MCPcat
|
|
3
3
|
// Licensed under the MIT License: https://github.com/MCPCat/mcpcat-typescript-sdk/blob/main/LICENSE
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { ListToolsResult } from '@modelcontextprotocol/sdk/types.js'
|
|
6
6
|
import type { CompatibleRequestHandlerExtra, MCPAnalyticsData, MCPRequestLike, MCPServerLike, McpEvent } from '../types'
|
|
7
7
|
import { addContextParameterToTools, getContextDescription, isContextEnabled } from './context-parameters'
|
|
8
8
|
import {
|
|
@@ -228,63 +228,53 @@ function publishFailedToolEvent(
|
|
|
228
228
|
|
|
229
229
|
// --- tools/list -----------------------------------------------------------
|
|
230
230
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
231
|
+
/**
|
|
232
|
+
* A method's patch: runs the original handler and captures analytics. `server`
|
|
233
|
+
* and `originalHandler` are bound by {@link patchRequestHandlers}; the SDK
|
|
234
|
+
* supplies `request` and `extra` per call.
|
|
235
|
+
*/
|
|
236
|
+
export type HandlerPatch = (
|
|
237
|
+
server: MCPServerLike,
|
|
238
|
+
originalHandler: MCPRequestHandler,
|
|
239
|
+
request: MCPRequestLike,
|
|
240
|
+
extra: CompatibleRequestHandlerExtra | undefined
|
|
241
|
+
) => Promise<unknown>
|
|
238
242
|
|
|
239
243
|
/**
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* The handler can reach us two ways, and we cover both:
|
|
246
|
-
* 1. It already exists when instrument() runs (tools registered first) — wrap
|
|
247
|
-
* the entry in `_requestHandlers` directly.
|
|
248
|
-
* 2. It's registered after instrument() (e.g. `@rekog/mcp-nest` registers it at
|
|
249
|
-
* the low level once it gets the server) — intercept `setRequestHandler` and
|
|
250
|
-
* wrap the handler as it lands, mirroring how `tools/call` already works.
|
|
244
|
+
* Applies the `patches` (keyed by method, e.g. `initialize`, `tools/list`) to the
|
|
245
|
+
* handlers already registered, and patches `setRequestHandler` so matching
|
|
246
|
+
* handlers registered later are patched too. The latter is what makes adapters
|
|
247
|
+
* that register handlers post-construction work — e.g. `@rekog/mcp-nest` hands a
|
|
248
|
+
* bare server to instrument() and only then registers its handlers.
|
|
251
249
|
*/
|
|
252
|
-
export function
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
250
|
+
export function patchRequestHandlers(server: MCPServerLike, patches: Record<string, HandlerPatch>): void {
|
|
251
|
+
// Monkey patch existing handlers.
|
|
252
|
+
for (const [handlerName, patch] of Object.entries(patches)) {
|
|
253
|
+
const originalHandler = server._requestHandlers.get(handlerName)
|
|
254
|
+
if (originalHandler) {
|
|
255
|
+
server._requestHandlers.set(handlerName, (request, extra) => patch(server, originalHandler, request, extra))
|
|
256
|
+
}
|
|
258
257
|
}
|
|
259
|
-
listToolsTracingSetup.set(server, true)
|
|
260
258
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
259
|
+
// Monkey patch dynamically added handlers (registered after instrument()).
|
|
260
|
+
const originalSetRequestHandler = server.setRequestHandler.bind(server)
|
|
261
|
+
server.setRequestHandler = ((requestSchema: unknown, originalHandler: MCPRequestHandler) => {
|
|
262
|
+
const shape = getObjectShape(requestSchema)
|
|
263
|
+
const handlerName = shape?.method ? getLiteralValue(shape.method) : undefined
|
|
264
|
+
const patch = typeof handlerName === 'string' ? patches[handlerName] : undefined
|
|
265
|
+
if (!patch) {
|
|
266
|
+
return originalSetRequestHandler(requestSchema, originalHandler)
|
|
268
267
|
}
|
|
269
268
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
server.setRequestHandler = ((requestSchema: unknown, handler: MCPRequestHandler) => {
|
|
273
|
-
const shape = getObjectShape(requestSchema)
|
|
274
|
-
const method = shape?.method ? getLiteralValue(shape.method) : undefined
|
|
275
|
-
if (method === 'tools/list') {
|
|
276
|
-
return originalSetRequestHandler(requestSchema, (request, extra) =>
|
|
277
|
-
handleListToolsRequest(server, handler, request, extra)
|
|
278
|
-
)
|
|
279
|
-
}
|
|
280
|
-
return originalSetRequestHandler(requestSchema, handler)
|
|
281
|
-
}) as MCPServerLike['setRequestHandler']
|
|
282
|
-
} catch (error) {
|
|
283
|
-
log(`Warning: Failed to override list tools handler - ${error}`)
|
|
284
|
-
}
|
|
269
|
+
return originalSetRequestHandler(requestSchema, (request, extra) => patch(server, originalHandler, request, extra))
|
|
270
|
+
}) as MCPServerLike['setRequestHandler']
|
|
285
271
|
}
|
|
286
272
|
|
|
287
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Captures each `tools/list` and injects the SDK-managed tools (context
|
|
275
|
+
* parameter, conversation id, `get_more_tools`) into the returned list.
|
|
276
|
+
*/
|
|
277
|
+
export async function handleListToolsRequest(
|
|
288
278
|
server: MCPServerLike,
|
|
289
279
|
originalListToolsHandler: MCPRequestHandler,
|
|
290
280
|
request: MCPRequestLike,
|
|
@@ -421,40 +411,38 @@ export function cacheToolCategories(cache: Map<string, string>, tools: ListTools
|
|
|
421
411
|
// --- initialize -----------------------------------------------------------
|
|
422
412
|
|
|
423
413
|
/**
|
|
424
|
-
*
|
|
425
|
-
*
|
|
414
|
+
* Captures the connection handshake (and resolves identity) on `initialize`
|
|
415
|
+
* before the original handler runs.
|
|
426
416
|
*/
|
|
427
|
-
export function
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
417
|
+
export async function handleInitializeRequest(
|
|
418
|
+
server: MCPServerLike,
|
|
419
|
+
originalInitializeHandler: MCPRequestHandler,
|
|
420
|
+
request: MCPRequestLike,
|
|
421
|
+
extra?: CompatibleRequestHandlerExtra
|
|
422
|
+
): Promise<unknown> {
|
|
423
|
+
const data = getServerTrackingData(server)
|
|
424
|
+
if (!data) {
|
|
425
|
+
log(
|
|
426
|
+
'Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.'
|
|
427
|
+
)
|
|
428
|
+
return await originalInitializeHandler(request, extra)
|
|
431
429
|
}
|
|
432
430
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (!data) {
|
|
436
|
-
log(
|
|
437
|
-
'Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called instrument(server, options) before using tool calls.'
|
|
438
|
-
)
|
|
439
|
-
return await originalInitializeHandler(request, extra)
|
|
440
|
-
}
|
|
431
|
+
const sessionId = getServerSessionId(server, extra)
|
|
432
|
+
await handleIdentify(server, data, sessionId, request, extra)
|
|
441
433
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
parameters: buildCapturedMcpParameters(request),
|
|
450
|
-
timestamp: new Date(),
|
|
451
|
-
}
|
|
434
|
+
const event: McpEvent = {
|
|
435
|
+
sessionId,
|
|
436
|
+
resourceName: request.params?.name || 'Unknown Tool Name',
|
|
437
|
+
eventType: MCPAnalyticsEventType.mcpInitialize,
|
|
438
|
+
parameters: buildCapturedMcpParameters(request),
|
|
439
|
+
timestamp: new Date(),
|
|
440
|
+
}
|
|
452
441
|
|
|
453
|
-
|
|
442
|
+
await applyResolvedMetadata(event, data, request, extra)
|
|
454
443
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
})
|
|
444
|
+
const result = await originalInitializeHandler(request, extra)
|
|
445
|
+
event.response = result
|
|
446
|
+
captureEvent(server, event)
|
|
447
|
+
return result
|
|
460
448
|
}
|
package/src/extensions/sink.ts
CHANGED
|
@@ -114,10 +114,19 @@ export class McpEventSink {
|
|
|
114
114
|
const { event: fullEvent, captures } = result
|
|
115
115
|
try {
|
|
116
116
|
for (const captureEvent of captures) {
|
|
117
|
+
// `$groups` is written into `properties` by `buildPostHogCaptureEvents`,
|
|
118
|
+
// but posthog-node's `prepareEventMessage` overwrites the outgoing
|
|
119
|
+
// `$groups` property with the top-level `groups` field
|
|
120
|
+
// (`$groups: eventMessage.groups || groups`). Without passing `groups`
|
|
121
|
+
// here the group association would be silently dropped. See
|
|
122
|
+
// https://github.com/PostHog/posthog-js/issues/3888.
|
|
123
|
+
const groups = captureEvent.properties.$groups as Record<string, string> | undefined
|
|
124
|
+
|
|
117
125
|
this.posthog.capture({
|
|
118
126
|
distinctId: captureEvent.distinct_id,
|
|
119
127
|
event: captureEvent.event,
|
|
120
128
|
properties: captureEvent.properties,
|
|
129
|
+
...(groups ? { groups } : {}),
|
|
121
130
|
timestamp: new Date(captureEvent.timestamp),
|
|
122
131
|
uuid: uuidv7(),
|
|
123
132
|
})
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '0.4.
|
|
1
|
+
export const version = '0.4.4'
|