@posthog/mcp 0.10.7 → 0.10.9
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/analytics-parameters.d.ts +7 -2
- package/dist/extensions/analytics-parameters.d.ts.map +1 -1
- package/dist/extensions/analytics-parameters.js +4 -2
- package/dist/extensions/analytics-parameters.mjs +4 -2
- package/dist/extensions/conversation-id.d.ts +37 -8
- package/dist/extensions/conversation-id.d.ts.map +1 -1
- package/dist/extensions/conversation-id.js +8 -13
- package/dist/extensions/conversation-id.mjs +8 -13
- package/dist/extensions/instrument-highlevel.d.ts.map +1 -1
- package/dist/extensions/instrument-highlevel.js +1 -1
- package/dist/extensions/instrument-highlevel.mjs +1 -1
- package/dist/extensions/instrument-lowlevel.d.ts.map +1 -1
- package/dist/extensions/instrument-lowlevel.js +6 -5
- package/dist/extensions/instrument-lowlevel.mjs +7 -6
- package/dist/extensions/instrumentation.d.ts +22 -0
- package/dist/extensions/instrumentation.d.ts.map +1 -1
- package/dist/extensions/instrumentation.js +48 -23
- package/dist/extensions/instrumentation.mjs +46 -24
- package/dist/extensions/internal.d.ts +8 -1
- package/dist/extensions/internal.d.ts.map +1 -1
- package/dist/extensions/internal.js +2 -2
- package/dist/extensions/internal.mjs +2 -2
- package/dist/extensions/mcp-sdk-compat.d.ts +10 -0
- package/dist/extensions/mcp-sdk-compat.d.ts.map +1 -1
- package/dist/extensions/mcp-sdk-compat.js +11 -2
- package/dist/extensions/mcp-sdk-compat.mjs +7 -1
- package/dist/extensions/output-instructions.d.ts +70 -0
- package/dist/extensions/output-instructions.d.ts.map +1 -0
- package/dist/extensions/output-instructions.js +131 -0
- package/dist/extensions/output-instructions.mjs +82 -0
- package/dist/extensions/session.d.ts +26 -5
- package/dist/extensions/session.d.ts.map +1 -1
- package/dist/extensions/session.js +32 -14
- package/dist/extensions/session.mjs +30 -15
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- 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/analytics-parameters.ts +15 -2
- package/src/extensions/conversation-id.ts +51 -29
- package/src/extensions/instrument-highlevel.ts +3 -1
- package/src/extensions/instrument-lowlevel.ts +14 -9
- package/src/extensions/instrumentation.ts +130 -38
- package/src/extensions/internal.ts +10 -2
- package/src/extensions/mcp-sdk-compat.ts +18 -0
- package/src/extensions/output-instructions.ts +231 -0
- package/src/extensions/session.ts +127 -28
- package/src/types.ts +23 -1
- package/src/version.ts +1 -1
|
@@ -24,6 +24,7 @@ var __webpack_require__ = {};
|
|
|
24
24
|
var __webpack_exports__ = {};
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
deriveSessionIdFromConversation: ()=>deriveSessionIdFromConversation,
|
|
27
28
|
getSessionId: ()=>getSessionId,
|
|
28
29
|
deriveSessionIdFromMCPSession: ()=>deriveSessionIdFromMCPSession,
|
|
29
30
|
getSessionInfo: ()=>getSessionInfo,
|
|
@@ -40,27 +41,42 @@ function newSessionId() {
|
|
|
40
41
|
function deriveSessionIdFromMCPSession(mcpSessionId) {
|
|
41
42
|
return (0, external_ids_js_namespaceObject.deterministicPrefixedId)('ses', mcpSessionId);
|
|
42
43
|
}
|
|
43
|
-
function
|
|
44
|
+
function deriveSessionIdFromConversation(conversationId) {
|
|
45
|
+
return (0, external_ids_js_namespaceObject.deterministicPrefixedId)('ses', conversationId);
|
|
46
|
+
}
|
|
47
|
+
function getSessionId(server, extra, conversationId) {
|
|
44
48
|
const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
|
|
45
49
|
if (!data) throw new Error('Server tracking data not found');
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
data.sessionInfo.clientVersion = token.clientVersion;
|
|
53
|
-
data.sessionInfo.protocolVersion = token.protocolVersion;
|
|
54
|
-
sessionId = token.sessionId;
|
|
55
|
-
} else if (extra?.sessionId) {
|
|
56
|
-
data.sessionSource = 'mcp';
|
|
57
|
-
sessionId = deriveSessionIdFromMCPSession(extra.sessionId);
|
|
58
|
-
} else sessionId = getSessionIdFromMemory(data);
|
|
50
|
+
if (conversationId) {
|
|
51
|
+
applyTokenClientIdentity(data, extra);
|
|
52
|
+
return deriveSessionIdFromConversation(conversationId);
|
|
53
|
+
}
|
|
54
|
+
const carriedByRequest = readSessionIdFromRequest(data, extra);
|
|
55
|
+
const sessionId = carriedByRequest ?? getSessionIdFromMemory(data);
|
|
59
56
|
data.sessionId = sessionId;
|
|
60
57
|
data.lastActivity = new Date();
|
|
61
58
|
(0, external_internal_js_namespaceObject.setServerTrackingData)(server, data);
|
|
62
59
|
return sessionId;
|
|
63
60
|
}
|
|
61
|
+
function applyTokenClientIdentity(data, extra) {
|
|
62
|
+
const token = (0, external_session_token_js_namespaceObject.decodeSessionId)((0, external_session_token_js_namespaceObject.readMcpSessionHeader)(extra?.requestInfo?.headers));
|
|
63
|
+
if (!token) return;
|
|
64
|
+
data.sessionInfo.clientName = token.clientName;
|
|
65
|
+
data.sessionInfo.clientVersion = token.clientVersion;
|
|
66
|
+
data.sessionInfo.protocolVersion = token.protocolVersion;
|
|
67
|
+
return token;
|
|
68
|
+
}
|
|
69
|
+
function readSessionIdFromRequest(data, extra) {
|
|
70
|
+
const token = applyTokenClientIdentity(data, extra);
|
|
71
|
+
if (token) {
|
|
72
|
+
data.sessionSource = 'token';
|
|
73
|
+
return token.sessionId;
|
|
74
|
+
}
|
|
75
|
+
if (extra?.sessionId) {
|
|
76
|
+
data.sessionSource = 'mcp';
|
|
77
|
+
return deriveSessionIdFromMCPSession(extra.sessionId);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
64
80
|
function getSessionIdFromMemory(data) {
|
|
65
81
|
const timeoutMs = 60 * external_constants_js_namespaceObject.INACTIVITY_TIMEOUT_IN_MINUTES * 1000;
|
|
66
82
|
const isStale = Date.now() - data.lastActivity.getTime() > timeoutMs;
|
|
@@ -94,11 +110,13 @@ function getSessionInfo(server, data, sessionId) {
|
|
|
94
110
|
...sessionInfo
|
|
95
111
|
};
|
|
96
112
|
}
|
|
113
|
+
exports.deriveSessionIdFromConversation = __webpack_exports__.deriveSessionIdFromConversation;
|
|
97
114
|
exports.deriveSessionIdFromMCPSession = __webpack_exports__.deriveSessionIdFromMCPSession;
|
|
98
115
|
exports.getSessionId = __webpack_exports__.getSessionId;
|
|
99
116
|
exports.getSessionInfo = __webpack_exports__.getSessionInfo;
|
|
100
117
|
exports.newSessionId = __webpack_exports__.newSessionId;
|
|
101
118
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
119
|
+
"deriveSessionIdFromConversation",
|
|
102
120
|
"deriveSessionIdFromMCPSession",
|
|
103
121
|
"getSessionId",
|
|
104
122
|
"getSessionInfo",
|
|
@@ -9,27 +9,42 @@ function newSessionId() {
|
|
|
9
9
|
function deriveSessionIdFromMCPSession(mcpSessionId) {
|
|
10
10
|
return deterministicPrefixedId('ses', mcpSessionId);
|
|
11
11
|
}
|
|
12
|
-
function
|
|
12
|
+
function deriveSessionIdFromConversation(conversationId) {
|
|
13
|
+
return deterministicPrefixedId('ses', conversationId);
|
|
14
|
+
}
|
|
15
|
+
function getSessionId(server, extra, conversationId) {
|
|
13
16
|
const data = getServerTrackingData(server);
|
|
14
17
|
if (!data) throw new Error('Server tracking data not found');
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
data.sessionInfo.clientVersion = token.clientVersion;
|
|
22
|
-
data.sessionInfo.protocolVersion = token.protocolVersion;
|
|
23
|
-
sessionId = token.sessionId;
|
|
24
|
-
} else if (extra?.sessionId) {
|
|
25
|
-
data.sessionSource = 'mcp';
|
|
26
|
-
sessionId = deriveSessionIdFromMCPSession(extra.sessionId);
|
|
27
|
-
} else sessionId = getSessionIdFromMemory(data);
|
|
18
|
+
if (conversationId) {
|
|
19
|
+
applyTokenClientIdentity(data, extra);
|
|
20
|
+
return deriveSessionIdFromConversation(conversationId);
|
|
21
|
+
}
|
|
22
|
+
const carriedByRequest = readSessionIdFromRequest(data, extra);
|
|
23
|
+
const sessionId = carriedByRequest ?? getSessionIdFromMemory(data);
|
|
28
24
|
data.sessionId = sessionId;
|
|
29
25
|
data.lastActivity = new Date();
|
|
30
26
|
setServerTrackingData(server, data);
|
|
31
27
|
return sessionId;
|
|
32
28
|
}
|
|
29
|
+
function applyTokenClientIdentity(data, extra) {
|
|
30
|
+
const token = decodeSessionId(readMcpSessionHeader(extra?.requestInfo?.headers));
|
|
31
|
+
if (!token) return;
|
|
32
|
+
data.sessionInfo.clientName = token.clientName;
|
|
33
|
+
data.sessionInfo.clientVersion = token.clientVersion;
|
|
34
|
+
data.sessionInfo.protocolVersion = token.protocolVersion;
|
|
35
|
+
return token;
|
|
36
|
+
}
|
|
37
|
+
function readSessionIdFromRequest(data, extra) {
|
|
38
|
+
const token = applyTokenClientIdentity(data, extra);
|
|
39
|
+
if (token) {
|
|
40
|
+
data.sessionSource = 'token';
|
|
41
|
+
return token.sessionId;
|
|
42
|
+
}
|
|
43
|
+
if (extra?.sessionId) {
|
|
44
|
+
data.sessionSource = 'mcp';
|
|
45
|
+
return deriveSessionIdFromMCPSession(extra.sessionId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
33
48
|
function getSessionIdFromMemory(data) {
|
|
34
49
|
const timeoutMs = 60 * INACTIVITY_TIMEOUT_IN_MINUTES * 1000;
|
|
35
50
|
const isStale = Date.now() - data.lastActivity.getTime() > timeoutMs;
|
|
@@ -63,4 +78,4 @@ function getSessionInfo(server, data, sessionId) {
|
|
|
63
78
|
...sessionInfo
|
|
64
79
|
};
|
|
65
80
|
}
|
|
66
|
-
export { deriveSessionIdFromMCPSession, getSessionId, getSessionInfo, newSessionId };
|
|
81
|
+
export { deriveSessionIdFromConversation, deriveSessionIdFromMCPSession, getSessionId, getSessionInfo, newSessionId };
|
package/dist/types.d.ts
CHANGED
|
@@ -46,7 +46,21 @@ export interface MCPAnalyticsOptions {
|
|
|
46
46
|
* detected under the same name.
|
|
47
47
|
*/
|
|
48
48
|
missingCapabilityToolName?: string;
|
|
49
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Opt in to session correlation for the MCP **2026-07-28** revision, which removed
|
|
51
|
+
* protocol-level sessions: no `initialize`, no `mcp-session-id` header, and a fresh
|
|
52
|
+
* server instance per HTTP request. With none of those left to anchor on, the only
|
|
53
|
+
* thing that can carry a session across calls is the agent itself.
|
|
54
|
+
*
|
|
55
|
+
* Turning this on injects a `conversation_id` parameter into every tool, mints one
|
|
56
|
+
* on the first call, asks the agent to echo it back, and derives `$session_id` from
|
|
57
|
+
* that handle — so calls correlate across reconnects, restarts, and per-request
|
|
58
|
+
* instances.
|
|
59
|
+
*
|
|
60
|
+
* Off by default, and fully inert when off: no parameter is injected, no schema is
|
|
61
|
+
* touched, no prompt-back is appended, and `$session_id` resolves exactly as it did
|
|
62
|
+
* before (the request's own session id, else this instance's).
|
|
63
|
+
*/
|
|
50
64
|
enableConversationId?: boolean;
|
|
51
65
|
/**
|
|
52
66
|
* Emit a `$exception` event alongside any failed tool call. Defaults to `true`.
|
|
@@ -96,6 +110,8 @@ export type RegisteredTool = {
|
|
|
96
110
|
/** MCP tool `_meta` block (spec-allowed arbitrary metadata, e.g. `category`). */
|
|
97
111
|
_meta?: Record<string, unknown>;
|
|
98
112
|
inputSchema?: unknown;
|
|
113
|
+
/** Present when the tool was registered with a declared output schema. */
|
|
114
|
+
outputSchema?: unknown;
|
|
99
115
|
update?: (...args: unknown[]) => unknown;
|
|
100
116
|
} & ({
|
|
101
117
|
callback: ToolCallback;
|
|
@@ -243,6 +259,12 @@ export interface SessionInfo {
|
|
|
243
259
|
export interface AnalyticsParameterOwnership {
|
|
244
260
|
context: boolean;
|
|
245
261
|
conversationId: boolean;
|
|
262
|
+
/**
|
|
263
|
+
* True when we declared `_mcp_instructions` on this tool's advertised output
|
|
264
|
+
* schema, so writing that key into `structuredContent` will validate. False
|
|
265
|
+
* for tools with no output schema, or one we could not extend.
|
|
266
|
+
*/
|
|
267
|
+
outputInstructions: boolean;
|
|
246
268
|
}
|
|
247
269
|
export interface MCPAnalyticsData {
|
|
248
270
|
sink: McpEventSink | undefined;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEnD,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD,+FAA+F;AAC/F,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC,eAAe,CAAA;AAC3D,qEAAqE;AACrE,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,CAAA;AAEjD,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,4FAA4F;AAC5F,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,2FAA2F;IAC3F,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "0.10.
|
|
1
|
+
export declare const version = "0.10.9";
|
|
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.10.
|
|
29
|
+
const version = '0.10.9';
|
|
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.10.
|
|
1
|
+
const version = '0.10.9';
|
|
2
2
|
export { version };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.9",
|
|
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.46.
|
|
31
|
+
"@posthog/core": "^1.46.9"
|
|
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.48.1",
|
|
43
|
+
"@posthog-tooling/tsconfig-base": "1.1.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@modelcontextprotocol/sdk": ">=1.26.0",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AnalyticsParameterOwnership } from '../types'
|
|
2
2
|
import { getObjectShape, isZodRawShapeCompat } from './mcp-sdk-compat'
|
|
3
|
+
import { canDeclareOutputInstructions } from './output-instructions'
|
|
3
4
|
|
|
4
5
|
const JSON_SCHEMA_KEYWORDS = [
|
|
5
6
|
'$defs',
|
|
@@ -68,14 +69,26 @@ export function analyticsOwnsParameter(inputSchema: unknown, parameterName: stri
|
|
|
68
69
|
return canInjectAnalyticsParameter(schema, parameterName)
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
export function getAnalyticsParameterOwnership(
|
|
72
|
+
export function getAnalyticsParameterOwnership(
|
|
73
|
+
inputSchema: unknown,
|
|
74
|
+
outputSchema?: unknown
|
|
75
|
+
): AnalyticsParameterOwnership {
|
|
72
76
|
return {
|
|
73
77
|
context: analyticsOwnsParameter(inputSchema, 'context'),
|
|
74
78
|
conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id'),
|
|
79
|
+
outputInstructions: canDeclareOutputInstructions(outputSchema),
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Removes the arguments we injected, leaving the host's own. Input-side only, so
|
|
85
|
+
* it takes just those two flags rather than the whole ownership record — callers
|
|
86
|
+
* that have no output-schema context should not have to invent a value for it.
|
|
87
|
+
*/
|
|
88
|
+
export function stripOwnedAnalyticsArguments(
|
|
89
|
+
args: unknown,
|
|
90
|
+
ownership: Pick<AnalyticsParameterOwnership, 'context' | 'conversationId'>
|
|
91
|
+
): unknown {
|
|
79
92
|
let cleanedArgs = args
|
|
80
93
|
if (ownership.context && cleanedArgs && typeof cleanedArgs === 'object' && 'context' in cleanedArgs) {
|
|
81
94
|
const { context: _context, ...rest } = cleanedArgs
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
} from './analytics-parameters'
|
|
12
12
|
import { DEFAULT_CONVERSATION_ID_DESCRIPTION } from './constants'
|
|
13
13
|
import { log, type LoggerFn } from './logger'
|
|
14
|
-
import { GET_MORE_TOOLS_NAME } from './tools'
|
|
15
14
|
|
|
16
15
|
export const CONVERSATION_ID_PARAM_NAME = 'conversation_id'
|
|
17
16
|
|
|
@@ -70,60 +69,83 @@ export function addConversationIdToTool<TTool extends ConversationIdInjectableTo
|
|
|
70
69
|
return modifiedTool
|
|
71
70
|
}
|
|
72
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Injects `conversation_id` across a tool listing, including the virtual
|
|
74
|
+
* `get_more_tools` tool. Its calls publish `$mcp_missing_capability`, and a
|
|
75
|
+
* capability gap is only meaningful next to the work that hit it — so it belongs
|
|
76
|
+
* in the same session as the surrounding tool calls.
|
|
77
|
+
*/
|
|
73
78
|
export function addConversationIdToTools<TTool extends ConversationIdInjectableTool>(
|
|
74
79
|
tools: TTool[],
|
|
75
|
-
missingCapabilityToolName: string = GET_MORE_TOOLS_NAME,
|
|
76
|
-
skipMissingCapabilityTool = true,
|
|
77
80
|
logger: LoggerFn = log
|
|
78
81
|
): TTool[] {
|
|
79
|
-
return tools.map((tool) =>
|
|
80
|
-
if (skipMissingCapabilityTool && tool.name === missingCapabilityToolName) {
|
|
81
|
-
return tool
|
|
82
|
-
}
|
|
83
|
-
return addConversationIdToTool(tool, logger)
|
|
84
|
-
})
|
|
82
|
+
return tools.map((tool) => addConversationIdToTool(tool, logger))
|
|
85
83
|
}
|
|
86
84
|
|
|
85
|
+
/**
|
|
86
|
+
* The shape of every id we mint: a uuidv7. Used to tell an echo of our own handle
|
|
87
|
+
* from a value the agent made up.
|
|
88
|
+
*/
|
|
89
|
+
const MINTED_CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
|
90
|
+
|
|
87
91
|
export type ConversationIdResolution =
|
|
88
92
|
| { minted: false; conversationId: string | undefined }
|
|
89
93
|
| { minted: true; conversationId: string }
|
|
90
94
|
|
|
91
95
|
/**
|
|
92
96
|
* Decides which conversation_id to use for a tool call:
|
|
93
|
-
* - disabled
|
|
94
|
-
* - agent
|
|
95
|
-
* -
|
|
97
|
+
* - disabled → none
|
|
98
|
+
* - agent echoed a handle we could have minted → use it
|
|
99
|
+
* - anything else → mint a fresh one
|
|
100
|
+
*
|
|
101
|
+
* The shape check matters because this value becomes `$session_id`, and the
|
|
102
|
+
* derivation is deterministic so that two pods agree — which also means two
|
|
103
|
+
* *callers* sending the same string land in the same session. The strings agents
|
|
104
|
+
* invent are not random (`conv-1`, `1`, `session`), so trusting them verbatim
|
|
105
|
+
* would silently merge unrelated conversations, potentially across users.
|
|
106
|
+
*
|
|
107
|
+
* A compliant agent echoes the uuidv7 we minted and is unaffected. Anything else
|
|
108
|
+
* is treated exactly as if the handle were absent: mint, and prompt back. Shape
|
|
109
|
+
* rather than a registry of issued ids, because a per-request server has no
|
|
110
|
+
* memory of what it minted.
|
|
111
|
+
*
|
|
112
|
+
* This narrows the problem, it does not prove provenance: a caller supplying a
|
|
113
|
+
* well-formed uuidv7 is trusted, so two that pick the *same* one still merge. That
|
|
114
|
+
* residue is far smaller than the case it replaces — an agent ignoring the
|
|
115
|
+
* parameter description reaches for `conv-1` or `1`, not a conforming uuidv7 — and
|
|
116
|
+
* closing it needs a signed handle, i.e. a secret shared by every pod. Worth doing
|
|
117
|
+
* if this ever anchors something security-bearing; `$session_id` is an analytics
|
|
118
|
+
* grouping key, so it does not today.
|
|
96
119
|
*/
|
|
97
|
-
export function resolveConversationId(
|
|
98
|
-
enabled
|
|
99
|
-
args: unknown,
|
|
100
|
-
toolName: string | undefined,
|
|
101
|
-
missingCapabilityToolName: string = GET_MORE_TOOLS_NAME
|
|
102
|
-
): ConversationIdResolution {
|
|
103
|
-
if (!enabled || toolName === missingCapabilityToolName) {
|
|
120
|
+
export function resolveConversationId(enabled: boolean, args: unknown): ConversationIdResolution {
|
|
121
|
+
if (!enabled) {
|
|
104
122
|
return { minted: false, conversationId: undefined }
|
|
105
123
|
}
|
|
106
124
|
const supplied = extractConversationId(args)
|
|
107
|
-
if (supplied) {
|
|
108
|
-
|
|
125
|
+
if (supplied && MINTED_CONVERSATION_ID.test(supplied)) {
|
|
126
|
+
// Lowercased because the shape test is case-insensitive but the hash behind
|
|
127
|
+
// `$session_id` is not. Some hosts normalise uuids to uppercase, and an
|
|
128
|
+
// uppercased echo of our own handle would otherwise clear the gate and then
|
|
129
|
+
// land in a different session than the call that minted it.
|
|
130
|
+
return { minted: false, conversationId: supplied.toLowerCase() }
|
|
109
131
|
}
|
|
110
132
|
return { minted: true, conversationId: uuidv7() }
|
|
111
133
|
}
|
|
112
134
|
|
|
113
135
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
136
|
+
* Whether the prompt-back can ride this result's `content`. The only requirement
|
|
137
|
+
* is an array to append to.
|
|
138
|
+
*
|
|
139
|
+
* Errored results included on purpose. A tool that fails on the first call of a
|
|
140
|
+
* conversation is exactly when the agent needs the session handle: without it the
|
|
141
|
+
* retry starts a fresh conversation, so the failure and its fix land in different
|
|
142
|
+
* sessions.
|
|
117
143
|
*/
|
|
118
144
|
export function canInjectConversationIdPromptBack(result: unknown): boolean {
|
|
119
145
|
if (!(result && typeof result === 'object')) {
|
|
120
146
|
return false
|
|
121
147
|
}
|
|
122
|
-
|
|
123
|
-
if (resultObj.isError === true) {
|
|
124
|
-
return false
|
|
125
|
-
}
|
|
126
|
-
return Array.isArray(resultObj.content)
|
|
148
|
+
return Array.isArray((result as { content?: unknown }).content)
|
|
127
149
|
}
|
|
128
150
|
|
|
129
151
|
export function extractConversationId(args: unknown): string | undefined {
|
|
@@ -262,7 +262,9 @@ async function handleToolCallRequest(
|
|
|
262
262
|
request,
|
|
263
263
|
extra,
|
|
264
264
|
execute: (downstreamRequest) => originalCallToolHandler(downstreamRequest as MCPRequest, extra),
|
|
265
|
-
parameterOwnership: registeredTool
|
|
265
|
+
parameterOwnership: registeredTool
|
|
266
|
+
? getAnalyticsParameterOwnership(registeredTool.inputSchema, registeredTool.outputSchema)
|
|
267
|
+
: undefined,
|
|
266
268
|
takeCapturedError: () => {
|
|
267
269
|
const captured = extra?.__mcp_analytics_error
|
|
268
270
|
if (extra) {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// Copyright (c) 2025 AgentCat, Inc. (formerly MCPcat)
|
|
4
4
|
// Licensed under the MIT License: https://github.com/agentcathq/agentcat-typescript-sdk/blob/main/LICENSE
|
|
5
5
|
|
|
6
|
-
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'
|
|
7
6
|
import type { CompatibleRequestHandlerExtra, MCPRequestLike, MCPServerLike } from '../types'
|
|
8
7
|
import { MCPAnalyticsEventType } from './event-types'
|
|
9
8
|
import { getServerTrackingData } from './internal'
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
handleInitializeRequest,
|
|
14
13
|
handleListToolsRequest,
|
|
15
14
|
patchRequestHandlers,
|
|
15
|
+
registerFallbackRequestHandler,
|
|
16
16
|
captureToolCall,
|
|
17
17
|
isToolAdvertised,
|
|
18
18
|
type HandlerPatch,
|
|
@@ -34,23 +34,23 @@ export function instrumentLowLevelServer(server: MCPServerLike, logger: LoggerFn
|
|
|
34
34
|
try {
|
|
35
35
|
// Patch already existing handlers, and patch setRequestHandler to capture dynamically created handlers.
|
|
36
36
|
const hadCallToolHandler = server._requestHandlers.has('tools/call')
|
|
37
|
+
const traceToolCall: HandlerPatch = (server, originalHandler, request, extra) =>
|
|
38
|
+
handleToolCallRequest(server, originalHandler, request, extra, logger)
|
|
37
39
|
const handlers: Record<string, HandlerPatch> = {
|
|
38
40
|
initialize: (server, originalHandler, request, extra) =>
|
|
39
41
|
handleInitializeRequest(server, originalHandler, request, extra, logger),
|
|
40
42
|
'tools/list': (server, originalHandler, request, extra) =>
|
|
41
43
|
handleListToolsRequest(server, originalHandler, request, extra, logger),
|
|
42
|
-
'tools/call':
|
|
43
|
-
handleToolCallRequest(server, originalHandler, request, extra, logger),
|
|
44
|
+
'tools/call': traceToolCall,
|
|
44
45
|
}
|
|
45
46
|
patchRequestHandlers(server, handlers)
|
|
46
47
|
|
|
47
48
|
if (!hadCallToolHandler) {
|
|
48
|
-
// Register a raw fallback
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
49
|
+
// Register a raw fallback so reportMissing works even before an application
|
|
50
|
+
// dispatcher is attached. A later registration replaces it and is wrapped by
|
|
51
|
+
// the patched setRequestHandler. Written into the handler map directly — see
|
|
52
|
+
// registerFallbackRequestHandler for why the SDK setter is the wrong door.
|
|
53
|
+
registerFallbackRequestHandler(server, 'tools/call', unknownToolHandler, traceToolCall)
|
|
54
54
|
}
|
|
55
55
|
} catch (error) {
|
|
56
56
|
logger(`Warning: Failed to setup tool call instrumentation - ${error}`)
|
|
@@ -58,6 +58,11 @@ export function instrumentLowLevelServer(server: MCPServerLike, logger: LoggerFn
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/** Stands in for an application dispatcher that has not been attached yet. */
|
|
62
|
+
async function unknownToolHandler(request: MCPRequestLike): Promise<never> {
|
|
63
|
+
throw new Error(`Unknown tool: ${request.params?.name || 'unknown'}`)
|
|
64
|
+
}
|
|
65
|
+
|
|
61
66
|
async function handleToolCallRequest(
|
|
62
67
|
server: MCPServerLike,
|
|
63
68
|
originalCallToolHandler: MCPRequestHandler | undefined,
|