@posthog/mcp 0.11.0 → 0.11.2
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 +39 -0
- package/dist/extensions/client-identity.d.ts +70 -15
- package/dist/extensions/client-identity.d.ts.map +1 -1
- package/dist/extensions/client-identity.js +72 -17
- package/dist/extensions/client-identity.mjs +59 -13
- package/dist/extensions/compatibility.d.ts.map +1 -1
- package/dist/extensions/compatibility.js +14 -18
- package/dist/extensions/compatibility.mjs +10 -14
- package/dist/extensions/detect.d.ts +51 -0
- package/dist/extensions/detect.d.ts.map +1 -0
- package/dist/extensions/detect.js +96 -0
- package/dist/extensions/detect.mjs +38 -0
- package/dist/extensions/instrument-highlevel.d.ts.map +1 -1
- package/dist/extensions/instrumentation.d.ts +4 -5
- package/dist/extensions/instrumentation.d.ts.map +1 -1
- package/dist/extensions/instrumentation.js +6 -5
- package/dist/extensions/instrumentation.mjs +7 -6
- package/dist/extensions/internal.js +1 -1
- package/dist/extensions/internal.mjs +2 -2
- package/dist/extensions/request-headers.d.ts +36 -0
- package/dist/extensions/request-headers.d.ts.map +1 -0
- package/dist/extensions/request-headers.js +62 -0
- package/dist/extensions/request-headers.mjs +28 -0
- package/dist/extensions/session.d.ts.map +1 -1
- package/dist/extensions/session.js +2 -1
- package/dist/extensions/session.mjs +2 -1
- package/dist/extensions/tools.d.ts +4 -4
- package/dist/extensions/tools.d.ts.map +1 -1
- package/dist/extensions/transport-identity.d.ts +8 -3
- package/dist/extensions/transport-identity.d.ts.map +1 -1
- package/dist/extensions/transport-identity.js +2 -1
- package/dist/extensions/transport-identity.mjs +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -7
- package/dist/index.mjs +2 -1
- package/dist/types.d.ts +77 -2
- 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 +12 -2
- package/src/extensions/client-identity.ts +146 -31
- package/src/extensions/compatibility.ts +25 -24
- package/src/extensions/detect.ts +87 -0
- package/src/extensions/instrument-highlevel.ts +4 -4
- package/src/extensions/instrumentation.ts +22 -15
- package/src/extensions/internal.ts +2 -2
- package/src/extensions/request-headers.ts +76 -0
- package/src/extensions/session.ts +2 -1
- package/src/extensions/tools.ts +4 -4
- package/src/extensions/transport-identity.ts +10 -4
- package/src/index.ts +4 -0
- package/src/types.ts +78 -3
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -67,6 +67,45 @@ if (body?.method === 'initialize' && !req.headers[MCP_SESSION_HEADER]) {
|
|
|
67
67
|
|
|
68
68
|
Details: [docs/ARCHITECTURE.md §4](./docs/ARCHITECTURE.md).
|
|
69
69
|
|
|
70
|
+
## MCP TypeScript SDK v2
|
|
71
|
+
|
|
72
|
+
`instrument()` works on both SDK majors — `@modelcontextprotocol/sdk` v1 and
|
|
73
|
+
`@modelcontextprotocol/{core,server,client}` v2 — and on both the high-level `McpServer` and the
|
|
74
|
+
low-level `Server`. Shapes are detected at runtime, so neither major is a dependency here.
|
|
75
|
+
|
|
76
|
+
### Reading request headers in a callback
|
|
77
|
+
|
|
78
|
+
If your `identify`, `intentFallback`, `eventProperties` or `beforeSend` reads HTTP headers, it has
|
|
79
|
+
to change. The two majors put the request in different places and in different shapes: v1 attaches
|
|
80
|
+
a plain object at `extra.requestInfo.headers`, v2 attaches the WHATWG `Request` at `extra.http.req`,
|
|
81
|
+
whose `headers` only answers to `.get()`. A v1-shaped read returns `undefined` on v2 — an
|
|
82
|
+
`identify()` written that way returns `null` and every event goes anonymous.
|
|
83
|
+
|
|
84
|
+
The SDK hands your callback whatever the MCP SDK handed it, unchanged; it does **not** fake a v1
|
|
85
|
+
shape on v2, because a partially synthesised `requestInfo` is a more convincing lie than an absent
|
|
86
|
+
one. Read headers through the exported helper instead, which handles both majors, lowercases keys,
|
|
87
|
+
and duck-types `Headers` so it also works on edge runtimes:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { getRequestHeaders } from '@posthog/mcp'
|
|
91
|
+
|
|
92
|
+
identify: async (request, extra) => {
|
|
93
|
+
const auth = getRequestHeaders(extra)?.['authorization'] // v1 and v2
|
|
94
|
+
// ...
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### If you switched to `instrument(server.server)`
|
|
99
|
+
|
|
100
|
+
Before v2 support landed, the compatibility gate rejected high-level v2 servers, and the usual
|
|
101
|
+
workaround was to instrument the underlying low-level server. `instrument(server)` now works, so
|
|
102
|
+
you can go back to the documented call.
|
|
103
|
+
|
|
104
|
+
Whether the workaround costs you anything depends on your stack: instrumenting the low-level server
|
|
105
|
+
skips the high-level tool registry, so tool descriptions and callback-level wrapping come only from
|
|
106
|
+
what is advertised over `tools/list`. If your framework never calls `registerTool()` — `@rekog/mcp-nest`
|
|
107
|
+
does not — the registry is empty and the two calls behave the same.
|
|
108
|
+
|
|
70
109
|
## Developing locally
|
|
71
110
|
|
|
72
111
|
To test local changes in a consumer app (e.g. a dummy MCP server), symlink **both**
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
import type { McpEvent, MCPRequestLike } from '../types';
|
|
1
|
+
import type { CompatibleRequestHandlerExtra, McpEvent, MCPRequestLike, MCPServerLike } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Client identity
|
|
3
|
+
* Client identity — who is calling, and which spec revision they speak.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* of
|
|
5
|
+
* Where it lives depends on the revision the *request* declares, so this is a
|
|
6
|
+
* fallback chain and never a branch: one server serves both eras, request by
|
|
7
|
+
* request.
|
|
8
|
+
*
|
|
9
|
+
* 1. `ctx.mcpReq.envelope` — MCP SDK v2 lifts the reserved
|
|
10
|
+
* `io.modelcontextprotocol/*` keys out of `_meta` before dispatch, so by
|
|
11
|
+
* the time a handler runs they are here and `params._meta` is empty.
|
|
12
|
+
* 2. `request.params._meta` — where 2026-07-28 puts them on the wire, and
|
|
13
|
+
* where they still are on any server that does not lift them.
|
|
14
|
+
* 3. the server's own accessors — `getClientVersion()` from a legacy
|
|
15
|
+
* `initialize` handshake, `getNegotiatedProtocolVersion()` on v2.
|
|
16
|
+
*
|
|
17
|
+
* The 2026-07-28 revision removed the `initialize` handshake and the
|
|
18
|
+
* `Mcp-Session-Id` header (SEP-2575 / SEP-2567), so client name/version and the
|
|
19
|
+
* protocol version no longer arrive once per connection — they travel with
|
|
20
|
+
* every request. The key strings are mirrored here rather than imported,
|
|
21
|
+
* because no `@modelcontextprotocol/*` package is a dependency of this one.
|
|
11
22
|
*/
|
|
12
23
|
export declare const META_CLIENT_INFO_KEY = "io.modelcontextprotocol/clientInfo";
|
|
13
24
|
export declare const META_PROTOCOL_VERSION_KEY = "io.modelcontextprotocol/protocolVersion";
|
|
@@ -16,6 +27,18 @@ export interface MetaClientInfo {
|
|
|
16
27
|
clientVersion?: string;
|
|
17
28
|
protocolVersion?: string;
|
|
18
29
|
}
|
|
30
|
+
/** Everything a request can be asked about who is calling. */
|
|
31
|
+
export interface ClientIdentitySources {
|
|
32
|
+
request: MCPRequestLike;
|
|
33
|
+
extra?: CompatibleRequestHandlerExtra;
|
|
34
|
+
/**
|
|
35
|
+
* Typed `unknown` on purpose: every accessor on it is reached through a
|
|
36
|
+
* structural probe, never a declared type, because the two SDK majors expose
|
|
37
|
+
* different ones. Call sites pass a real `MCPServerLike`; the shape checks
|
|
38
|
+
* here are what decide whether it can answer.
|
|
39
|
+
*/
|
|
40
|
+
server?: unknown;
|
|
41
|
+
}
|
|
19
42
|
/**
|
|
20
43
|
* Reads the client name/version and protocol version a modern client puts in
|
|
21
44
|
* `params._meta`. Returns `undefined` when the request carries none (e.g. a
|
|
@@ -23,17 +46,49 @@ export interface MetaClientInfo {
|
|
|
23
46
|
*/
|
|
24
47
|
export declare function readMetaClientInfo(request: MCPRequestLike): MetaClientInfo | undefined;
|
|
25
48
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
49
|
+
* Reads the same keys from MCP SDK v2's request envelope. v2 strips the reserved
|
|
50
|
+
* `io.modelcontextprotocol/*` keys from `_meta` while parsing, so on exactly the
|
|
51
|
+
* traffic this matters for, `readMetaClientInfo` finds nothing and this finds
|
|
52
|
+
* everything.
|
|
53
|
+
*/
|
|
54
|
+
export declare function readEnvelopeClientInfo(extra: CompatibleRequestHandlerExtra | undefined): MetaClientInfo | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Asks the server itself. `getClientVersion()` answers on any server that
|
|
57
|
+
* handled an `initialize` (and v2 hosts such as `createMcpHandler` backfill it
|
|
58
|
+
* from the envelope); `getNegotiatedProtocolVersion()` exists on v2 only, which
|
|
59
|
+
* is why it is a link in the chain rather than a branch. Never throws — a
|
|
60
|
+
* server that dislikes being asked must not fail the tool call.
|
|
61
|
+
*/
|
|
62
|
+
export declare function readServerClientIdentity(server: unknown): MetaClientInfo | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Resolves client identity through the whole chain, field by field: the first
|
|
65
|
+
* source that answers a field wins, and a source that answers nothing simply
|
|
66
|
+
* does not participate. Field-by-field rather than source-by-source because a
|
|
67
|
+
* request may carry its protocol version in the envelope while the client's
|
|
68
|
+
* name is only known to the server from a handshake.
|
|
69
|
+
*
|
|
70
|
+
* The first three links are **per request**, so they cannot describe anyone but
|
|
71
|
+
* the caller. Only the last — the server's own accessors — is connection-scoped,
|
|
72
|
+
* and on a server that multiplexes several clients through one connection it
|
|
73
|
+
* answers for whichever client completed the handshake. That is the best answer
|
|
74
|
+
* available on that connection, and it is the same scope `capture.ts` has always
|
|
75
|
+
* fallen back to (`eventInput.clientName ?? sessionInfo.clientName`), so the
|
|
76
|
+
* chain neither introduces that sharing nor widens it. Ordering it last is what
|
|
77
|
+
* keeps it a fallback: any request that identifies itself wins outright.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveClientIdentity({ request, extra, server }: ClientIdentitySources): MetaClientInfo | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Stamps whatever the chain resolved onto the event being built for *this*
|
|
82
|
+
* request, so it carries `$mcp_client_name`, `$mcp_client_version` and
|
|
83
|
+
* `$mcp_protocol_version` even when there was no `initialize` to learn them
|
|
84
|
+
* from (the modern stateless case).
|
|
30
85
|
*
|
|
31
86
|
* Writing to the event — a per-request object — rather than the server-wide
|
|
32
87
|
* `sessionInfo` keeps identity correct when one instrumented server multiplexes
|
|
33
88
|
* concurrent requests from different clients (which the stateless spec allows):
|
|
34
89
|
* a sibling request can't clobber this event's attribution between now and when
|
|
35
|
-
* it's captured. Only fields
|
|
36
|
-
*
|
|
90
|
+
* it's captured. Only fields actually resolved are set, so a request that
|
|
91
|
+
* carries nothing leaves the event's existing values untouched.
|
|
37
92
|
*/
|
|
38
|
-
export declare function
|
|
93
|
+
export declare function stampClientIdentity(event: McpEvent, request: MCPRequestLike, extra?: CompatibleRequestHandlerExtra, server?: MCPServerLike): void;
|
|
39
94
|
//# sourceMappingURL=client-identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-identity.d.ts","sourceRoot":"","sources":["../../src/extensions/client-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"client-identity.d.ts","sourceRoot":"","sources":["../../src/extensions/client-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGtG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB,uCAAuC,CAAA;AACxE,eAAO,MAAM,yBAAyB,4CAA4C,CAAA;AAElF,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,CAAC,EAAE,6BAA6B,CAAA;IACrC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAuCD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,GAAG,SAAS,CAEtF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,6BAA6B,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAEnH;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAsBpF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,qBAAqB,GAAG,cAAc,GAAG,SAAS,CAYnH;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,EACrC,MAAM,CAAC,EAAE,aAAa,GACrB,IAAI,CAcN"}
|
|
@@ -24,30 +24,79 @@ var __webpack_require__ = {};
|
|
|
24
24
|
var __webpack_exports__ = {};
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
-
|
|
28
|
-
META_PROTOCOL_VERSION_KEY: ()=>META_PROTOCOL_VERSION_KEY,
|
|
27
|
+
resolveClientIdentity: ()=>resolveClientIdentity,
|
|
29
28
|
readMetaClientInfo: ()=>readMetaClientInfo,
|
|
30
|
-
|
|
29
|
+
readServerClientIdentity: ()=>readServerClientIdentity,
|
|
30
|
+
readEnvelopeClientInfo: ()=>readEnvelopeClientInfo,
|
|
31
|
+
META_PROTOCOL_VERSION_KEY: ()=>META_PROTOCOL_VERSION_KEY,
|
|
32
|
+
stampClientIdentity: ()=>stampClientIdentity,
|
|
33
|
+
META_CLIENT_INFO_KEY: ()=>META_CLIENT_INFO_KEY
|
|
31
34
|
});
|
|
35
|
+
const external_detect_js_namespaceObject = require("./detect.js");
|
|
32
36
|
const META_CLIENT_INFO_KEY = 'io.modelcontextprotocol/clientInfo';
|
|
33
37
|
const META_PROTOCOL_VERSION_KEY = 'io.modelcontextprotocol/protocolVersion';
|
|
38
|
+
function nonEmptyString(value) {
|
|
39
|
+
return 'string' == typeof value && value.length > 0 ? value : void 0;
|
|
40
|
+
}
|
|
41
|
+
function readClientInfoValue(value) {
|
|
42
|
+
if (!value || 'object' != typeof value) return;
|
|
43
|
+
const { name, version } = value;
|
|
44
|
+
const result = {};
|
|
45
|
+
const clientName = nonEmptyString(name);
|
|
46
|
+
const clientVersion = nonEmptyString(version);
|
|
47
|
+
if (clientName) result.clientName = clientName;
|
|
48
|
+
if (clientVersion) result.clientVersion = clientVersion;
|
|
49
|
+
return result.clientName || result.clientVersion ? result : void 0;
|
|
50
|
+
}
|
|
51
|
+
function readReservedKeys(bag) {
|
|
52
|
+
if (!bag || 'object' != typeof bag) return;
|
|
53
|
+
const record = bag;
|
|
54
|
+
const result = {
|
|
55
|
+
...readClientInfoValue(record[META_CLIENT_INFO_KEY])
|
|
56
|
+
};
|
|
57
|
+
const protocolVersion = nonEmptyString(record[META_PROTOCOL_VERSION_KEY]);
|
|
58
|
+
if (protocolVersion) result.protocolVersion = protocolVersion;
|
|
59
|
+
return result.clientName || result.clientVersion || result.protocolVersion ? result : void 0;
|
|
60
|
+
}
|
|
34
61
|
function readMetaClientInfo(request) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
62
|
+
return readReservedKeys(request.params?._meta);
|
|
63
|
+
}
|
|
64
|
+
function readEnvelopeClientInfo(extra) {
|
|
65
|
+
return readReservedKeys(extra?.mcpReq?.envelope);
|
|
66
|
+
}
|
|
67
|
+
function readServerClientIdentity(server) {
|
|
68
|
+
if (!server) return;
|
|
69
|
+
const result = {};
|
|
70
|
+
try {
|
|
71
|
+
if ((0, external_detect_js_namespaceObject.hasClientVersionAccessor)(server)) Object.assign(result, readClientInfoValue(server.getClientVersion()));
|
|
72
|
+
if ((0, external_detect_js_namespaceObject.hasNegotiatedProtocolVersionAccessor)(server)) {
|
|
73
|
+
const negotiated = server.getNegotiatedProtocolVersion();
|
|
74
|
+
const protocolVersion = nonEmptyString(negotiated);
|
|
75
|
+
if (protocolVersion) result.protocolVersion = protocolVersion;
|
|
76
|
+
}
|
|
77
|
+
} catch {}
|
|
78
|
+
return result.clientName || result.clientVersion || result.protocolVersion ? result : void 0;
|
|
79
|
+
}
|
|
80
|
+
function resolveClientIdentity({ request, extra, server }) {
|
|
81
|
+
const chain = [
|
|
82
|
+
readEnvelopeClientInfo(extra),
|
|
83
|
+
readMetaClientInfo(request),
|
|
84
|
+
readServerClientIdentity(server)
|
|
85
|
+
];
|
|
38
86
|
const result = {};
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if ('string' == typeof version && version.length > 0) result.clientVersion = version;
|
|
87
|
+
for (const source of chain)if (source) {
|
|
88
|
+
result.clientName ??= source.clientName;
|
|
89
|
+
result.clientVersion ??= source.clientVersion;
|
|
90
|
+
result.protocolVersion ??= source.protocolVersion;
|
|
44
91
|
}
|
|
45
|
-
const protocolVersion = record[META_PROTOCOL_VERSION_KEY];
|
|
46
|
-
if ('string' == typeof protocolVersion && protocolVersion.length > 0) result.protocolVersion = protocolVersion;
|
|
47
92
|
return result.clientName || result.clientVersion || result.protocolVersion ? result : void 0;
|
|
48
93
|
}
|
|
49
|
-
function
|
|
50
|
-
const info =
|
|
94
|
+
function stampClientIdentity(event, request, extra, server) {
|
|
95
|
+
const info = resolveClientIdentity({
|
|
96
|
+
request,
|
|
97
|
+
extra,
|
|
98
|
+
server
|
|
99
|
+
});
|
|
51
100
|
if (!info) return;
|
|
52
101
|
if (info.clientName) event.clientName = info.clientName;
|
|
53
102
|
if (info.clientVersion) event.clientVersion = info.clientVersion;
|
|
@@ -55,13 +104,19 @@ function stampMetaClientInfo(event, request) {
|
|
|
55
104
|
}
|
|
56
105
|
exports.META_CLIENT_INFO_KEY = __webpack_exports__.META_CLIENT_INFO_KEY;
|
|
57
106
|
exports.META_PROTOCOL_VERSION_KEY = __webpack_exports__.META_PROTOCOL_VERSION_KEY;
|
|
107
|
+
exports.readEnvelopeClientInfo = __webpack_exports__.readEnvelopeClientInfo;
|
|
58
108
|
exports.readMetaClientInfo = __webpack_exports__.readMetaClientInfo;
|
|
59
|
-
exports.
|
|
109
|
+
exports.readServerClientIdentity = __webpack_exports__.readServerClientIdentity;
|
|
110
|
+
exports.resolveClientIdentity = __webpack_exports__.resolveClientIdentity;
|
|
111
|
+
exports.stampClientIdentity = __webpack_exports__.stampClientIdentity;
|
|
60
112
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
61
113
|
"META_CLIENT_INFO_KEY",
|
|
62
114
|
"META_PROTOCOL_VERSION_KEY",
|
|
115
|
+
"readEnvelopeClientInfo",
|
|
63
116
|
"readMetaClientInfo",
|
|
64
|
-
"
|
|
117
|
+
"readServerClientIdentity",
|
|
118
|
+
"resolveClientIdentity",
|
|
119
|
+
"stampClientIdentity"
|
|
65
120
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
66
121
|
Object.defineProperty(exports, '__esModule', {
|
|
67
122
|
value: true
|
|
@@ -1,25 +1,71 @@
|
|
|
1
|
+
import { hasClientVersionAccessor, hasNegotiatedProtocolVersionAccessor } from "./detect.mjs";
|
|
1
2
|
const META_CLIENT_INFO_KEY = 'io.modelcontextprotocol/clientInfo';
|
|
2
3
|
const META_PROTOCOL_VERSION_KEY = 'io.modelcontextprotocol/protocolVersion';
|
|
4
|
+
function nonEmptyString(value) {
|
|
5
|
+
return 'string' == typeof value && value.length > 0 ? value : void 0;
|
|
6
|
+
}
|
|
7
|
+
function readClientInfoValue(value) {
|
|
8
|
+
if (!value || 'object' != typeof value) return;
|
|
9
|
+
const { name, version } = value;
|
|
10
|
+
const result = {};
|
|
11
|
+
const clientName = nonEmptyString(name);
|
|
12
|
+
const clientVersion = nonEmptyString(version);
|
|
13
|
+
if (clientName) result.clientName = clientName;
|
|
14
|
+
if (clientVersion) result.clientVersion = clientVersion;
|
|
15
|
+
return result.clientName || result.clientVersion ? result : void 0;
|
|
16
|
+
}
|
|
17
|
+
function readReservedKeys(bag) {
|
|
18
|
+
if (!bag || 'object' != typeof bag) return;
|
|
19
|
+
const record = bag;
|
|
20
|
+
const result = {
|
|
21
|
+
...readClientInfoValue(record[META_CLIENT_INFO_KEY])
|
|
22
|
+
};
|
|
23
|
+
const protocolVersion = nonEmptyString(record[META_PROTOCOL_VERSION_KEY]);
|
|
24
|
+
if (protocolVersion) result.protocolVersion = protocolVersion;
|
|
25
|
+
return result.clientName || result.clientVersion || result.protocolVersion ? result : void 0;
|
|
26
|
+
}
|
|
3
27
|
function readMetaClientInfo(request) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
28
|
+
return readReservedKeys(request.params?._meta);
|
|
29
|
+
}
|
|
30
|
+
function readEnvelopeClientInfo(extra) {
|
|
31
|
+
return readReservedKeys(extra?.mcpReq?.envelope);
|
|
32
|
+
}
|
|
33
|
+
function readServerClientIdentity(server) {
|
|
34
|
+
if (!server) return;
|
|
35
|
+
const result = {};
|
|
36
|
+
try {
|
|
37
|
+
if (hasClientVersionAccessor(server)) Object.assign(result, readClientInfoValue(server.getClientVersion()));
|
|
38
|
+
if (hasNegotiatedProtocolVersionAccessor(server)) {
|
|
39
|
+
const negotiated = server.getNegotiatedProtocolVersion();
|
|
40
|
+
const protocolVersion = nonEmptyString(negotiated);
|
|
41
|
+
if (protocolVersion) result.protocolVersion = protocolVersion;
|
|
42
|
+
}
|
|
43
|
+
} catch {}
|
|
44
|
+
return result.clientName || result.clientVersion || result.protocolVersion ? result : void 0;
|
|
45
|
+
}
|
|
46
|
+
function resolveClientIdentity({ request, extra, server }) {
|
|
47
|
+
const chain = [
|
|
48
|
+
readEnvelopeClientInfo(extra),
|
|
49
|
+
readMetaClientInfo(request),
|
|
50
|
+
readServerClientIdentity(server)
|
|
51
|
+
];
|
|
7
52
|
const result = {};
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if ('string' == typeof version && version.length > 0) result.clientVersion = version;
|
|
53
|
+
for (const source of chain)if (source) {
|
|
54
|
+
result.clientName ??= source.clientName;
|
|
55
|
+
result.clientVersion ??= source.clientVersion;
|
|
56
|
+
result.protocolVersion ??= source.protocolVersion;
|
|
13
57
|
}
|
|
14
|
-
const protocolVersion = record[META_PROTOCOL_VERSION_KEY];
|
|
15
|
-
if ('string' == typeof protocolVersion && protocolVersion.length > 0) result.protocolVersion = protocolVersion;
|
|
16
58
|
return result.clientName || result.clientVersion || result.protocolVersion ? result : void 0;
|
|
17
59
|
}
|
|
18
|
-
function
|
|
19
|
-
const info =
|
|
60
|
+
function stampClientIdentity(event, request, extra, server) {
|
|
61
|
+
const info = resolveClientIdentity({
|
|
62
|
+
request,
|
|
63
|
+
extra,
|
|
64
|
+
server
|
|
65
|
+
});
|
|
20
66
|
if (!info) return;
|
|
21
67
|
if (info.clientName) event.clientName = info.clientName;
|
|
22
68
|
if (info.clientVersion) event.clientVersion = info.clientVersion;
|
|
23
69
|
if (info.protocolVersion) event.protocolVersion = info.protocolVersion;
|
|
24
70
|
}
|
|
25
|
-
export { META_CLIENT_INFO_KEY, META_PROTOCOL_VERSION_KEY, readMetaClientInfo,
|
|
71
|
+
export { META_CLIENT_INFO_KEY, META_PROTOCOL_VERSION_KEY, readEnvelopeClientInfo, readMetaClientInfo, readServerClientIdentity, resolveClientIdentity, stampClientIdentity };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/extensions/compatibility.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/extensions/compatibility.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAWrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE3C;;;;;;;;;;;GAWG;AAEH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAI9D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,GAAG;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAEpG;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,CAExE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAG,aAAa,GAAG,sBAAsB,CAiChH;AAyCD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAanE"}
|
|
@@ -24,20 +24,21 @@ var __webpack_require__ = {};
|
|
|
24
24
|
var __webpack_exports__ = {};
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
-
getMCPCompatibleErrorMessage: ()=>getMCPCompatibleErrorMessage,
|
|
28
|
-
isCompatibleServerType: ()=>isCompatibleServerType,
|
|
29
|
-
isHighLevelServer: ()=>isHighLevelServer,
|
|
30
27
|
isLowLevelServer: ()=>isLowLevelServer,
|
|
31
|
-
|
|
28
|
+
isHighLevelServer: ()=>isHighLevelServer,
|
|
29
|
+
logCompatibilityWarning: ()=>logCompatibilityWarning,
|
|
30
|
+
isCompatibleServerType: ()=>isCompatibleServerType,
|
|
31
|
+
getMCPCompatibleErrorMessage: ()=>getMCPCompatibleErrorMessage
|
|
32
32
|
});
|
|
33
|
+
const external_detect_js_namespaceObject = require("./detect.js");
|
|
33
34
|
function logCompatibilityWarning(logger) {
|
|
34
35
|
logger('PostHog MCP analytics SDK Compatibility: This version only supports Model Context Protocol TypeScript SDK v1.11 and above. Please upgrade if using an older version.');
|
|
35
36
|
}
|
|
36
37
|
function isHighLevelServer(server) {
|
|
37
|
-
return
|
|
38
|
+
return (0, external_detect_js_namespaceObject.hasNestedLowLevelServer)(server);
|
|
38
39
|
}
|
|
39
40
|
function isLowLevelServer(server) {
|
|
40
|
-
return
|
|
41
|
+
return (0, external_detect_js_namespaceObject.isBareServerShape)(server);
|
|
41
42
|
}
|
|
42
43
|
function isCompatibleServerType(server, logger) {
|
|
43
44
|
if (!server || 'object' != typeof server) {
|
|
@@ -45,13 +46,13 @@ function isCompatibleServerType(server, logger) {
|
|
|
45
46
|
throw new Error("PostHog MCP analytics SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher.");
|
|
46
47
|
}
|
|
47
48
|
if (isHighLevelServer(server)) {
|
|
48
|
-
if (!
|
|
49
|
+
if (!(0, external_detect_js_namespaceObject.hasToolRegistry)(server)) {
|
|
49
50
|
logCompatibilityWarning(logger);
|
|
50
51
|
throw new Error('PostHog MCP analytics SDK compatibility error: High-level server must have _registeredTools object. This requires MCP SDK v1.11 or higher.');
|
|
51
52
|
}
|
|
52
|
-
if (
|
|
53
|
+
if (!(0, external_detect_js_namespaceObject.canRegisterTools)(server)) {
|
|
53
54
|
logCompatibilityWarning(logger);
|
|
54
|
-
throw new Error('PostHog MCP analytics SDK compatibility error: High-level server must have tool() method. This requires MCP SDK v1.11 or higher.');
|
|
55
|
+
throw new Error('PostHog MCP analytics SDK compatibility error: High-level server must have a registerTool() or tool() method. This requires MCP SDK v1.11 or higher.');
|
|
55
56
|
}
|
|
56
57
|
const targetServer = server.server;
|
|
57
58
|
validateLowLevelServer(targetServer, logger);
|
|
@@ -65,24 +66,19 @@ function validateLowLevelServer(server, logger) {
|
|
|
65
66
|
logCompatibilityWarning(logger);
|
|
66
67
|
throw new Error("PostHog MCP analytics SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher.");
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
-
if ('function' != typeof serverRecord.setRequestHandler) {
|
|
69
|
+
if (!(0, external_detect_js_namespaceObject.canSetRequestHandler)(server)) {
|
|
70
70
|
logCompatibilityWarning(logger);
|
|
71
71
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server must have a setRequestHandler method. This requires MCP SDK v1.11 or higher.');
|
|
72
72
|
}
|
|
73
|
-
if (!(
|
|
73
|
+
if (!(0, external_detect_js_namespaceObject.hasRequestHandlerMap)(server)) {
|
|
74
74
|
logCompatibilityWarning(logger);
|
|
75
75
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server._requestHandlers is not accessible. This requires MCP SDK v1.11 or higher.');
|
|
76
76
|
}
|
|
77
|
-
if (
|
|
78
|
-
logCompatibilityWarning(logger);
|
|
79
|
-
throw new Error('PostHog MCP analytics SDK compatibility error: Server._requestHandlers must be a Map with a get method. This requires MCP SDK v1.11 or higher.');
|
|
80
|
-
}
|
|
81
|
-
if ('function' != typeof serverRecord.getClientVersion) {
|
|
77
|
+
if (!(0, external_detect_js_namespaceObject.hasClientVersionAccessor)(server)) {
|
|
82
78
|
logCompatibilityWarning(logger);
|
|
83
79
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server.getClientVersion must be a function. This requires MCP SDK v1.11 or higher.');
|
|
84
80
|
}
|
|
85
|
-
if (!
|
|
81
|
+
if (!(0, external_detect_js_namespaceObject.hasServerInfo)(server)) {
|
|
86
82
|
logCompatibilityWarning(logger);
|
|
87
83
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server._serverInfo is not accessible or missing name. This requires MCP SDK v1.11 or higher.');
|
|
88
84
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { canRegisterTools, canSetRequestHandler, hasClientVersionAccessor, hasNestedLowLevelServer, hasRequestHandlerMap, hasServerInfo, hasToolRegistry, isBareServerShape } from "./detect.mjs";
|
|
1
2
|
function logCompatibilityWarning(logger) {
|
|
2
3
|
logger('PostHog MCP analytics SDK Compatibility: This version only supports Model Context Protocol TypeScript SDK v1.11 and above. Please upgrade if using an older version.');
|
|
3
4
|
}
|
|
4
5
|
function isHighLevelServer(server) {
|
|
5
|
-
return
|
|
6
|
+
return hasNestedLowLevelServer(server);
|
|
6
7
|
}
|
|
7
8
|
function isLowLevelServer(server) {
|
|
8
|
-
return
|
|
9
|
+
return isBareServerShape(server);
|
|
9
10
|
}
|
|
10
11
|
function isCompatibleServerType(server, logger) {
|
|
11
12
|
if (!server || 'object' != typeof server) {
|
|
@@ -13,13 +14,13 @@ function isCompatibleServerType(server, logger) {
|
|
|
13
14
|
throw new Error("PostHog MCP analytics SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher.");
|
|
14
15
|
}
|
|
15
16
|
if (isHighLevelServer(server)) {
|
|
16
|
-
if (!server
|
|
17
|
+
if (!hasToolRegistry(server)) {
|
|
17
18
|
logCompatibilityWarning(logger);
|
|
18
19
|
throw new Error('PostHog MCP analytics SDK compatibility error: High-level server must have _registeredTools object. This requires MCP SDK v1.11 or higher.');
|
|
19
20
|
}
|
|
20
|
-
if (
|
|
21
|
+
if (!canRegisterTools(server)) {
|
|
21
22
|
logCompatibilityWarning(logger);
|
|
22
|
-
throw new Error('PostHog MCP analytics SDK compatibility error: High-level server must have tool() method. This requires MCP SDK v1.11 or higher.');
|
|
23
|
+
throw new Error('PostHog MCP analytics SDK compatibility error: High-level server must have a registerTool() or tool() method. This requires MCP SDK v1.11 or higher.');
|
|
23
24
|
}
|
|
24
25
|
const targetServer = server.server;
|
|
25
26
|
validateLowLevelServer(targetServer, logger);
|
|
@@ -33,24 +34,19 @@ function validateLowLevelServer(server, logger) {
|
|
|
33
34
|
logCompatibilityWarning(logger);
|
|
34
35
|
throw new Error("PostHog MCP analytics SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher.");
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
-
if ('function' != typeof serverRecord.setRequestHandler) {
|
|
37
|
+
if (!canSetRequestHandler(server)) {
|
|
38
38
|
logCompatibilityWarning(logger);
|
|
39
39
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server must have a setRequestHandler method. This requires MCP SDK v1.11 or higher.');
|
|
40
40
|
}
|
|
41
|
-
if (!(
|
|
41
|
+
if (!hasRequestHandlerMap(server)) {
|
|
42
42
|
logCompatibilityWarning(logger);
|
|
43
43
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server._requestHandlers is not accessible. This requires MCP SDK v1.11 or higher.');
|
|
44
44
|
}
|
|
45
|
-
if (
|
|
46
|
-
logCompatibilityWarning(logger);
|
|
47
|
-
throw new Error('PostHog MCP analytics SDK compatibility error: Server._requestHandlers must be a Map with a get method. This requires MCP SDK v1.11 or higher.');
|
|
48
|
-
}
|
|
49
|
-
if ('function' != typeof serverRecord.getClientVersion) {
|
|
45
|
+
if (!hasClientVersionAccessor(server)) {
|
|
50
46
|
logCompatibilityWarning(logger);
|
|
51
47
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server.getClientVersion must be a function. This requires MCP SDK v1.11 or higher.');
|
|
52
48
|
}
|
|
53
|
-
if (!
|
|
49
|
+
if (!hasServerInfo(server)) {
|
|
54
50
|
logCompatibilityWarning(logger);
|
|
55
51
|
throw new Error('PostHog MCP analytics SDK compatibility error: Server._serverInfo is not accessible or missing name. This requires MCP SDK v1.11 or higher.');
|
|
56
52
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural feature probes.
|
|
3
|
+
*
|
|
4
|
+
* Every question about the shape of a server object is answered here, by
|
|
5
|
+
* duck-typing the object in front of us — never by reading a package version or
|
|
6
|
+
* a protocol constant. Two reasons this is a rule and not a preference:
|
|
7
|
+
*
|
|
8
|
+
* - The two SDK majors expose the same capability under different names (v1's
|
|
9
|
+
* `.tool()` vs v2's `.registerTool()`), so "which SDK is installed" answers a
|
|
10
|
+
* different question than "can this object register a tool".
|
|
11
|
+
* - A single v2 server serves both protocol eras, request by request, so no
|
|
12
|
+
* module-level constant describes it. v2's exported `LATEST_PROTOCOL_VERSION`
|
|
13
|
+
* is `2025-11-25`.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here imports `@modelcontextprotocol/*`; that boundary is pinned by
|
|
16
|
+
* `sdk-import-boundary.test.ts`.
|
|
17
|
+
*/
|
|
18
|
+
type UnknownRecord = Record<string, unknown>;
|
|
19
|
+
/** A high-level `McpServer` wrapper: it holds the low-level server on `.server`. */
|
|
20
|
+
export declare function hasNestedLowLevelServer(server: unknown): server is UnknownRecord & {
|
|
21
|
+
server: UnknownRecord;
|
|
22
|
+
};
|
|
23
|
+
/** No `.server` property, so the object is itself the low-level `Server`. */
|
|
24
|
+
export declare function isBareServerShape(server: unknown): boolean;
|
|
25
|
+
/** The high-level registry we read tool metadata from and wrap callbacks in. */
|
|
26
|
+
export declare function hasToolRegistry(server: unknown): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The object can register a tool.
|
|
29
|
+
*
|
|
30
|
+
* v1 offers both `tool()` and `registerTool()`; v2 dropped the deprecated
|
|
31
|
+
* `tool()` and keeps only `registerTool()`. Requiring `tool()` specifically is
|
|
32
|
+
* what made `instrument()` reject every v2 high-level server — and, because
|
|
33
|
+
* `instrument()` swallows compatibility errors, reject it silently.
|
|
34
|
+
*/
|
|
35
|
+
export declare function canRegisterTools(server: unknown): boolean;
|
|
36
|
+
/** Handler registration, which we patch to wrap late registrations. */
|
|
37
|
+
export declare function canSetRequestHandler(server: unknown): boolean;
|
|
38
|
+
/** The live handler map we read and write directly. A real `Map` on both majors. */
|
|
39
|
+
export declare function hasRequestHandlerMap(server: unknown): boolean;
|
|
40
|
+
/** `getClientVersion()` — still present on v2, and a link in B1's identity chain. */
|
|
41
|
+
export declare function hasClientVersionAccessor(server: unknown): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* `getNegotiatedProtocolVersion()` — v2 only, and the last link in the protocol
|
|
44
|
+
* version chain. A v1 server does not have it, which is why the chain probes for
|
|
45
|
+
* it instead of branching on which SDK is installed.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hasNegotiatedProtocolVersionAccessor(server: unknown): boolean;
|
|
48
|
+
/** `_serverInfo`, which names the server on every event. */
|
|
49
|
+
export declare function hasServerInfo(server: unknown): boolean;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/extensions/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAU5C,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,aAAa,GAAG;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAG5G;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAG1D;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAG7D;AAED,qFAAqF;AACrF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAE7E;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAGtD"}
|