@posthog/mcp 0.8.0 → 0.9.0
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/LICENSE +2 -2
- package/README.md +51 -0
- package/dist/extensions/capture.d.ts.map +1 -1
- package/dist/extensions/compatibility.d.ts.map +1 -1
- package/dist/extensions/constants.d.ts.map +1 -1
- package/dist/extensions/context-parameters.d.ts.map +1 -1
- package/dist/extensions/conversation-id.d.ts.map +1 -1
- package/dist/extensions/event-types.d.ts.map +1 -1
- package/dist/extensions/exceptions.d.ts.map +1 -1
- package/dist/extensions/ids.d.ts.map +1 -1
- package/dist/extensions/instrument-highlevel.d.ts.map +1 -1
- package/dist/extensions/instrument-lowlevel.d.ts.map +1 -1
- package/dist/extensions/instrumentation.d.ts.map +1 -1
- package/dist/extensions/instrumentation.js +39 -3
- package/dist/extensions/instrumentation.mjs +41 -5
- package/dist/extensions/intent.d.ts.map +1 -1
- package/dist/extensions/internal.d.ts.map +1 -1
- package/dist/extensions/logger.d.ts.map +1 -1
- package/dist/extensions/mcp-payloads.d.ts.map +1 -1
- package/dist/extensions/mcp-sdk-compat.d.ts.map +1 -1
- package/dist/extensions/posthog-events.d.ts.map +1 -1
- package/dist/extensions/sanitization.d.ts.map +1 -1
- package/dist/extensions/session-token.d.ts +46 -0
- package/dist/extensions/session-token.d.ts.map +1 -0
- package/dist/extensions/session-token.js +122 -0
- package/dist/extensions/session-token.mjs +76 -0
- package/dist/extensions/session.d.ts +5 -4
- package/dist/extensions/session.d.ts.map +1 -1
- package/dist/extensions/session.js +25 -33
- package/dist/extensions/session.mjs +22 -27
- package/dist/extensions/sink.d.ts.map +1 -1
- package/dist/extensions/tools.d.ts.map +1 -1
- package/dist/extensions/tracing-helpers.d.ts.map +1 -1
- package/dist/extensions/truncation.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.mjs +2 -1
- package/dist/types.d.ts +16 -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 +4 -4
- package/src/extensions/capture.ts +4 -3
- package/src/extensions/compatibility.ts +4 -3
- package/src/extensions/constants.ts +4 -3
- package/src/extensions/context-parameters.ts +4 -3
- package/src/extensions/conversation-id.ts +4 -3
- package/src/extensions/event-types.ts +4 -3
- package/src/extensions/exceptions.ts +4 -3
- package/src/extensions/ids.ts +4 -3
- package/src/extensions/instrument-highlevel.ts +4 -3
- package/src/extensions/instrument-lowlevel.ts +4 -3
- package/src/extensions/instrumentation.ts +85 -9
- package/src/extensions/intent.ts +4 -3
- package/src/extensions/internal.ts +4 -3
- package/src/extensions/logger.ts +4 -3
- package/src/extensions/mcp-payloads.ts +4 -3
- package/src/extensions/mcp-sdk-compat.ts +4 -3
- package/src/extensions/posthog-events.ts +4 -3
- package/src/extensions/sanitization.ts +4 -3
- package/src/extensions/session-token.ts +168 -0
- package/src/extensions/session.ts +42 -40
- package/src/extensions/sink.ts +4 -3
- package/src/extensions/tools.ts +4 -3
- package/src/extensions/tracing-helpers.ts +4 -3
- package/src/extensions/truncation.ts +4 -3
- package/src/index.ts +14 -4
- package/src/types.ts +22 -5
- package/src/version.ts +1 -1
package/LICENSE
CHANGED
|
@@ -327,12 +327,12 @@ SOFTWARE.
|
|
|
327
327
|
|
|
328
328
|
---
|
|
329
329
|
|
|
330
|
-
Some files in this codebase contain code from MCPCat/mcpcat-typescript-sdk.
|
|
330
|
+
Some files in this codebase contain code from agentcathq/agentcat-typescript-sdk (formerly MCPCat/mcpcat-typescript-sdk).
|
|
331
331
|
In such cases it is explicitly stated in the file header. This license only applies to the relevant code in such cases.
|
|
332
332
|
|
|
333
333
|
MIT License
|
|
334
334
|
|
|
335
|
-
Copyright (c) 2025 MCPcat
|
|
335
|
+
Copyright (c) 2025 AgentCat, Inc. (formerly MCPcat)
|
|
336
336
|
|
|
337
337
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
338
338
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -8,6 +8,57 @@ SDK usage examples and code snippets live in the official documentation so they
|
|
|
8
8
|
|
|
9
9
|
- [MCP analytics docs](https://posthog.com/docs/mcp-analytics)
|
|
10
10
|
|
|
11
|
+
## Stateless & multi-pod servers
|
|
12
|
+
|
|
13
|
+
On stateless deployments the SDK mints the `Mcp-Session-Id` response header at `initialize`
|
|
14
|
+
as a token carrying the session id and client name/version. Clients replay the header on
|
|
15
|
+
every request, so any pod keeps `$session_id` and `$mcp_client_name`/`$mcp_client_version`
|
|
16
|
+
stable with no server-side store.
|
|
17
|
+
|
|
18
|
+
### Streamable HTTP: set `enableJsonResponse: true`
|
|
19
|
+
|
|
20
|
+
The token is minted onto the `Mcp-Session-Id` **response** header from inside the `initialize`
|
|
21
|
+
handler, so it only reaches the client when the transport builds the response **after** the
|
|
22
|
+
handler runs — i.e. **JSON mode**. In **SSE (streaming) mode** `StreamableHTTPServerTransport`
|
|
23
|
+
flushes the response headers **before** the handler runs, so the minted header never lands and
|
|
24
|
+
behavior silently falls back to a session-per-request. This is a property of the transport, so
|
|
25
|
+
it applies to **every** Streamable-HTTP host — set `enableJsonResponse: true` (and use a fresh
|
|
26
|
+
transport per request):
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// @modelcontextprotocol/sdk
|
|
30
|
+
new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true })
|
|
31
|
+
|
|
32
|
+
// Cloudflare agents / createMcpHandler (SSE is the default)
|
|
33
|
+
createMcpHandler(server, { enableJsonResponse: true })
|
|
34
|
+
|
|
35
|
+
// @rekog/mcp-nest
|
|
36
|
+
McpModule.forRoot({ streamableHttp: { enableJsonResponse: true } })
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### If you must stream (SSE)
|
|
40
|
+
|
|
41
|
+
Set the header yourself at the HTTP layer with the exported `encodeSessionId` (read `clientInfo`
|
|
42
|
+
from the `initialize` body) — the SDK decodes it either way:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { MCP_SESSION_HEADER, encodeSessionId, newSessionId } from '@posthog/mcp'
|
|
46
|
+
|
|
47
|
+
// after parsing the POST body, before flushing headers:
|
|
48
|
+
if (body?.method === 'initialize' && !req.headers[MCP_SESSION_HEADER]) {
|
|
49
|
+
res.setHeader(
|
|
50
|
+
MCP_SESSION_HEADER,
|
|
51
|
+
encodeSessionId({
|
|
52
|
+
sessionId: newSessionId(),
|
|
53
|
+
clientName: body.params?.clientInfo?.name,
|
|
54
|
+
clientVersion: body.params?.clientInfo?.version,
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Details: [docs/ARCHITECTURE.md §4](./docs/ARCHITECTURE.md).
|
|
61
|
+
|
|
11
62
|
## Developing locally
|
|
12
63
|
|
|
13
64
|
To test local changes in a consumer app (e.g. a dummy MCP server), symlink **both**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/extensions/capture.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/extensions/capture.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAMvD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CA2DnG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../../src/extensions/compatibility.ts"],"names":[],"mappings":"
|
|
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;AAGrE,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE3C;;;;;;;;;;;GAWG;AAGH,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AAGD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,GAAG;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAIpG;AAGD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,CAExE;AAGD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,aAAa,GAAG,sBAAsB,CAgC9F;AAsDD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAanE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/extensions/constants.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/extensions/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,6BAA6B,KAAK,CAAA;AAE/C,eAAO,MAAM,qCAAqC,2hBAAyhB,CAAA;AAE3kB,eAAO,MAAM,mCAAmC,4LACsI,CAAA;AAEtL,eAAO,MAAM,4BAA4B,0BAA0B,CAAA;AAMnE,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;CAY3B,CAAA;AAEV,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAA;AAE/G,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;CAqB9B,CAAA;AAEV,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,OAAO,2BAA2B,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/context-parameters.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"context-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/context-parameters.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAInD,UAAU,UAAU;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,UAAU,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,CAAC,SAAS,CAAC,GAAG,OAAO,CAEjF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAEjG;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,SAAS,qBAAqB,EAC3E,IAAI,EAAE,KAAK,EACX,0BAA0B,CAAC,EAAE,MAAM,GAClC,KAAK,CAgEP;AAED,wBAAgB,0BAA0B,CAAC,KAAK,SAAS,qBAAqB,EAC5E,KAAK,EAAE,KAAK,EAAE,EACd,0BAA0B,CAAC,EAAE,MAAM,GAClC,KAAK,EAAE,CAQT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-id.d.ts","sourceRoot":"","sources":["../../src/extensions/conversation-id.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conversation-id.d.ts","sourceRoot":"","sources":["../../src/extensions/conversation-id.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D,UAAU,UAAU;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,UAAU,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,4BAA4B,EAAE,IAAI,EAAE,KAAK,GAAG,KAAK,CA2CtG;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,4BAA4B,EACjF,KAAK,EAAE,KAAK,EAAE,EACd,yBAAyB,GAAE,MAA4B,GACtD,KAAK,EAAE,CAOT;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,yBAAyB,GAAE,MAA4B,GACtD,wBAAwB,CAS1B;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAS1E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAUvE;AAED,wBAAgB,iCAAiC,CAC/C,QAAQ,SAAS;IAAE,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CAAE,EAC3E,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAe7B;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAKA;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAS/F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-types.d.ts","sourceRoot":"","sources":["../../src/extensions/event-types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-types.d.ts","sourceRoot":"","sources":["../../src/extensions/event-types.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;CAWxB,CAAA;AAEV,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,OAAO,qBAAqB,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../../src/extensions/exceptions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../../src/extensions/exceptions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAA;AA8BlE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAAC,eAAe,CAMlF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/extensions/ids.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/extensions/ids.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,KAAK,CAAA;AAEhD,wBAAgB,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAElE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAiC,sBAAsB,EAAiC,MAAM,UAAU,CAAA;AAqPpH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAwB9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-lowlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-lowlevel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instrument-lowlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-lowlevel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAiD,aAAa,EAAE,MAAM,UAAU,CAAA;AAmB5F;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAkBpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAGd,MAAM,UAAU,CAAA;AAWjB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAYrD;;;;;;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;AAqED;;;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,CA4BlB"}
|
|
@@ -43,6 +43,7 @@ const external_logger_js_namespaceObject = require("./logger.js");
|
|
|
43
43
|
const external_mcp_payloads_js_namespaceObject = require("./mcp-payloads.js");
|
|
44
44
|
const external_mcp_sdk_compat_js_namespaceObject = require("./mcp-sdk-compat.js");
|
|
45
45
|
const external_session_js_namespaceObject = require("./session.js");
|
|
46
|
+
const external_session_token_js_namespaceObject = require("./session-token.js");
|
|
46
47
|
const external_tools_js_namespaceObject = require("./tools.js");
|
|
47
48
|
const external_tracing_helpers_js_namespaceObject = require("./tracing-helpers.js");
|
|
48
49
|
async function captureToolCall(params) {
|
|
@@ -65,7 +66,7 @@ async function captureToolCall(params) {
|
|
|
65
66
|
}
|
|
66
67
|
async function prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, eventType) {
|
|
67
68
|
try {
|
|
68
|
-
const sessionId = (0, external_session_js_namespaceObject.
|
|
69
|
+
const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra);
|
|
69
70
|
await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra);
|
|
70
71
|
const toolName = request.params?.name;
|
|
71
72
|
const event = {
|
|
@@ -137,7 +138,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
|
|
|
137
138
|
const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
|
|
138
139
|
const startTime = new Date();
|
|
139
140
|
const event = {
|
|
140
|
-
sessionId: (0, external_session_js_namespaceObject.
|
|
141
|
+
sessionId: (0, external_session_js_namespaceObject.getSessionId)(server, extra),
|
|
141
142
|
parameters: (0, external_mcp_payloads_js_namespaceObject.buildCapturedMcpParameters)(request),
|
|
142
143
|
eventType: external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpToolsList,
|
|
143
144
|
timestamp: startTime
|
|
@@ -217,13 +218,48 @@ function cacheToolCategories(cache, tools) {
|
|
|
217
218
|
if (category) cache.set(tool.name, category);
|
|
218
219
|
}
|
|
219
220
|
}
|
|
221
|
+
function mintStatelessSessionOnInitialize(server, data, request, extra) {
|
|
222
|
+
try {
|
|
223
|
+
const headers = extra?.requestInfo?.headers;
|
|
224
|
+
if (!headers || 'object' != typeof headers) return;
|
|
225
|
+
if ((0, external_session_token_js_namespaceObject.readMcpSessionHeader)(headers)) return;
|
|
226
|
+
const transport = server.transport;
|
|
227
|
+
if (!transport || extra?.sessionId || transport.sessionId) return;
|
|
228
|
+
const sessionId = (0, external_session_js_namespaceObject.newSessionId)();
|
|
229
|
+
const clientInfo = readInitializeClientInfo(request);
|
|
230
|
+
const token = (0, external_session_token_js_namespaceObject.encodeSessionId)({
|
|
231
|
+
sessionId,
|
|
232
|
+
clientName: clientInfo?.name,
|
|
233
|
+
clientVersion: clientInfo?.version
|
|
234
|
+
});
|
|
235
|
+
if (!(0, external_session_token_js_namespaceObject.writeSessionIdToTransport)(transport, token)) return;
|
|
236
|
+
data.sessionId = sessionId;
|
|
237
|
+
data.sessionSource = 'token';
|
|
238
|
+
data.sessionInfo.clientName = clientInfo?.name;
|
|
239
|
+
data.sessionInfo.clientVersion = clientInfo?.version;
|
|
240
|
+
data.lastActivity = new Date();
|
|
241
|
+
(0, external_internal_js_namespaceObject.setServerTrackingData)(server, data);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
(0, external_logger_js_namespaceObject.log)(`Warning: PostHog MCP analytics failed to mint a stateless session id - ${error}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function readInitializeClientInfo(request) {
|
|
247
|
+
const clientInfo = request.params?.clientInfo;
|
|
248
|
+
if (!clientInfo || 'object' != typeof clientInfo) return;
|
|
249
|
+
const { name, version } = clientInfo;
|
|
250
|
+
return {
|
|
251
|
+
name: 'string' == typeof name ? name : void 0,
|
|
252
|
+
version: 'string' == typeof version ? version : void 0
|
|
253
|
+
};
|
|
254
|
+
}
|
|
220
255
|
async function handleInitializeRequest(server, originalInitializeHandler, request, extra) {
|
|
221
256
|
const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server);
|
|
222
257
|
if (!data) {
|
|
223
258
|
(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
259
|
return await originalInitializeHandler(request, extra);
|
|
225
260
|
}
|
|
226
|
-
|
|
261
|
+
mintStatelessSessionOnInitialize(server, data, request, extra);
|
|
262
|
+
const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra);
|
|
227
263
|
await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, extra);
|
|
228
264
|
const event = {
|
|
229
265
|
sessionId,
|
|
@@ -4,11 +4,12 @@ import { captureEvent } from "./capture.mjs";
|
|
|
4
4
|
import { MCPAnalyticsEventType } from "./event-types.mjs";
|
|
5
5
|
import { captureException } from "./exceptions.mjs";
|
|
6
6
|
import { resolveToolCallIntent, setEventIntent, setExplicitContextIntent } from "./intent.mjs";
|
|
7
|
-
import { getServerTrackingData, handleIdentify } from "./internal.mjs";
|
|
7
|
+
import { getServerTrackingData, handleIdentify, setServerTrackingData } from "./internal.mjs";
|
|
8
8
|
import { log } from "./logger.mjs";
|
|
9
9
|
import { buildCapturedMcpParameters } from "./mcp-payloads.mjs";
|
|
10
10
|
import { getLiteralValue, getObjectShape } from "./mcp-sdk-compat.mjs";
|
|
11
|
-
import {
|
|
11
|
+
import { getSessionId, newSessionId } from "./session.mjs";
|
|
12
|
+
import { encodeSessionId, readMcpSessionHeader, writeSessionIdToTransport } from "./session-token.mjs";
|
|
12
13
|
import { getReportMissingToolDescriptor, resolveMissingCapabilityToolName } from "./tools.mjs";
|
|
13
14
|
import { applyResolvedMetadata, isToolResultError } from "./tracing-helpers.mjs";
|
|
14
15
|
async function captureToolCall(params) {
|
|
@@ -31,7 +32,7 @@ async function captureToolCall(params) {
|
|
|
31
32
|
}
|
|
32
33
|
async function prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, eventType) {
|
|
33
34
|
try {
|
|
34
|
-
const sessionId =
|
|
35
|
+
const sessionId = getSessionId(server, extra);
|
|
35
36
|
await handleIdentify(server, data, sessionId, request, extra);
|
|
36
37
|
const toolName = request.params?.name;
|
|
37
38
|
const event = {
|
|
@@ -103,7 +104,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
|
|
|
103
104
|
const data = getServerTrackingData(server);
|
|
104
105
|
const startTime = new Date();
|
|
105
106
|
const event = {
|
|
106
|
-
sessionId:
|
|
107
|
+
sessionId: getSessionId(server, extra),
|
|
107
108
|
parameters: buildCapturedMcpParameters(request),
|
|
108
109
|
eventType: MCPAnalyticsEventType.mcpToolsList,
|
|
109
110
|
timestamp: startTime
|
|
@@ -183,13 +184,48 @@ function cacheToolCategories(cache, tools) {
|
|
|
183
184
|
if (category) cache.set(tool.name, category);
|
|
184
185
|
}
|
|
185
186
|
}
|
|
187
|
+
function mintStatelessSessionOnInitialize(server, data, request, extra) {
|
|
188
|
+
try {
|
|
189
|
+
const headers = extra?.requestInfo?.headers;
|
|
190
|
+
if (!headers || 'object' != typeof headers) return;
|
|
191
|
+
if (readMcpSessionHeader(headers)) return;
|
|
192
|
+
const transport = server.transport;
|
|
193
|
+
if (!transport || extra?.sessionId || transport.sessionId) return;
|
|
194
|
+
const sessionId = newSessionId();
|
|
195
|
+
const clientInfo = readInitializeClientInfo(request);
|
|
196
|
+
const token = encodeSessionId({
|
|
197
|
+
sessionId,
|
|
198
|
+
clientName: clientInfo?.name,
|
|
199
|
+
clientVersion: clientInfo?.version
|
|
200
|
+
});
|
|
201
|
+
if (!writeSessionIdToTransport(transport, token)) return;
|
|
202
|
+
data.sessionId = sessionId;
|
|
203
|
+
data.sessionSource = 'token';
|
|
204
|
+
data.sessionInfo.clientName = clientInfo?.name;
|
|
205
|
+
data.sessionInfo.clientVersion = clientInfo?.version;
|
|
206
|
+
data.lastActivity = new Date();
|
|
207
|
+
setServerTrackingData(server, data);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
log(`Warning: PostHog MCP analytics failed to mint a stateless session id - ${error}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function readInitializeClientInfo(request) {
|
|
213
|
+
const clientInfo = request.params?.clientInfo;
|
|
214
|
+
if (!clientInfo || 'object' != typeof clientInfo) return;
|
|
215
|
+
const { name, version } = clientInfo;
|
|
216
|
+
return {
|
|
217
|
+
name: 'string' == typeof name ? name : void 0,
|
|
218
|
+
version: 'string' == typeof version ? version : void 0
|
|
219
|
+
};
|
|
220
|
+
}
|
|
186
221
|
async function handleInitializeRequest(server, originalInitializeHandler, request, extra) {
|
|
187
222
|
const data = getServerTrackingData(server);
|
|
188
223
|
if (!data) {
|
|
189
224
|
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
225
|
return await originalInitializeHandler(request, extra);
|
|
191
226
|
}
|
|
192
|
-
|
|
227
|
+
mintStatelessSessionOnInitialize(server, data, request, extra);
|
|
228
|
+
const sessionId = getSessionId(server, extra);
|
|
193
229
|
await handleIdentify(server, data, sessionId, request, extra);
|
|
194
230
|
const event = {
|
|
195
231
|
sessionId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/extensions/intent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/extensions/intent.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,QAAQ,EACT,MAAM,UAAU,CAAA;AAIjB,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,wBAAwB,CAAA;CACjC;AAkCD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAO3F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQ/E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/extensions/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/extensions/logger.ts"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;AAIhD,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAE5D;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAQzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-payloads.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-payloads.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-payloads.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-payloads.ts"],"names":[],"mappings":"AAaA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAiBzC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA0B7D;AA6BD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAiBvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-sdk-compat.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-sdk-compat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-sdk-compat.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-sdk-compat.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAK5D,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,SAAS,CAAA;AAEpD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,YAAY,CAQlE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG,eAAe,CAKxE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,cAAc,CAMrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,GAAG,cAAc,CAM7G;AAyBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAKnD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CA6BnF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAkCxD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-events.d.ts","sourceRoot":"","sources":["../../src/extensions/posthog-events.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"posthog-events.d.ts","sourceRoot":"","sources":["../../src/extensions/posthog-events.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAyBrC,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,SAAS,CAAA;CAChB;AAED,MAAM,WAAW,gCAAgC;IAC/C,2FAA2F;IAC3F,0BAA0B,CAAC,EAAE,OAAO,CAAA;CACrC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,KAAK,EACZ,OAAO,GAAE,gCAAqC,GAC7C,mBAAmB,EAAE,CAQvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitization.d.ts","sourceRoot":"","sources":["../../src/extensions/sanitization.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sanitization.d.ts","sourceRoot":"","sources":["../../src/extensions/sanitization.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAS/C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,KAAK,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAmBrE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-encoded session tokens for stateless / multi-pod MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* A stateless server keeps nothing between requests, so every request starts a
|
|
5
|
+
* new session and the client name/version (only sent at `initialize`) is lost.
|
|
6
|
+
* The one value clients replay on every request is the `Mcp-Session-Id` header.
|
|
7
|
+
* So at `initialize` we mint that header as a token carrying the session id and
|
|
8
|
+
* client identity — any pod can read them back from the header alone.
|
|
9
|
+
*
|
|
10
|
+
* The token is unsigned: it holds only what the client already self-reports.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MCP_SESSION_HEADER = "mcp-session-id";
|
|
13
|
+
/** What a session token carries. */
|
|
14
|
+
export interface SessionTokenPayload {
|
|
15
|
+
/** PostHog session id (`ses_…`) → `$session_id`. */
|
|
16
|
+
sessionId: string;
|
|
17
|
+
/** MCP client name → `$mcp_client_name`. */
|
|
18
|
+
clientName?: string;
|
|
19
|
+
/** MCP client version → `$mcp_client_version`. */
|
|
20
|
+
clientVersion?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Encodes a session token for the `Mcp-Session-Id` response header. Also
|
|
24
|
+
* exported for SSE servers, which flush headers before handlers run and so
|
|
25
|
+
* must set the header themselves at the HTTP layer.
|
|
26
|
+
*/
|
|
27
|
+
export declare function encodeSessionId(payload: SessionTokenPayload): string;
|
|
28
|
+
/**
|
|
29
|
+
* Decodes an `Mcp-Session-Id` value into a token payload. Returns `null` for
|
|
30
|
+
* anything that isn't one of our tokens (transport UUIDs, JWTs, garbage) and
|
|
31
|
+
* never throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function decodeSessionId(value: unknown): SessionTokenPayload | null;
|
|
34
|
+
/**
|
|
35
|
+
* Reads the `mcp-session-id` header off `extra.requestInfo.headers`. The SDK
|
|
36
|
+
* transports lowercase header keys; the fallback scan covers hand-built extras.
|
|
37
|
+
*/
|
|
38
|
+
export declare function readMcpSessionHeader(headers: unknown): string | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Puts a minted token on the transport so it goes out as the `Mcp-Session-Id`
|
|
41
|
+
* response header. The Node transport's `sessionId` is a getter backed by an
|
|
42
|
+
* inner web-standard transport, so verify the write by reading back and fall
|
|
43
|
+
* back to writing the inner one. Returns whether the write stuck; never throws.
|
|
44
|
+
*/
|
|
45
|
+
export declare function writeSessionIdToTransport(transport: unknown, token: string): boolean;
|
|
46
|
+
//# sourceMappingURL=session-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-token.d.ts","sourceRoot":"","sources":["../../src/extensions/session-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,kBAAkB,mBAAmB,CAAA;AAElD,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAA;IACjB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAUD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAYpE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA8B1E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAgBzE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAsBpF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
MCP_SESSION_HEADER: ()=>MCP_SESSION_HEADER,
|
|
28
|
+
decodeSessionId: ()=>decodeSessionId,
|
|
29
|
+
encodeSessionId: ()=>encodeSessionId,
|
|
30
|
+
readMcpSessionHeader: ()=>readMcpSessionHeader,
|
|
31
|
+
writeSessionIdToTransport: ()=>writeSessionIdToTransport
|
|
32
|
+
});
|
|
33
|
+
const MCP_SESSION_HEADER = 'mcp-session-id';
|
|
34
|
+
const MAX_TOKEN_LENGTH = 4096;
|
|
35
|
+
const MAX_SESSION_ID_LENGTH = 128;
|
|
36
|
+
const MAX_CLIENT_FIELD_LENGTH = 200;
|
|
37
|
+
const BASE64URL_PATTERN = /^[A-Za-z0-9_-]+={0,2}$/;
|
|
38
|
+
function encodeSessionId(payload) {
|
|
39
|
+
if (!payload || 'string' != typeof payload.sessionId || 0 === payload.sessionId.length) throw new Error('encodeSessionId requires a non-empty `sessionId` (use newSessionId())');
|
|
40
|
+
const wire = {
|
|
41
|
+
sid: payload.sessionId
|
|
42
|
+
};
|
|
43
|
+
if ('string' == typeof payload.clientName && payload.clientName.length > 0) wire.cn = payload.clientName.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
44
|
+
if ('string' == typeof payload.clientVersion && payload.clientVersion.length > 0) wire.cv = payload.clientVersion.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
45
|
+
return utf8ToBase64Url(JSON.stringify(wire));
|
|
46
|
+
}
|
|
47
|
+
function decodeSessionId(value) {
|
|
48
|
+
if ('string' != typeof value || 0 === value.length || value.length > MAX_TOKEN_LENGTH) return null;
|
|
49
|
+
if (!BASE64URL_PATTERN.test(value)) return null;
|
|
50
|
+
let parsed;
|
|
51
|
+
try {
|
|
52
|
+
parsed = JSON.parse(base64UrlToUtf8(value));
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if (!parsed || 'object' != typeof parsed || Array.isArray(parsed)) return null;
|
|
57
|
+
const wire = parsed;
|
|
58
|
+
if ('string' != typeof wire.sid || 0 === wire.sid.length || wire.sid.length > MAX_SESSION_ID_LENGTH) return null;
|
|
59
|
+
const payload = {
|
|
60
|
+
sessionId: wire.sid
|
|
61
|
+
};
|
|
62
|
+
if ('string' == typeof wire.cn && wire.cn.length > 0) payload.clientName = wire.cn.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
63
|
+
if ('string' == typeof wire.cv && wire.cv.length > 0) payload.clientVersion = wire.cv.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
64
|
+
return payload;
|
|
65
|
+
}
|
|
66
|
+
function readMcpSessionHeader(headers) {
|
|
67
|
+
if (!headers || 'object' != typeof headers) return;
|
|
68
|
+
const record = headers;
|
|
69
|
+
let value = record[MCP_SESSION_HEADER];
|
|
70
|
+
if (void 0 === value) {
|
|
71
|
+
const key = Object.keys(record).find((k)=>k.toLowerCase() === MCP_SESSION_HEADER);
|
|
72
|
+
value = void 0 === key ? void 0 : record[key];
|
|
73
|
+
}
|
|
74
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
75
|
+
if ('string' != typeof first) return;
|
|
76
|
+
const trimmed = first.trim();
|
|
77
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
78
|
+
}
|
|
79
|
+
function writeSessionIdToTransport(transport, token) {
|
|
80
|
+
if (!transport || 'object' != typeof transport) return false;
|
|
81
|
+
const outer = transport;
|
|
82
|
+
try {
|
|
83
|
+
outer.sessionId = token;
|
|
84
|
+
} catch {}
|
|
85
|
+
if (outer.sessionId === token) return true;
|
|
86
|
+
const inner = outer._webStandardTransport;
|
|
87
|
+
if (inner && 'object' == typeof inner) try {
|
|
88
|
+
inner.sessionId = token;
|
|
89
|
+
} catch {}
|
|
90
|
+
return outer.sessionId === token;
|
|
91
|
+
}
|
|
92
|
+
function utf8ToBase64Url(input) {
|
|
93
|
+
if ('undefined' != typeof Buffer && 'function' == typeof Buffer.from) return Buffer.from(input, 'utf8').toString('base64url');
|
|
94
|
+
const bytes = new TextEncoder().encode(input);
|
|
95
|
+
let binary = '';
|
|
96
|
+
for(let i = 0; i < bytes.length; i++)binary += String.fromCharCode(bytes[i]);
|
|
97
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
98
|
+
}
|
|
99
|
+
function base64UrlToUtf8(input) {
|
|
100
|
+
const normalized = input.replace(/-/g, '+').replace(/_/g, '/').replace(/=+$/, '');
|
|
101
|
+
const padded = normalized + '='.repeat((4 - normalized.length % 4) % 4);
|
|
102
|
+
if ('undefined' != typeof Buffer && 'function' == typeof Buffer.from) return Buffer.from(padded, 'base64').toString('utf8');
|
|
103
|
+
const binary = atob(padded);
|
|
104
|
+
const bytes = new Uint8Array(binary.length);
|
|
105
|
+
for(let i = 0; i < binary.length; i++)bytes[i] = binary.charCodeAt(i);
|
|
106
|
+
return new TextDecoder().decode(bytes);
|
|
107
|
+
}
|
|
108
|
+
exports.MCP_SESSION_HEADER = __webpack_exports__.MCP_SESSION_HEADER;
|
|
109
|
+
exports.decodeSessionId = __webpack_exports__.decodeSessionId;
|
|
110
|
+
exports.encodeSessionId = __webpack_exports__.encodeSessionId;
|
|
111
|
+
exports.readMcpSessionHeader = __webpack_exports__.readMcpSessionHeader;
|
|
112
|
+
exports.writeSessionIdToTransport = __webpack_exports__.writeSessionIdToTransport;
|
|
113
|
+
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
114
|
+
"MCP_SESSION_HEADER",
|
|
115
|
+
"decodeSessionId",
|
|
116
|
+
"encodeSessionId",
|
|
117
|
+
"readMcpSessionHeader",
|
|
118
|
+
"writeSessionIdToTransport"
|
|
119
|
+
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
120
|
+
Object.defineProperty(exports, '__esModule', {
|
|
121
|
+
value: true
|
|
122
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const MCP_SESSION_HEADER = 'mcp-session-id';
|
|
2
|
+
const MAX_TOKEN_LENGTH = 4096;
|
|
3
|
+
const MAX_SESSION_ID_LENGTH = 128;
|
|
4
|
+
const MAX_CLIENT_FIELD_LENGTH = 200;
|
|
5
|
+
const BASE64URL_PATTERN = /^[A-Za-z0-9_-]+={0,2}$/;
|
|
6
|
+
function encodeSessionId(payload) {
|
|
7
|
+
if (!payload || 'string' != typeof payload.sessionId || 0 === payload.sessionId.length) throw new Error('encodeSessionId requires a non-empty `sessionId` (use newSessionId())');
|
|
8
|
+
const wire = {
|
|
9
|
+
sid: payload.sessionId
|
|
10
|
+
};
|
|
11
|
+
if ('string' == typeof payload.clientName && payload.clientName.length > 0) wire.cn = payload.clientName.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
12
|
+
if ('string' == typeof payload.clientVersion && payload.clientVersion.length > 0) wire.cv = payload.clientVersion.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
13
|
+
return utf8ToBase64Url(JSON.stringify(wire));
|
|
14
|
+
}
|
|
15
|
+
function decodeSessionId(value) {
|
|
16
|
+
if ('string' != typeof value || 0 === value.length || value.length > MAX_TOKEN_LENGTH) return null;
|
|
17
|
+
if (!BASE64URL_PATTERN.test(value)) return null;
|
|
18
|
+
let parsed;
|
|
19
|
+
try {
|
|
20
|
+
parsed = JSON.parse(base64UrlToUtf8(value));
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (!parsed || 'object' != typeof parsed || Array.isArray(parsed)) return null;
|
|
25
|
+
const wire = parsed;
|
|
26
|
+
if ('string' != typeof wire.sid || 0 === wire.sid.length || wire.sid.length > MAX_SESSION_ID_LENGTH) return null;
|
|
27
|
+
const payload = {
|
|
28
|
+
sessionId: wire.sid
|
|
29
|
+
};
|
|
30
|
+
if ('string' == typeof wire.cn && wire.cn.length > 0) payload.clientName = wire.cn.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
31
|
+
if ('string' == typeof wire.cv && wire.cv.length > 0) payload.clientVersion = wire.cv.slice(0, MAX_CLIENT_FIELD_LENGTH);
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
function readMcpSessionHeader(headers) {
|
|
35
|
+
if (!headers || 'object' != typeof headers) return;
|
|
36
|
+
const record = headers;
|
|
37
|
+
let value = record[MCP_SESSION_HEADER];
|
|
38
|
+
if (void 0 === value) {
|
|
39
|
+
const key = Object.keys(record).find((k)=>k.toLowerCase() === MCP_SESSION_HEADER);
|
|
40
|
+
value = void 0 === key ? void 0 : record[key];
|
|
41
|
+
}
|
|
42
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
43
|
+
if ('string' != typeof first) return;
|
|
44
|
+
const trimmed = first.trim();
|
|
45
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
46
|
+
}
|
|
47
|
+
function writeSessionIdToTransport(transport, token) {
|
|
48
|
+
if (!transport || 'object' != typeof transport) return false;
|
|
49
|
+
const outer = transport;
|
|
50
|
+
try {
|
|
51
|
+
outer.sessionId = token;
|
|
52
|
+
} catch {}
|
|
53
|
+
if (outer.sessionId === token) return true;
|
|
54
|
+
const inner = outer._webStandardTransport;
|
|
55
|
+
if (inner && 'object' == typeof inner) try {
|
|
56
|
+
inner.sessionId = token;
|
|
57
|
+
} catch {}
|
|
58
|
+
return outer.sessionId === token;
|
|
59
|
+
}
|
|
60
|
+
function utf8ToBase64Url(input) {
|
|
61
|
+
if ('undefined' != typeof Buffer && 'function' == typeof Buffer.from) return Buffer.from(input, 'utf8').toString('base64url');
|
|
62
|
+
const bytes = new TextEncoder().encode(input);
|
|
63
|
+
let binary = '';
|
|
64
|
+
for(let i = 0; i < bytes.length; i++)binary += String.fromCharCode(bytes[i]);
|
|
65
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
66
|
+
}
|
|
67
|
+
function base64UrlToUtf8(input) {
|
|
68
|
+
const normalized = input.replace(/-/g, '+').replace(/_/g, '/').replace(/=+$/, '');
|
|
69
|
+
const padded = normalized + '='.repeat((4 - normalized.length % 4) % 4);
|
|
70
|
+
if ('undefined' != typeof Buffer && 'function' == typeof Buffer.from) return Buffer.from(padded, 'base64').toString('utf8');
|
|
71
|
+
const binary = atob(padded);
|
|
72
|
+
const bytes = new Uint8Array(binary.length);
|
|
73
|
+
for(let i = 0; i < binary.length; i++)bytes[i] = binary.charCodeAt(i);
|
|
74
|
+
return new TextDecoder().decode(bytes);
|
|
75
|
+
}
|
|
76
|
+
export { MCP_SESSION_HEADER, decodeSessionId, encodeSessionId, readMcpSessionHeader, writeSessionIdToTransport };
|
|
@@ -6,11 +6,12 @@ export declare function newSessionId(): string;
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function deriveSessionIdFromMCPSession(mcpSessionId: string): string;
|
|
8
8
|
/**
|
|
9
|
-
* Resolves the session id for a request
|
|
10
|
-
*
|
|
9
|
+
* Resolves the session id for a request: from the replayed session token, from
|
|
10
|
+
* the transport's MCP session id, or — when the request carries nothing — from
|
|
11
|
+
* this instance's memory. Also saves the token's client name/version so events
|
|
12
|
+
* built later in the request can use them (see getSessionInfo).
|
|
11
13
|
*/
|
|
12
|
-
export declare function
|
|
13
|
-
export declare function setLastActivity(server: MCPServerLike): void;
|
|
14
|
+
export declare function getSessionId(server: MCPServerLike, extra?: CompatibleRequestHandlerExtra): string;
|
|
14
15
|
/**
|
|
15
16
|
* Builds the session metadata stamped onto an event. The caller passes the
|
|
16
17
|
* session id resolved for *this* request so identity attribution can't be
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/extensions/session.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/extensions/session.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,aAAa,EAEb,WAAW,EACZ,MAAM,UAAU,CAAA;AAMjB,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,6BAA6B,GAAG,MAAM,CA+BjG;AAgBD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAClC,SAAS,CAAC,EAAE,MAAM,GACjB,WAAW,CAgCb"}
|