@effect-uai/mcp 0.12.1

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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Client.d.mts +55 -0
  3. package/dist/Client.d.mts.map +1 -0
  4. package/dist/Client.mjs +85 -0
  5. package/dist/Client.mjs.map +1 -0
  6. package/dist/McpError-DWg9BlW5.d.mts +83 -0
  7. package/dist/McpError-DWg9BlW5.d.mts.map +1 -0
  8. package/dist/McpError.d.mts +2 -0
  9. package/dist/McpError.mjs +61 -0
  10. package/dist/McpError.mjs.map +1 -0
  11. package/dist/Toolkit.d.mts +20 -0
  12. package/dist/Toolkit.d.mts.map +1 -0
  13. package/dist/Toolkit.mjs +70 -0
  14. package/dist/Toolkit.mjs.map +1 -0
  15. package/dist/auth-ZDvsxpCo.d.mts +126 -0
  16. package/dist/auth-ZDvsxpCo.d.mts.map +1 -0
  17. package/dist/index.d.mts +4 -0
  18. package/dist/index.mjs +4 -0
  19. package/dist/internal/auth.d.mts +2 -0
  20. package/dist/internal/auth.mjs +25 -0
  21. package/dist/internal/auth.mjs.map +1 -0
  22. package/dist/internal/httpTransport.d.mts +17 -0
  23. package/dist/internal/httpTransport.d.mts.map +1 -0
  24. package/dist/internal/httpTransport.mjs +88 -0
  25. package/dist/internal/httpTransport.mjs.map +1 -0
  26. package/dist/internal/protocol.d.mts +2 -0
  27. package/dist/internal/protocol.mjs +23 -0
  28. package/dist/internal/protocol.mjs.map +1 -0
  29. package/dist/internal/protocols/2025-06-18.d.mts +11 -0
  30. package/dist/internal/protocols/2025-06-18.d.mts.map +1 -0
  31. package/dist/internal/protocols/2025-06-18.mjs +70 -0
  32. package/dist/internal/protocols/2025-06-18.mjs.map +1 -0
  33. package/dist/internal/protocols/2025-11-25.d.mts +2 -0
  34. package/dist/internal/protocols/2025-11-25.mjs +2 -0
  35. package/dist/internal/protocols/2026-07-28.d.mts +16 -0
  36. package/dist/internal/protocols/2026-07-28.d.mts.map +1 -0
  37. package/dist/internal/protocols/2026-07-28.mjs +83 -0
  38. package/dist/internal/protocols/2026-07-28.mjs.map +1 -0
  39. package/dist/internal/rpc.d.mts +2 -0
  40. package/dist/internal/rpc.mjs +78 -0
  41. package/dist/internal/rpc.mjs.map +1 -0
  42. package/dist/internal/schema.d.mts +2 -0
  43. package/dist/internal/schema.mjs +168 -0
  44. package/dist/internal/schema.mjs.map +1 -0
  45. package/dist/internal/stdioTransport.d.mts +15 -0
  46. package/dist/internal/stdioTransport.d.mts.map +1 -0
  47. package/dist/internal/stdioTransport.mjs +46 -0
  48. package/dist/internal/stdioTransport.mjs.map +1 -0
  49. package/dist/protocol-kjC3iAMb.d.mts +35 -0
  50. package/dist/protocol-kjC3iAMb.d.mts.map +1 -0
  51. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  52. package/dist/rpc-Bq95Lio9.d.mts +34 -0
  53. package/dist/rpc-Bq95Lio9.d.mts.map +1 -0
  54. package/dist/schema-D2oUNuo5.d.mts +245 -0
  55. package/dist/schema-D2oUNuo5.d.mts.map +1 -0
  56. package/package.json +70 -0
  57. package/src/Client.ts +180 -0
  58. package/src/McpError.ts +93 -0
  59. package/src/Toolkit.ts +109 -0
  60. package/src/index.ts +3 -0
  61. package/src/internal/auth.ts +48 -0
  62. package/src/internal/httpTransport.ts +171 -0
  63. package/src/internal/protocol.ts +67 -0
  64. package/src/internal/protocols/2025-06-18.ts +110 -0
  65. package/src/internal/protocols/2025-11-25.ts +8 -0
  66. package/src/internal/protocols/2026-07-28.test.ts +131 -0
  67. package/src/internal/protocols/2026-07-28.ts +152 -0
  68. package/src/internal/rpc.test.ts +156 -0
  69. package/src/internal/rpc.ts +189 -0
  70. package/src/internal/schema.ts +223 -0
  71. package/src/internal/stdioTransport.ts +63 -0
@@ -0,0 +1,17 @@
1
+ import { i as McpError } from "../McpError-DWg9BlW5.mjs";
2
+ import { t as Auth } from "../auth-ZDvsxpCo.mjs";
3
+ import { i as Transport } from "../rpc-Bq95Lio9.mjs";
4
+ import { Effect, Scope } from "effect";
5
+ import { HttpClient } from "effect/unstable/http";
6
+ //#region src/internal/httpTransport.d.ts
7
+ type HttpConfig = {
8
+ readonly url: string;
9
+ /** Static, non-auth headers applied to every request. */
10
+ readonly headers?: Record<string, string>;
11
+ /** Omit for a public server. Resolved per request, so a rotating source works. */
12
+ readonly auth?: Auth;
13
+ };
14
+ declare const make: (config: HttpConfig) => Effect.Effect<Transport, McpError, Scope.Scope | HttpClient.HttpClient>;
15
+ //#endregion
16
+ export { HttpConfig, make };
17
+ //# sourceMappingURL=httpTransport.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpTransport.d.mts","names":[],"sources":["../../src/internal/httpTransport.ts"],"mappings":";;;;;;KAuBY;WACD;;WAEA,UAAU;;WAEV,OAAO;;cAyBL,OAAI,QACP,eACP,OAAO,OAAO,WAAW,UAAU,MAAM,QAAQ,WAAW"}
@@ -0,0 +1,88 @@
1
+ import { McpAuthRequired, McpConnectFailed, McpProtocolError, McpTransportClosed } from "../McpError.mjs";
2
+ import { authHeaders } from "./auth.mjs";
3
+ import { Effect, Match, Option, Queue, Ref, Stream } from "effect";
4
+ import { HttpClient, HttpClientRequest } from "effect/unstable/http";
5
+ import * as SSE from "@effect-uai/core/SSE";
6
+ //#region src/internal/httpTransport.ts
7
+ /**
8
+ * Streamable HTTP `Transport`. Each client message is its own POST; the server
9
+ * answers with either one JSON object or a request-scoped SSE stream ending in
10
+ * the JSON-RPC response, and a client MUST accept both. Frames from every
11
+ * in-flight POST demux into one `messages` stream, which the rpc core
12
+ * correlates by id.
13
+ *
14
+ * Interrupting a request aborts its POST, which is exactly the spec's
15
+ * cancellation signal (closing the response stream).
16
+ */
17
+ /** RFC 9728: the `resource_metadata` pointer on a 401's `WWW-Authenticate`. */
18
+ const resourceMetadataUrl = (wwwAuthenticate) => /resource_metadata="([^"]+)"/.exec(wwwAuthenticate)?.[1];
19
+ const unauthorized = (response) => {
20
+ const header = response.headers["www-authenticate"];
21
+ const pointer = header === void 0 ? void 0 : resourceMetadataUrl(header);
22
+ return new McpAuthRequired({
23
+ ...pointer !== void 0 ? { resourceMetadataUrl: pointer } : {},
24
+ ...header !== void 0 ? { wwwAuthenticate: header } : {}
25
+ });
26
+ };
27
+ /**
28
+ * A non-2xx that is not a 401. The body still matters: a modern server answers
29
+ * `400` for `-32022` / `-32021` / `-32020` and `404` for `-32601`, and era
30
+ * detection reads those codes off the JSON-RPC body. So the body is forwarded
31
+ * into `messages` whenever it parses as JSON, and only a bodyless failure
32
+ * becomes a transport error.
33
+ */
34
+ const isJsonRpcBody = (body) => body.trimStart().startsWith("{");
35
+ const make = (config) => Effect.gen(function* () {
36
+ const client = yield* HttpClient.HttpClient;
37
+ const inbox = yield* Queue.make();
38
+ yield* Effect.addFinalizer(() => Queue.end(inbox));
39
+ const session = yield* Ref.make(Option.none());
40
+ const post = (frame, meta) => Effect.gen(function* () {
41
+ const sessionId = yield* Ref.get(session);
42
+ const auth = yield* authHeaders(Option.fromNullishOr(config.auth));
43
+ const request = HttpClientRequest.post(config.url).pipe(HttpClientRequest.setHeaders({
44
+ "content-type": "application/json",
45
+ accept: "application/json, text/event-stream",
46
+ ...config.headers,
47
+ ...auth,
48
+ ...meta?.headers,
49
+ ...Option.match(sessionId, {
50
+ onNone: () => ({}),
51
+ onSome: (id) => ({ "Mcp-Session-Id": id })
52
+ })
53
+ }), HttpClientRequest.bodyText(frame, "application/json"));
54
+ const response = yield* client.execute(request).pipe(Effect.mapError((cause) => new McpConnectFailed({
55
+ reason: "MCP request failed",
56
+ raw: cause
57
+ })));
58
+ yield* captureSession(response);
59
+ yield* ingest(response);
60
+ });
61
+ const captureSession = (response) => {
62
+ const minted = response.headers["mcp-session-id"];
63
+ return minted === void 0 ? Effect.void : Ref.set(session, Option.some(minted));
64
+ };
65
+ const ingest = (response) => Match.value(response.status).pipe(Match.when(401, () => Effect.fail(unauthorized(response))), Match.when(404, () => expiredOrBody(response)), Match.when(202, () => Effect.void), Match.orElse(() => readFrames(response)));
66
+ const expiredOrBody = (response) => Ref.get(session).pipe(Effect.flatMap((held) => Option.isSome(held) ? Effect.fail(new McpTransportClosed({ reason: "the server expired this session" })) : readBody(response)));
67
+ const readFrames = (response) => (response.headers["content-type"] ?? "").includes("text/event-stream") ? readSse(response) : readBody(response);
68
+ const readSse = (response) => response.stream.pipe(SSE.fromBytes, Stream.runForEach((event) => Queue.offer(inbox, event.data)), Effect.mapError((cause) => new McpTransportClosed({
69
+ reason: "SSE stream failed",
70
+ raw: cause
71
+ })));
72
+ const readBody = (response) => response.text.pipe(Effect.mapError((cause) => new McpTransportClosed({
73
+ reason: "could not read response",
74
+ raw: cause
75
+ })), Effect.flatMap((body) => isJsonRpcBody(body) ? Effect.asVoid(Queue.offer(inbox, body)) : Effect.fail(new McpProtocolError({
76
+ code: response.status,
77
+ reason: `HTTP ${response.status} with a non-JSON-RPC body`,
78
+ raw: body.slice(0, 500)
79
+ }))));
80
+ return {
81
+ send: post,
82
+ messages: Stream.fromQueue(inbox)
83
+ };
84
+ });
85
+ //#endregion
86
+ export { make };
87
+
88
+ //# sourceMappingURL=httpTransport.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpTransport.mjs","names":[],"sources":["../../src/internal/httpTransport.ts"],"sourcesContent":["/**\n * Streamable HTTP `Transport`. Each client message is its own POST; the server\n * answers with either one JSON object or a request-scoped SSE stream ending in\n * the JSON-RPC response, and a client MUST accept both. Frames from every\n * in-flight POST demux into one `messages` stream, which the rpc core\n * correlates by id.\n *\n * Interrupting a request aborts its POST, which is exactly the spec's\n * cancellation signal (closing the response stream).\n */\nimport { Cause, Effect, Match, Option, Queue, Ref, type Scope, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest, type HttpClientResponse } from \"effect/unstable/http\"\nimport * as SSE from \"@effect-uai/core/SSE\"\nimport {\n McpAuthRequired,\n McpConnectFailed,\n type McpError,\n McpProtocolError,\n McpTransportClosed,\n} from \"../McpError.js\"\nimport { type Auth, authHeaders } from \"./auth.js\"\nimport type { SendMeta, Transport } from \"./rpc.js\"\n\nexport type HttpConfig = {\n readonly url: string\n /** Static, non-auth headers applied to every request. */\n readonly headers?: Record<string, string>\n /** Omit for a public server. Resolved per request, so a rotating source works. */\n readonly auth?: Auth\n}\n\n/** RFC 9728: the `resource_metadata` pointer on a 401's `WWW-Authenticate`. */\nconst resourceMetadataUrl = (wwwAuthenticate: string): string | undefined =>\n /resource_metadata=\"([^\"]+)\"/.exec(wwwAuthenticate)?.[1]\n\nconst unauthorized = (response: HttpClientResponse.HttpClientResponse): McpError => {\n const header = response.headers[\"www-authenticate\"]\n const pointer = header === undefined ? undefined : resourceMetadataUrl(header)\n return new McpAuthRequired({\n ...(pointer !== undefined ? { resourceMetadataUrl: pointer } : {}),\n ...(header !== undefined ? { wwwAuthenticate: header } : {}),\n })\n}\n\n/**\n * A non-2xx that is not a 401. The body still matters: a modern server answers\n * `400` for `-32022` / `-32021` / `-32020` and `404` for `-32601`, and era\n * detection reads those codes off the JSON-RPC body. So the body is forwarded\n * into `messages` whenever it parses as JSON, and only a bodyless failure\n * becomes a transport error.\n */\nconst isJsonRpcBody = (body: string): boolean => body.trimStart().startsWith(\"{\")\n\nexport const make = (\n config: HttpConfig,\n): Effect.Effect<Transport, McpError, Scope.Scope | HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const inbox = yield* Queue.make<string, Cause.Done>()\n yield* Effect.addFinalizer(() => Queue.end(inbox))\n\n // The legacy era's `Mcp-Session-Id` is a transport concern, not a protocol\n // one: capture whatever the server mints and echo it from then on, so the\n // protocol implementations stay transport-agnostic. Stateless servers\n // never send one, and this stays empty.\n const session = yield* Ref.make(Option.none<string>())\n\n const post = (frame: string, meta?: SendMeta): Effect.Effect<void, McpError> =>\n Effect.gen(function* () {\n const sessionId = yield* Ref.get(session)\n const auth = yield* authHeaders(Option.fromNullishOr(config.auth))\n const request = HttpClientRequest.post(config.url).pipe(\n HttpClientRequest.setHeaders({\n \"content-type\": \"application/json\",\n // Both response shapes are legal for any request.\n accept: \"application/json, text/event-stream\",\n ...config.headers,\n ...auth,\n ...meta?.headers,\n ...Option.match(sessionId, {\n onNone: () => ({}),\n onSome: (id) => ({ \"Mcp-Session-Id\": id }),\n }),\n }),\n // The content type must be set on the body: it overrides any header.\n HttpClientRequest.bodyText(frame, \"application/json\"),\n )\n const response = yield* client\n .execute(request)\n .pipe(\n Effect.mapError(\n (cause) => new McpConnectFailed({ reason: \"MCP request failed\", raw: cause }),\n ),\n )\n yield* captureSession(response)\n yield* ingest(response)\n })\n\n const captureSession = (\n response: HttpClientResponse.HttpClientResponse,\n ): Effect.Effect<void> => {\n const minted = response.headers[\"mcp-session-id\"]\n return minted === undefined ? Effect.void : Ref.set(session, Option.some(minted))\n }\n\n const ingest = (\n response: HttpClientResponse.HttpClientResponse,\n ): Effect.Effect<void, McpError> =>\n Match.value(response.status).pipe(\n Match.when(401, () => Effect.fail(unauthorized(response))),\n Match.when(404, () => expiredOrBody(response)),\n // 202 answers a notification and carries no body.\n Match.when(202, () => Effect.void),\n Match.orElse(() => readFrames(response)),\n )\n\n // A 404 against a session we hold means the server dropped it; the caller\n // reconnects rather than retrying into a dead session.\n const expiredOrBody = (\n response: HttpClientResponse.HttpClientResponse,\n ): Effect.Effect<void, McpError> =>\n Ref.get(session).pipe(\n Effect.flatMap((held) =>\n Option.isSome(held)\n ? Effect.fail(new McpTransportClosed({ reason: \"the server expired this session\" }))\n : readBody(response),\n ),\n )\n\n const readFrames = (\n response: HttpClientResponse.HttpClientResponse,\n ): Effect.Effect<void, McpError> =>\n (response.headers[\"content-type\"] ?? \"\").includes(\"text/event-stream\")\n ? readSse(response)\n : readBody(response)\n\n const readSse = (\n response: HttpClientResponse.HttpClientResponse,\n ): Effect.Effect<void, McpError> =>\n response.stream.pipe(\n SSE.fromBytes,\n Stream.runForEach((event) => Queue.offer(inbox, event.data)),\n Effect.mapError(\n (cause) => new McpTransportClosed({ reason: \"SSE stream failed\", raw: cause }),\n ),\n )\n\n const readBody = (\n response: HttpClientResponse.HttpClientResponse,\n ): Effect.Effect<void, McpError> =>\n response.text.pipe(\n Effect.mapError(\n (cause) => new McpTransportClosed({ reason: \"could not read response\", raw: cause }),\n ),\n Effect.flatMap((body) =>\n isJsonRpcBody(body)\n ? Effect.asVoid(Queue.offer(inbox, body))\n : Effect.fail(\n new McpProtocolError({\n code: response.status,\n reason: `HTTP ${response.status} with a non-JSON-RPC body`,\n raw: body.slice(0, 500),\n }),\n ),\n ),\n )\n\n // The POST runs on the caller's fiber so interruption aborts it, which is\n // the spec's cancellation signal.\n return { send: post, messages: Stream.fromQueue(inbox) } satisfies Transport\n })\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { i as modernRejection, n as Protocol, r as ProtocolProbe, t as ModernRejection } from "../protocol-kjC3iAMb.mjs";
2
+ export { ModernRejection, Protocol, ProtocolProbe, modernRejection };
@@ -0,0 +1,23 @@
1
+ import { MODERN_ERROR_CODES, decodeUnsupportedVersionData } from "./schema.mjs";
2
+ import { Option, Predicate } from "effect";
3
+ //#region src/internal/protocol.ts
4
+ /**
5
+ * The `Protocol` seam: everything that differs between the stateless
6
+ * 2026-07-28 revision and the 2025-06-18 handshake era, behind one interface.
7
+ * `modern.ts` and `legacy.ts` implement it independently and never import each
8
+ * other; `Client.connect` picks one, once, from the probes.
9
+ *
10
+ * The negotiated `version` is the single source of truth. There is no separate
11
+ * era label: nothing branches on it at runtime, so carrying one would only
12
+ * create state that can drift out of sync with the version.
13
+ */
14
+ const isProtocolError = Predicate.isTagged("McpProtocolError");
15
+ const modernRejection = (error) => isProtocolError(error) ? Option.fromNullishOr(error.code).pipe(Option.filter((code) => MODERN_ERROR_CODES.has(code)), Option.map((code) => ({
16
+ code,
17
+ supported: supportedVersions(error.raw)
18
+ }))) : Option.none();
19
+ const supportedVersions = (raw) => decodeUnsupportedVersionData(Predicate.hasProperty(raw, "data") ? raw.data : void 0).pipe(Option.flatMap((data) => Option.fromNullishOr(data.supported)), Option.getOrElse(() => []));
20
+ //#endregion
21
+ export { modernRejection };
22
+
23
+ //# sourceMappingURL=protocol.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.mjs","names":[],"sources":["../../src/internal/protocol.ts"],"sourcesContent":["/**\n * The `Protocol` seam: everything that differs between the stateless\n * 2026-07-28 revision and the 2025-06-18 handshake era, behind one interface.\n * `modern.ts` and `legacy.ts` implement it independently and never import each\n * other; `Client.connect` picks one, once, from the probes.\n *\n * The negotiated `version` is the single source of truth. There is no separate\n * era label: nothing branches on it at runtime, so carrying one would only\n * create state that can drift out of sync with the version.\n */\nimport { Effect, Option, Predicate, type Scope } from \"effect\"\nimport type { McpError } from \"../McpError.js\"\nimport type { Inbound, McpConnection, SendMeta } from \"./rpc.js\"\nimport {\n decodeUnsupportedVersionData,\n type McpMethod,\n MODERN_ERROR_CODES,\n type ProtocolVersion,\n type ServerInfo,\n} from \"./schema.js\"\n\nexport type Protocol = {\n readonly version: ProtocolVersion\n readonly serverInfo: ServerInfo\n /** Wrap outgoing params: modern adds the `_meta` envelope, legacy passes through. */\n readonly envelope: (method: McpMethod, params: unknown) => unknown\n /** Per-request transport hints: modern headers, or the legacy session id. */\n readonly meta: (method: McpMethod, params: unknown) => SendMeta\n /** Answer a server-initiated frame. Modern servers never send one. */\n readonly onInbound: (inbound: Inbound) => Effect.Effect<void>\n}\n\n/**\n * Probe for one protocol era. `None` means \"not this era, try the next\"; a\n * failure means the server is this era but unusable (no mutual version).\n */\nexport type ProtocolProbe = (\n connection: McpConnection,\n) => Effect.Effect<Option.Option<Protocol>, McpError, Scope.Scope>\n\nconst isProtocolError = Predicate.isTagged(\"McpProtocolError\")\n\n/**\n * A `-32020` / `-32021` / `-32022` reply, which is the spec's era\n * discriminator: it proves the peer speaks a modern version, so the client\n * corrects and retries rather than falling back to `initialize`. `supported`\n * carries the versions a `-32022` offered, decoded through the schema so a\n * server that adds fields cannot break it.\n */\nexport type ModernRejection = {\n readonly code: number\n readonly supported: ReadonlyArray<string>\n}\n\nexport const modernRejection = (error: McpError): Option.Option<ModernRejection> =>\n isProtocolError(error)\n ? Option.fromNullishOr(error.code).pipe(\n Option.filter((code) => MODERN_ERROR_CODES.has(code)),\n Option.map((code) => ({ code, supported: supportedVersions(error.raw) })),\n )\n : Option.none()\n\nconst supportedVersions = (raw: unknown): ReadonlyArray<string> =>\n decodeUnsupportedVersionData(Predicate.hasProperty(raw, \"data\") ? raw.data : undefined).pipe(\n Option.flatMap((data) => Option.fromNullishOr(data.supported)),\n Option.getOrElse((): ReadonlyArray<string> => []),\n )\n"],"mappings":";;;;;;;;;;;;;AAwCA,MAAM,kBAAkB,UAAU,SAAS,kBAAkB;AAc7D,MAAa,mBAAmB,UAC9B,gBAAgB,KAAK,IACjB,OAAO,cAAc,MAAM,IAAI,CAAC,CAAC,KAC/B,OAAO,QAAQ,SAAS,mBAAmB,IAAI,IAAI,CAAC,GACpD,OAAO,KAAK,UAAU;CAAE;CAAM,WAAW,kBAAkB,MAAM,GAAG;AAAE,EAAE,CAC1E,IACA,OAAO,KAAK;AAElB,MAAM,qBAAqB,QACzB,6BAA6B,UAAU,YAAY,KAAK,MAAM,IAAI,IAAI,OAAO,KAAA,CAAS,CAAC,CAAC,KACtF,OAAO,SAAS,SAAS,OAAO,cAAc,KAAK,SAAS,CAAC,GAC7D,OAAO,gBAAuC,CAAC,CAAC,CAClD"}
@@ -0,0 +1,11 @@
1
+ import { r as ProtocolProbe } from "../../protocol-kjC3iAMb.mjs";
2
+ //#region src/internal/protocols/2025-06-18.d.ts
3
+ /**
4
+ * Run the `initialize` handshake. Unlike the stateless probe there is nothing
5
+ * to fall back to afterwards, so a failure here propagates rather than
6
+ * yielding `None`: this is the last era we speak.
7
+ */
8
+ declare const probe: ProtocolProbe;
9
+ //#endregion
10
+ export { probe };
11
+ //# sourceMappingURL=2025-06-18.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"2025-06-18.d.mts","names":[],"sources":["../../../src/internal/protocols/2025-06-18.ts"],"mappings":";;;;;;;cAyEa,OAAO"}
@@ -0,0 +1,70 @@
1
+ import { McpUnsupportedProtocol } from "../../McpError.mjs";
2
+ import { CLIENT_INFO, CODE_METHOD_NOT_FOUND, LEGACY_VERSION, asProtocolVersion, decodeInitializeResult } from "../schema.mjs";
3
+ import { Effect, Option } from "effect";
4
+ //#region src/internal/protocols/2025-06-18.ts
5
+ /**
6
+ * Protocol revision 2025-06-18: the handshake era, and the compatibility mode
7
+ * this client keeps for the servers that have not migrated. Also serves
8
+ * 2025-11-25, which is wire-compatible for a tools-only client (see
9
+ * `2025-11-25.ts`).
10
+ *
11
+ * Three things differ from the stateless era, and they are all here:
12
+ * an `initialize` exchange at connect, a negotiated version echoed on every
13
+ * later request, and server-initiated requests arriving on the connection.
14
+ *
15
+ * The HTTP session id (`Mcp-Session-Id`) is deliberately *not* here: it is a
16
+ * transport concern that `httpTransport` captures and echoes on its own, so
17
+ * this file stays transport-agnostic.
18
+ */
19
+ const UNKNOWN_SERVER = { name: "unknown" };
20
+ /**
21
+ * Legacy params travel bare: no `_meta` envelope. Only the negotiated version
22
+ * rides along, and on HTTP only as a header.
23
+ */
24
+ const makeProtocol = (connection, version, serverInfo) => ({
25
+ version,
26
+ serverInfo,
27
+ envelope: (_method, params) => params ?? {},
28
+ meta: () => ({ headers: { "MCP-Protocol-Version": version } }),
29
+ onInbound: (inbound) => answer(connection, inbound)
30
+ });
31
+ /**
32
+ * Legacy servers may send requests to the client. We are a headless tools
33
+ * client: answer `ping` so the connection stays healthy, and decline
34
+ * everything else (sampling, elicitation, roots) with method-not-found rather
35
+ * than leaving the server waiting.
36
+ */
37
+ const answer = (connection, inbound) => Option.match(inbound.id, {
38
+ onNone: () => Effect.void,
39
+ onSome: (id) => (inbound.method === "ping" ? connection.respond(id, {}) : connection.respondError(id, CODE_METHOD_NOT_FOUND, `${inbound.method} is not supported by this client`)).pipe(Effect.ignore)
40
+ });
41
+ /**
42
+ * Run the `initialize` handshake. Unlike the stateless probe there is nothing
43
+ * to fall back to afterwards, so a failure here propagates rather than
44
+ * yielding `None`: this is the last era we speak.
45
+ */
46
+ const probe = (connection) => handshake(connection).pipe(Effect.map(Option.some));
47
+ const handshake = (connection) => Effect.gen(function* () {
48
+ const raw = yield* connection.request("initialize", {
49
+ protocolVersion: LEGACY_VERSION,
50
+ capabilities: {},
51
+ clientInfo: CLIENT_INFO
52
+ });
53
+ const result = yield* decodeInitializeResult(raw).pipe(Effect.mapError(() => new McpUnsupportedProtocol({
54
+ offered: [],
55
+ reason: "initialize returned an undecodable result"
56
+ })));
57
+ const version = yield* Option.match(asProtocolVersion(result.protocolVersion), {
58
+ onNone: () => Effect.fail(new McpUnsupportedProtocol({
59
+ offered: [result.protocolVersion],
60
+ reason: `the server negotiated ${result.protocolVersion}, which this client does not support`
61
+ })),
62
+ onSome: Effect.succeed
63
+ });
64
+ yield* connection.notify("notifications/initialized");
65
+ return makeProtocol(connection, version, result.serverInfo ?? UNKNOWN_SERVER);
66
+ });
67
+ //#endregion
68
+ export { probe };
69
+
70
+ //# sourceMappingURL=2025-06-18.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"2025-06-18.mjs","names":[],"sources":["../../../src/internal/protocols/2025-06-18.ts"],"sourcesContent":["/**\n * Protocol revision 2025-06-18: the handshake era, and the compatibility mode\n * this client keeps for the servers that have not migrated. Also serves\n * 2025-11-25, which is wire-compatible for a tools-only client (see\n * `2025-11-25.ts`).\n *\n * Three things differ from the stateless era, and they are all here:\n * an `initialize` exchange at connect, a negotiated version echoed on every\n * later request, and server-initiated requests arriving on the connection.\n *\n * The HTTP session id (`Mcp-Session-Id`) is deliberately *not* here: it is a\n * transport concern that `httpTransport` captures and echoes on its own, so\n * this file stays transport-agnostic.\n */\nimport { Effect, Option, type Scope } from \"effect\"\nimport { type McpError, McpUnsupportedProtocol } from \"../../McpError.js\"\nimport type { Protocol, ProtocolProbe } from \"../protocol.js\"\nimport type { Inbound, McpConnection, SendMeta } from \"../rpc.js\"\nimport {\n asProtocolVersion,\n CLIENT_INFO,\n CODE_METHOD_NOT_FOUND,\n decodeInitializeResult,\n LEGACY_VERSION,\n type McpMethod,\n type ProtocolVersion,\n type ServerInfo,\n} from \"../schema.js\"\n\nconst UNKNOWN_SERVER: ServerInfo = { name: \"unknown\" }\n\n/**\n * Legacy params travel bare: no `_meta` envelope. Only the negotiated version\n * rides along, and on HTTP only as a header.\n */\nconst makeProtocol = (\n connection: McpConnection,\n version: ProtocolVersion,\n serverInfo: ServerInfo,\n): Protocol => ({\n version,\n serverInfo,\n envelope: (_method: McpMethod, params: unknown) => params ?? {},\n meta: (): SendMeta => ({ headers: { \"MCP-Protocol-Version\": version } }),\n onInbound: (inbound: Inbound) => answer(connection, inbound),\n})\n\n/**\n * Legacy servers may send requests to the client. We are a headless tools\n * client: answer `ping` so the connection stays healthy, and decline\n * everything else (sampling, elicitation, roots) with method-not-found rather\n * than leaving the server waiting.\n */\nconst answer = (connection: McpConnection, inbound: Inbound): Effect.Effect<void> =>\n Option.match(inbound.id, {\n // A notification expects no reply.\n onNone: () => Effect.void,\n onSome: (id) =>\n (inbound.method === \"ping\"\n ? connection.respond(id, {})\n : connection.respondError(\n id,\n CODE_METHOD_NOT_FOUND,\n `${inbound.method} is not supported by this client`,\n )\n ).pipe(Effect.ignore),\n })\n\n/**\n * Run the `initialize` handshake. Unlike the stateless probe there is nothing\n * to fall back to afterwards, so a failure here propagates rather than\n * yielding `None`: this is the last era we speak.\n */\nexport const probe: ProtocolProbe = (connection: McpConnection) =>\n handshake(connection).pipe(Effect.map(Option.some))\n\nconst handshake = (connection: McpConnection): Effect.Effect<Protocol, McpError, Scope.Scope> =>\n Effect.gen(function* () {\n const raw = yield* connection.request(\"initialize\", {\n protocolVersion: LEGACY_VERSION,\n capabilities: {},\n clientInfo: CLIENT_INFO,\n })\n const result = yield* decodeInitializeResult(raw).pipe(\n Effect.mapError(\n () =>\n new McpUnsupportedProtocol({\n offered: [],\n reason: \"initialize returned an undecodable result\",\n }),\n ),\n )\n // The server picks the version; we either speak it or we stop here.\n const version = yield* Option.match(asProtocolVersion(result.protocolVersion), {\n onNone: () =>\n Effect.fail(\n new McpUnsupportedProtocol({\n offered: [result.protocolVersion],\n reason: `the server negotiated ${result.protocolVersion}, which this client does not support`,\n }),\n ),\n onSome: Effect.succeed,\n })\n\n // Required by the spec before any other request; failing to send it is\n // fatal to the session, so it is not ignored.\n yield* connection.notify(\"notifications/initialized\")\n\n return makeProtocol(connection, version, result.serverInfo ?? UNKNOWN_SERVER)\n })\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6BA,MAAM,iBAA6B,EAAE,MAAM,UAAU;;;;;AAMrD,MAAM,gBACJ,YACA,SACA,gBACc;CACd;CACA;CACA,WAAW,SAAoB,WAAoB,UAAU,CAAC;CAC9D,aAAuB,EAAE,SAAS,EAAE,wBAAwB,QAAQ,EAAE;CACtE,YAAY,YAAqB,OAAO,YAAY,OAAO;AAC7D;;;;;;;AAQA,MAAM,UAAU,YAA2B,YACzC,OAAO,MAAM,QAAQ,IAAI;CAEvB,cAAc,OAAO;CACrB,SAAS,QACN,QAAQ,WAAW,SAChB,WAAW,QAAQ,IAAI,CAAC,CAAC,IACzB,WAAW,aACT,IACA,uBACA,GAAG,QAAQ,OAAO,iCACpB,EAAA,CACF,KAAK,OAAO,MAAM;AACxB,CAAC;;;;;;AAOH,MAAa,SAAwB,eACnC,UAAU,UAAU,CAAC,CAAC,KAAK,OAAO,IAAI,OAAO,IAAI,CAAC;AAEpD,MAAM,aAAa,eACjB,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,OAAO,WAAW,QAAQ,cAAc;EAClD,iBAAiB;EACjB,cAAc,CAAC;EACf,YAAY;CACd,CAAC;CACD,MAAM,SAAS,OAAO,uBAAuB,GAAG,CAAC,CAAC,KAChD,OAAO,eAEH,IAAI,uBAAuB;EACzB,SAAS,CAAC;EACV,QAAQ;CACV,CAAC,CACL,CACF;CAEA,MAAM,UAAU,OAAO,OAAO,MAAM,kBAAkB,OAAO,eAAe,GAAG;EAC7E,cACE,OAAO,KACL,IAAI,uBAAuB;GACzB,SAAS,CAAC,OAAO,eAAe;GAChC,QAAQ,yBAAyB,OAAO,gBAAgB;EAC1D,CAAC,CACH;EACF,QAAQ,OAAO;CACjB,CAAC;CAID,OAAO,WAAW,OAAO,2BAA2B;CAEpD,OAAO,aAAa,YAAY,SAAS,OAAO,cAAc,cAAc;AAC9E,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { probe } from "./2025-06-18.mjs";
2
+ export { probe };
@@ -0,0 +1,2 @@
1
+ import { probe } from "./2025-06-18.mjs";
2
+ export { probe };
@@ -0,0 +1,16 @@
1
+ import { r as ProtocolProbe } from "../../protocol-kjC3iAMb.mjs";
2
+ //#region src/internal/protocols/2026-07-28.d.ts
3
+ /**
4
+ * Header values outside the safe set (and any literal that would be mistaken
5
+ * for the marker) ride the spec's Base64 sentinel form.
6
+ */
7
+ declare const headerValue: (raw: string) => string;
8
+ /**
9
+ * Probe with `server/discover`. A `DiscoverResult` means modern. A modern
10
+ * error code means modern-but-rejected: on `-32022` retry with a mutual
11
+ * version. Anything else yields `None`, i.e. "try the legacy handshake".
12
+ */
13
+ declare const probe: ProtocolProbe;
14
+ //#endregion
15
+ export { headerValue, probe };
16
+ //# sourceMappingURL=2026-07-28.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"2026-07-28.d.mts","names":[],"sources":["../../../src/internal/protocols/2026-07-28.ts"],"mappings":";;;;;;cAyDa,cAAW;;;;;;cAqCX,OAAO"}
@@ -0,0 +1,83 @@
1
+ import { McpUnsupportedProtocol } from "../../McpError.mjs";
2
+ import { CLIENT_INFO, LATEST_VERSION, META_CLIENT_CAPABILITIES, META_CLIENT_INFO, META_PROTOCOL_VERSION, asProtocolVersion, decodeDiscoverResult } from "../schema.mjs";
3
+ import { modernRejection } from "../protocol.mjs";
4
+ import { Effect, Encoding, Option, Predicate, Record } from "effect";
5
+ //#region src/internal/protocols/2026-07-28.ts
6
+ /**
7
+ * Protocol revision 2026-07-28: the stateless era. No handshake and no
8
+ * session; every request self-describes via `_meta`, mirrored into the HTTP
9
+ * request headers. Servers never send requests back, so `onInbound` has
10
+ * nothing to answer.
11
+ *
12
+ * Files here are named for the revision they implement. A later revision that
13
+ * keeps this wire shape gets its own file re-exporting this one.
14
+ */
15
+ const UNKNOWN_SERVER = { name: "unknown" };
16
+ /**
17
+ * Which param field carries the subject name mirrored into `Mcp-Name`, per
18
+ * method. Keyed by string rather than `McpMethod` so the methods a later
19
+ * revision adds need no cast here.
20
+ */
21
+ const NAME_FIELD = {
22
+ "tools/call": "name",
23
+ "prompts/get": "name",
24
+ "resources/read": "uri"
25
+ };
26
+ const subjectName = (method, params) => Record.get(NAME_FIELD, method).pipe(Option.flatMap((field) => Record.get(asRecord(params), field)), Option.filter(Predicate.isString));
27
+ const asRecord = (value) => Predicate.isObject(value) ? value : {};
28
+ const SENTINEL = /^=\?base64\?.*\?=$/;
29
+ const HEADER_SAFE = /^[\x21-\x7e]([\x20-\x7e]*[\x21-\x7e])?$/;
30
+ /**
31
+ * Header values outside the safe set (and any literal that would be mistaken
32
+ * for the marker) ride the spec's Base64 sentinel form.
33
+ */
34
+ const headerValue = (raw) => HEADER_SAFE.test(raw) && !SENTINEL.test(raw) ? raw : `=?base64?${Encoding.encodeBase64(raw)}?=`;
35
+ const makeProtocol = (version, serverInfo) => ({
36
+ version,
37
+ serverInfo,
38
+ envelope: (_method, params) => ({
39
+ ...asRecord(params),
40
+ _meta: {
41
+ [META_PROTOCOL_VERSION]: version,
42
+ [META_CLIENT_INFO]: CLIENT_INFO,
43
+ [META_CLIENT_CAPABILITIES]: {}
44
+ }
45
+ }),
46
+ meta: (method, params) => ({ headers: {
47
+ "MCP-Protocol-Version": version,
48
+ "Mcp-Method": method,
49
+ ...subjectName(method, params).pipe(Option.map((name) => ({ "Mcp-Name": headerValue(name) })), Option.getOrElse(() => ({})))
50
+ } }),
51
+ onInbound: () => Effect.void
52
+ });
53
+ /**
54
+ * Probe with `server/discover`. A `DiscoverResult` means modern. A modern
55
+ * error code means modern-but-rejected: on `-32022` retry with a mutual
56
+ * version. Anything else yields `None`, i.e. "try the legacy handshake".
57
+ */
58
+ const probe = (connection) => discover(connection, LATEST_VERSION).pipe(Effect.map(Option.some), Effect.catch((error) => Option.match(modernRejection(error), {
59
+ onNone: () => Effect.succeedNone,
60
+ onSome: ({ supported }) => retryOnMutualVersion(connection, supported)
61
+ })));
62
+ const retryOnMutualVersion = (connection, offered) => Option.match(Option.firstSomeOf(offered.map(asProtocolVersion)), {
63
+ onNone: () => Effect.fail(new McpUnsupportedProtocol({
64
+ offered,
65
+ reason: "the server is modern but shares no protocol version with this client"
66
+ })),
67
+ onSome: (version) => discover(connection, version).pipe(Effect.map(Option.some))
68
+ });
69
+ const discover = (connection, version) => Effect.gen(function* () {
70
+ const probing = makeProtocol(version, UNKNOWN_SERVER);
71
+ const raw = yield* connection.request("server/discover", probing.envelope("server/discover", {}), probing.meta("server/discover", {}));
72
+ const result = yield* decodeDiscoverResult(raw).pipe(Effect.mapError(() => new McpUnsupportedProtocol({
73
+ offered: [],
74
+ reason: "server/discover returned an undecodable result"
75
+ })));
76
+ const agreed = result.supportedVersions.includes(version) ? version : Option.getOrElse(Option.firstSomeOf(result.supportedVersions.map(asProtocolVersion)), () => version);
77
+ const identity = result._meta?.["io.modelcontextprotocol/serverInfo"] ?? result.serverInfo ?? UNKNOWN_SERVER;
78
+ return makeProtocol(agreed, identity);
79
+ });
80
+ //#endregion
81
+ export { headerValue, probe };
82
+
83
+ //# sourceMappingURL=2026-07-28.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"2026-07-28.mjs","names":[],"sources":["../../../src/internal/protocols/2026-07-28.ts"],"sourcesContent":["/**\n * Protocol revision 2026-07-28: the stateless era. No handshake and no\n * session; every request self-describes via `_meta`, mirrored into the HTTP\n * request headers. Servers never send requests back, so `onInbound` has\n * nothing to answer.\n *\n * Files here are named for the revision they implement. A later revision that\n * keeps this wire shape gets its own file re-exporting this one.\n */\nimport { Effect, Encoding, Option, Predicate, Record, type Scope } from \"effect\"\nimport { type McpError, McpUnsupportedProtocol } from \"../../McpError.js\"\nimport { modernRejection, type Protocol, type ProtocolProbe } from \"../protocol.js\"\nimport type { McpConnection, SendMeta } from \"../rpc.js\"\nimport {\n asProtocolVersion,\n CLIENT_INFO,\n decodeDiscoverResult,\n META_CLIENT_CAPABILITIES,\n META_CLIENT_INFO,\n META_SERVER_INFO,\n META_PROTOCOL_VERSION,\n type McpMethod,\n LATEST_VERSION,\n type ProtocolVersion,\n type ServerInfo,\n} from \"../schema.js\"\n\nconst UNKNOWN_SERVER: ServerInfo = { name: \"unknown\" }\n\n/**\n * Which param field carries the subject name mirrored into `Mcp-Name`, per\n * method. Keyed by string rather than `McpMethod` so the methods a later\n * revision adds need no cast here.\n */\nconst NAME_FIELD: Record<string, string> = {\n \"tools/call\": \"name\",\n \"prompts/get\": \"name\",\n \"resources/read\": \"uri\",\n}\n\nconst subjectName = (method: McpMethod, params: unknown): Option.Option<string> =>\n Record.get(NAME_FIELD, method).pipe(\n Option.flatMap((field) => Record.get(asRecord(params), field)),\n Option.filter(Predicate.isString),\n )\n\nconst asRecord = (value: unknown): Record<string, unknown> =>\n Predicate.isObject(value) ? value : {}\n\nconst SENTINEL = /^=\\?base64\\?.*\\?=$/\n// Visible ASCII only, no leading or trailing space (RFC 9110 field values).\nconst HEADER_SAFE = /^[\\x21-\\x7e]([\\x20-\\x7e]*[\\x21-\\x7e])?$/\n\n/**\n * Header values outside the safe set (and any literal that would be mistaken\n * for the marker) ride the spec's Base64 sentinel form.\n */\nexport const headerValue = (raw: string): string =>\n HEADER_SAFE.test(raw) && !SENTINEL.test(raw) ? raw : `=?base64?${Encoding.encodeBase64(raw)}?=`\n\nconst makeProtocol = (version: ProtocolVersion, serverInfo: ServerInfo): Protocol => ({\n version,\n serverInfo,\n\n envelope: (_method, params) => ({\n ...asRecord(params),\n _meta: {\n [META_PROTOCOL_VERSION]: version,\n [META_CLIENT_INFO]: CLIENT_INFO,\n [META_CLIENT_CAPABILITIES]: {},\n },\n }),\n\n // `MCP-Protocol-Version` MUST equal the `_meta` version or the server\n // answers -32020, so both are minted from the same `version`.\n meta: (method, params): SendMeta => ({\n headers: {\n \"MCP-Protocol-Version\": version,\n \"Mcp-Method\": method,\n ...subjectName(method, params).pipe(\n Option.map((name) => ({ \"Mcp-Name\": headerValue(name) })),\n Option.getOrElse(() => ({})),\n ),\n },\n }),\n\n onInbound: () => Effect.void,\n})\n\n/**\n * Probe with `server/discover`. A `DiscoverResult` means modern. A modern\n * error code means modern-but-rejected: on `-32022` retry with a mutual\n * version. Anything else yields `None`, i.e. \"try the legacy handshake\".\n */\nexport const probe: ProtocolProbe = (connection) =>\n discover(connection, LATEST_VERSION).pipe(\n Effect.map(Option.some),\n Effect.catch((error) =>\n Option.match(modernRejection(error), {\n // Not a modern error shape, so this is not a modern server.\n onNone: () => Effect.succeedNone,\n onSome: ({ supported }) => retryOnMutualVersion(connection, supported),\n }),\n ),\n )\n\nconst retryOnMutualVersion = (\n connection: McpConnection,\n offered: ReadonlyArray<string>,\n): Effect.Effect<Option.Option<Protocol>, McpError, Scope.Scope> =>\n Option.match(Option.firstSomeOf(offered.map(asProtocolVersion)), {\n onNone: () =>\n Effect.fail(\n new McpUnsupportedProtocol({\n offered,\n reason: \"the server is modern but shares no protocol version with this client\",\n }),\n ),\n onSome: (version) => discover(connection, version).pipe(Effect.map(Option.some)),\n })\n\nconst discover = (\n connection: McpConnection,\n version: ProtocolVersion,\n): Effect.Effect<Protocol, McpError, Scope.Scope> =>\n Effect.gen(function* () {\n const probing = makeProtocol(version, UNKNOWN_SERVER)\n const raw = yield* connection.request(\n \"server/discover\",\n probing.envelope(\"server/discover\", {}),\n probing.meta(\"server/discover\", {}),\n )\n const result = yield* decodeDiscoverResult(raw).pipe(\n Effect.mapError(\n () =>\n new McpUnsupportedProtocol({\n offered: [],\n reason: \"server/discover returned an undecodable result\",\n }),\n ),\n )\n // The server answered on `version`, so it supports it; prefer it, and only\n // fall to its list if it somehow disagrees.\n const agreed = result.supportedVersions.includes(version)\n ? version\n : Option.getOrElse(\n Option.firstSomeOf(result.supportedVersions.map(asProtocolVersion)),\n () => version,\n )\n const identity = result._meta?.[META_SERVER_INFO] ?? result.serverInfo ?? UNKNOWN_SERVER\n return makeProtocol(agreed, identity)\n })\n"],"mappings":";;;;;;;;;;;;;;AA2BA,MAAM,iBAA6B,EAAE,MAAM,UAAU;;;;;;AAOrD,MAAM,aAAqC;CACzC,cAAc;CACd,eAAe;CACf,kBAAkB;AACpB;AAEA,MAAM,eAAe,QAAmB,WACtC,OAAO,IAAI,YAAY,MAAM,CAAC,CAAC,KAC7B,OAAO,SAAS,UAAU,OAAO,IAAI,SAAS,MAAM,GAAG,KAAK,CAAC,GAC7D,OAAO,OAAO,UAAU,QAAQ,CAClC;AAEF,MAAM,YAAY,UAChB,UAAU,SAAS,KAAK,IAAI,QAAQ,CAAC;AAEvC,MAAM,WAAW;AAEjB,MAAM,cAAc;;;;;AAMpB,MAAa,eAAe,QAC1B,YAAY,KAAK,GAAG,KAAK,CAAC,SAAS,KAAK,GAAG,IAAI,MAAM,YAAY,SAAS,aAAa,GAAG,EAAE;AAE9F,MAAM,gBAAgB,SAA0B,gBAAsC;CACpF;CACA;CAEA,WAAW,SAAS,YAAY;EAC9B,GAAG,SAAS,MAAM;EAClB,OAAO;IACJ,wBAAwB;IACxB,mBAAmB;IACnB,2BAA2B,CAAC;EAC/B;CACF;CAIA,OAAO,QAAQ,YAAsB,EACnC,SAAS;EACP,wBAAwB;EACxB,cAAc;EACd,GAAG,YAAY,QAAQ,MAAM,CAAC,CAAC,KAC7B,OAAO,KAAK,UAAU,EAAE,YAAY,YAAY,IAAI,EAAE,EAAE,GACxD,OAAO,iBAAiB,CAAC,EAAE,CAC7B;CACF,EACF;CAEA,iBAAiB,OAAO;AAC1B;;;;;;AAOA,MAAa,SAAwB,eACnC,SAAS,YAAY,cAAc,CAAC,CAAC,KACnC,OAAO,IAAI,OAAO,IAAI,GACtB,OAAO,OAAO,UACZ,OAAO,MAAM,gBAAgB,KAAK,GAAG;CAEnC,cAAc,OAAO;CACrB,SAAS,EAAE,gBAAgB,qBAAqB,YAAY,SAAS;AACvE,CAAC,CACH,CACF;AAEF,MAAM,wBACJ,YACA,YAEA,OAAO,MAAM,OAAO,YAAY,QAAQ,IAAI,iBAAiB,CAAC,GAAG;CAC/D,cACE,OAAO,KACL,IAAI,uBAAuB;EACzB;EACA,QAAQ;CACV,CAAC,CACH;CACF,SAAS,YAAY,SAAS,YAAY,OAAO,CAAC,CAAC,KAAK,OAAO,IAAI,OAAO,IAAI,CAAC;AACjF,CAAC;AAEH,MAAM,YACJ,YACA,YAEA,OAAO,IAAI,aAAa;CACtB,MAAM,UAAU,aAAa,SAAS,cAAc;CACpD,MAAM,MAAM,OAAO,WAAW,QAC5B,mBACA,QAAQ,SAAS,mBAAmB,CAAC,CAAC,GACtC,QAAQ,KAAK,mBAAmB,CAAC,CAAC,CACpC;CACA,MAAM,SAAS,OAAO,qBAAqB,GAAG,CAAC,CAAC,KAC9C,OAAO,eAEH,IAAI,uBAAuB;EACzB,SAAS,CAAC;EACV,QAAQ;CACV,CAAC,CACL,CACF;CAGA,MAAM,SAAS,OAAO,kBAAkB,SAAS,OAAO,IACpD,UACA,OAAO,UACL,OAAO,YAAY,OAAO,kBAAkB,IAAI,iBAAiB,CAAC,SAC5D,OACR;CACJ,MAAM,WAAW,OAAO,QAAA,yCAA6B,OAAO,cAAc;CAC1E,OAAO,aAAa,QAAQ,QAAQ;AACtC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { a as open, i as Transport, n as McpConnection, r as SendMeta, t as Inbound } from "../rpc-Bq95Lio9.mjs";
2
+ export { Inbound, McpConnection, SendMeta, Transport, open };
@@ -0,0 +1,78 @@
1
+ import { McpProtocolError, McpTransportClosed } from "../McpError.mjs";
2
+ import { decodeInboundMessage, errorFrame, notificationFrame, requestFrame, resultFrame } from "./schema.mjs";
3
+ import { Cause, Deferred, Effect, HashMap, Option, Ref, Stream } from "effect";
4
+ import * as JSONL from "@effect-uai/core/JSONL";
5
+ //#region src/internal/rpc.ts
6
+ /**
7
+ * Era-blind JSON-RPC 2.0 correlation core over a `Transport` (cdp.ts model):
8
+ * pending-`Deferred` map keyed by id, reader fiber that fails every pending
9
+ * request on transport close. Era behavior layers on top in era.ts.
10
+ */
11
+ const replyError = (method, error) => new McpProtocolError({
12
+ method,
13
+ code: error.code,
14
+ ...error.message !== void 0 ? { reason: error.message } : {},
15
+ raw: error
16
+ });
17
+ /**
18
+ * Open a scoped connection over an already-open transport. `onInbound`
19
+ * receives server-initiated frames; era.ts answers them via `transport.send`.
20
+ */
21
+ const open = (transport, onInbound) => Effect.gen(function* () {
22
+ const pending = yield* Ref.make(HashMap.empty());
23
+ const counter = yield* Ref.make(0);
24
+ const closeCause = yield* Ref.make(void 0);
25
+ const failAllPending = (toError) => Ref.getAndSet(pending, HashMap.empty()).pipe(Effect.flatMap((taken) => Effect.forEach(HashMap.values(taken), ({ deferred, method }) => Deferred.fail(deferred, toError(method)))), Effect.asVoid);
26
+ const unattributable = (error) => error === void 0 ? Effect.void : failAllPending((method) => replyError(method, error));
27
+ const settle = ({ deferred, method }, message) => Effect.asVoid(message.error === void 0 ? Deferred.succeed(deferred, message.result ?? {}) : Deferred.fail(deferred, replyError(method, message.error)));
28
+ const reply = (id, message) => Ref.modify(pending, (m) => [HashMap.get(m, id), HashMap.remove(m, id)]).pipe(Effect.flatMap(Option.match({
29
+ onNone: () => unattributable(message.error),
30
+ onSome: (entry) => settle(entry, message)
31
+ })));
32
+ const route = (message) => Option.match(Option.fromNullishOr(message.method), {
33
+ onNone: () => Option.match(Option.fromNullishOr(message.id), {
34
+ onNone: () => unattributable(message.error),
35
+ onSome: (id) => reply(id, message)
36
+ }),
37
+ onSome: (method) => onInbound({
38
+ id: Option.fromNullishOr(message.id),
39
+ method,
40
+ params: message.params
41
+ })
42
+ });
43
+ const dispatch = (raw) => JSONL.parseSafe(raw).pipe(Effect.flatMap((json) => Effect.option(decodeInboundMessage(json))), Effect.flatMap(Option.match({
44
+ onNone: () => Effect.void,
45
+ onSome: route
46
+ })));
47
+ const failPending = Effect.gen(function* () {
48
+ const raw = yield* Ref.get(closeCause);
49
+ yield* failAllPending((method) => new McpTransportClosed({
50
+ method,
51
+ reason: "connection closed",
52
+ raw
53
+ }));
54
+ });
55
+ yield* transport.messages.pipe(Stream.runForEach(dispatch), Effect.tapCause((cause) => Ref.set(closeCause, Cause.squash(cause))), Effect.ensuring(failPending), Effect.forkScoped);
56
+ const request = (method, params, meta) => Effect.gen(function* () {
57
+ const id = yield* Ref.updateAndGet(counter, (n) => n + 1);
58
+ const deferred = yield* Deferred.make();
59
+ yield* Ref.update(pending, (m) => HashMap.set(m, id, {
60
+ method,
61
+ deferred
62
+ }));
63
+ return yield* transport.send(requestFrame(id, method, params), meta).pipe(Effect.flatMap(() => Deferred.await(deferred)), Effect.ensuring(Ref.update(pending, (m) => HashMap.remove(m, id))));
64
+ });
65
+ const notify = (method, params, meta) => transport.send(notificationFrame(method, params), meta);
66
+ const respond = (id, result) => transport.send(resultFrame(id, result));
67
+ const respondError = (id, code, message) => transport.send(errorFrame(id, code, message));
68
+ return {
69
+ request,
70
+ notify,
71
+ respond,
72
+ respondError
73
+ };
74
+ });
75
+ //#endregion
76
+ export { open };
77
+
78
+ //# sourceMappingURL=rpc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.mjs","names":[],"sources":["../../src/internal/rpc.ts"],"sourcesContent":["/**\n * Era-blind JSON-RPC 2.0 correlation core over a `Transport` (cdp.ts model):\n * pending-`Deferred` map keyed by id, reader fiber that fails every pending\n * request on transport close. Era behavior layers on top in era.ts.\n */\nimport { Cause, Deferred, Effect, HashMap, Option, Ref, type Scope, Stream } from \"effect\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport { type McpError, McpProtocolError, McpTransportClosed } from \"../McpError.js\"\nimport {\n decodeInboundMessage,\n type InboundMessage,\n type JsonRpcId,\n errorFrame,\n notificationFrame,\n requestFrame,\n resultFrame,\n} from \"./schema.js\"\n\n/** Per-request transport hints (era headers on HTTP; stdio ignores them). */\nexport type SendMeta = {\n readonly headers?: Record<string, string>\n}\n\n/** The transport seam: one framed JSON message per `send` / `messages` element. */\nexport type Transport = {\n readonly send: (frame: string, meta?: SendMeta) => Effect.Effect<void, McpError>\n readonly messages: Stream.Stream<string, McpError>\n}\n\n/** A server-initiated request (has `id`) or notification (no `id`). */\nexport type Inbound = {\n readonly id: Option.Option<JsonRpcId>\n readonly method: string\n readonly params: unknown\n}\n\nexport type McpConnection = {\n readonly request: (\n method: string,\n params?: unknown,\n meta?: SendMeta,\n ) => Effect.Effect<unknown, McpError>\n readonly notify: (\n method: string,\n params?: unknown,\n meta?: SendMeta,\n ) => Effect.Effect<void, McpError>\n /** Answer a server-initiated request (legacy era only). */\n readonly respond: (id: JsonRpcId, result: unknown) => Effect.Effect<void, McpError>\n readonly respondError: (\n id: JsonRpcId,\n code: number,\n message: string,\n ) => Effect.Effect<void, McpError>\n}\n\ntype Pending = {\n readonly method: string\n readonly deferred: Deferred.Deferred<unknown, McpError>\n}\n\nconst replyError = (method: string, error: NonNullable<InboundMessage[\"error\"]>): McpError =>\n new McpProtocolError({\n method,\n code: error.code,\n ...(error.message !== undefined ? { reason: error.message } : {}),\n raw: error,\n })\n\n/**\n * Open a scoped connection over an already-open transport. `onInbound`\n * receives server-initiated frames; era.ts answers them via `transport.send`.\n */\nexport const open = (\n transport: Transport,\n onInbound: (inbound: Inbound) => Effect.Effect<void>,\n): Effect.Effect<McpConnection, never, Scope.Scope> =>\n Effect.gen(function* () {\n const pending = yield* Ref.make(HashMap.empty<JsonRpcId, Pending>())\n const counter = yield* Ref.make(0)\n const closeCause = yield* Ref.make<unknown>(undefined)\n\n // Fail every in-flight request with one error. Shared by transport close\n // and by unattributable server errors: a caller must never be left\n // awaiting a reply that cannot arrive.\n const failAllPending = (toError: (method: string) => McpError): Effect.Effect<void> =>\n Ref.getAndSet(pending, HashMap.empty()).pipe(\n Effect.flatMap((taken) =>\n Effect.forEach(HashMap.values(taken), ({ deferred, method }) =>\n Deferred.fail(deferred, toError(method)),\n ),\n ),\n Effect.asVoid,\n )\n\n // An error no pending request can claim: a null id (JSON-RPC raises one\n // before the request could be attributed) or an id we never issued. It\n // correlates to nothing, so everything in flight takes it rather than\n // waiting for a reply that cannot arrive. A *result* nobody claims is a\n // late or duplicate reply, and is simply dropped.\n const unattributable = (error: InboundMessage[\"error\"]): Effect.Effect<void> =>\n error === undefined ? Effect.void : failAllPending((method) => replyError(method, error))\n\n const settle = ({ deferred, method }: Pending, message: InboundMessage): Effect.Effect<void> =>\n Effect.asVoid(\n message.error === undefined\n ? Deferred.succeed(deferred, message.result ?? {})\n : Deferred.fail(deferred, replyError(method, message.error)),\n )\n\n const reply = (id: JsonRpcId, message: InboundMessage): Effect.Effect<void> =>\n Ref.modify(pending, (m) => [HashMap.get(m, id), HashMap.remove(m, id)]).pipe(\n Effect.flatMap(\n Option.match({\n onNone: () => unattributable(message.error),\n onSome: (entry) => settle(entry, message),\n }),\n ),\n )\n\n // A frame carrying a `method` is server-initiated; anything else is a\n // reply, correlated by id.\n const route = (message: InboundMessage): Effect.Effect<void> =>\n Option.match(Option.fromNullishOr(message.method), {\n onNone: () =>\n Option.match(Option.fromNullishOr(message.id), {\n onNone: () => unattributable(message.error),\n onSome: (id) => reply(id, message),\n }),\n onSome: (method) =>\n onInbound({ id: Option.fromNullishOr(message.id), method, params: message.params }),\n })\n\n // Unparseable and undecodable frames are dropped: one bad frame must not\n // end an otherwise healthy connection.\n const dispatch = (raw: string): Effect.Effect<void> =>\n JSONL.parseSafe(raw).pipe(\n Effect.flatMap((json) => Effect.option(decodeInboundMessage(json))),\n Effect.flatMap(Option.match({ onNone: () => Effect.void, onSome: route })),\n )\n\n // Fail every still-pending request on transport close so callers never hang.\n const failPending = Effect.gen(function* () {\n const raw = yield* Ref.get(closeCause)\n yield* failAllPending(\n (method) => new McpTransportClosed({ method, reason: \"connection closed\", raw }),\n )\n })\n yield* transport.messages.pipe(\n Stream.runForEach(dispatch),\n Effect.tapCause((cause) => Ref.set(closeCause, Cause.squash(cause))),\n Effect.ensuring(failPending),\n Effect.forkScoped,\n )\n\n const request = (\n method: string,\n params?: unknown,\n meta?: SendMeta,\n ): Effect.Effect<unknown, McpError> =>\n Effect.gen(function* () {\n const id: JsonRpcId = yield* Ref.updateAndGet(counter, (n) => n + 1)\n const deferred = yield* Deferred.make<unknown, McpError>()\n yield* Ref.update(pending, (m) => HashMap.set(m, id, { method, deferred }))\n // `ensuring` reclaims the entry on send failure and interruption; on\n // success dispatch has already removed it.\n return yield* transport.send(requestFrame(id, method, params), meta).pipe(\n Effect.flatMap(() => Deferred.await(deferred)),\n Effect.ensuring(Ref.update(pending, (m) => HashMap.remove(m, id))),\n )\n })\n\n const notify = (\n method: string,\n params?: unknown,\n meta?: SendMeta,\n ): Effect.Effect<void, McpError> => transport.send(notificationFrame(method, params), meta)\n\n const respond = (id: JsonRpcId, result: unknown): Effect.Effect<void, McpError> =>\n transport.send(resultFrame(id, result))\n\n const respondError = (\n id: JsonRpcId,\n code: number,\n message: string,\n ): Effect.Effect<void, McpError> => transport.send(errorFrame(id, code, message))\n\n return { request, notify, respond, respondError }\n })\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { A as decodeCallToolResult, B as resultFrame, C as ProtocolVersion, D as ToolInfo, E as TextContent, F as decodeUnsupportedVersionData, I as errorFrame, L as isTextContent, M as decodeInboundMessage, N as decodeInitializeResult, O as UnsupportedVersionData, P as decodeListToolsResult, R as notificationFrame, S as OtherContent, T as ServerInfo, _ as META_CLIENT_INFO, a as CODE_UNSUPPORTED_PROTOCOL_VERSION, b as MODERN_ERROR_CODES, c as DiscoverResult, d as JsonRpcErrorObject, f as JsonRpcId, g as META_CLIENT_CAPABILITIES, h as ListToolsResult, i as CODE_MISSING_CLIENT_CAPABILITY, j as decodeDiscoverResult, k as asProtocolVersion, l as InboundMessage, m as LEGACY_VERSION, n as CODE_HEADER_MISMATCH, o as CallToolResult, p as LATEST_VERSION, r as CODE_METHOD_NOT_FOUND, s as ContentBlock, t as CLIENT_INFO, u as InitializeResult, v as META_PROTOCOL_VERSION, w as ResultMeta, x as McpMethod, y as META_SERVER_INFO, z as requestFrame } from "../schema-D2oUNuo5.mjs";
2
+ export { CLIENT_INFO, CODE_HEADER_MISMATCH, CODE_METHOD_NOT_FOUND, CODE_MISSING_CLIENT_CAPABILITY, CODE_UNSUPPORTED_PROTOCOL_VERSION, CallToolResult, ContentBlock, DiscoverResult, InboundMessage, InitializeResult, JsonRpcErrorObject, JsonRpcId, LATEST_VERSION, LEGACY_VERSION, ListToolsResult, META_CLIENT_CAPABILITIES, META_CLIENT_INFO, META_PROTOCOL_VERSION, META_SERVER_INFO, MODERN_ERROR_CODES, McpMethod, OtherContent, ProtocolVersion, ResultMeta, ServerInfo, TextContent, ToolInfo, UnsupportedVersionData, asProtocolVersion, decodeCallToolResult, decodeDiscoverResult, decodeInboundMessage, decodeInitializeResult, decodeListToolsResult, decodeUnsupportedVersionData, errorFrame, isTextContent, notificationFrame, requestFrame, resultFrame };