@orkestrel/mcp 0.0.26 → 0.0.27

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.
@@ -1,12 +1,12 @@
1
1
  import { createSSEParser } from "@orkestrel/sse";
2
- import { JSONRPC_INVALID_PARAMS, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_PARSE_ERROR, MCP_HANDSHAKE_VERSION, MCP_HEADER_MISMATCH, MCP_META_VERSION, MCP_MISSING_CAPABILITY, MCP_UNSUPPORTED_VERSION, SUPPORTED_LEGACY_PROTOCOL_VERSIONS, bindServer, buildJSONRPCError, inferRequestVersion, isInitializeRequest, isJSONRPCInvocation, isJSONRPCResponse, isMCPLegacyVersion, isMCPVersion, isModernRequest, parseJSONRPCMessage, parseRequestContext } from "../core/index.js";
3
- import { isRecord, isString, sanitizeBudget } from "@orkestrel/contract";
2
+ import { JSONRPC_INVALID_PARAMS, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_PARSE_ERROR, MCP_HANDSHAKE_VERSION, MCP_HEADER_MISMATCH, MCP_LOOKUP_PAGES, MCP_META_VERSION, MCP_MISSING_CAPABILITY, MCP_PARAM_PREFIX, MCP_UNSUPPORTED_VERSION, SUPPORTED_LEGACY_PROTOCOL_VERSIONS, bindServer, buildHeaderParameters, buildHeaderProjection, buildJSONRPCError, decodeSentinel, encodeSentinel, extractToolSchema, inferRequestVersion, isInitializeRequest, isJSONRPCInvocation, isJSONRPCResponse, isMCPLegacyVersion, isMCPModernVersion, isMCPVersion, isModernRequest, parseJSONRPCMessage, parseRequestContext, renderHeaderValue } from "../core/index.js";
3
+ import { isArray, isRecord, isString, sanitizeBudget } from "@orkestrel/contract";
4
4
  import { openStream, signToken, verifyToken } from "@orkestrel/server";
5
5
  import { Emitter } from "@orkestrel/emitter";
6
+ import { WEBSOCKET_READY_OPEN, WEBSOCKET_VERSION, computeWebSocketAccept, createNodeWebSocket } from "@orkestrel/websocket";
6
7
  import { randomBytes } from "node:crypto";
7
8
  import { request } from "node:http";
8
9
  import { request as request$1 } from "node:https";
9
- import { WEBSOCKET_VERSION, computeWebSocketAccept, createNodeWebSocket } from "@orkestrel/websocket";
10
10
  import { Process } from "@orkestrel/process/server";
11
11
  import { PROCESS_GRACE } from "@orkestrel/process";
12
12
  import { Readable } from "node:stream";
@@ -526,13 +526,51 @@ function bridgeMessageTransport(transport) {
526
526
  //#endregion
527
527
  //#region src/server/inferers.ts
528
528
  /**
529
+ * Infers the target one modern request's `Mcp-Name` header must carry.
530
+ *
531
+ * @remarks
532
+ * The protocol scopes the header to the methods whose body carries a name-shaped field, and
533
+ * names the field per method: `tools/call` and `prompts/get` carry `params.name`, and
534
+ * `resources/read` carries `params.uri`. Every other method — `server/discover`, `tools/list`,
535
+ * `resources/list`, `prompts/list` — has nothing to derive a target from, so the header is not
536
+ * required there and a peer that sent one anyway is not held to it.
537
+ *
538
+ * A method within the scope whose named member is absent or is not a string reads as no
539
+ * target. There is nothing for a header to match, and refusing the request over a body member
540
+ * the header rule does not own would report a parameter fault as a header fault. Total.
541
+ *
542
+ * @param request - The parsed modern invocation to read the target from
543
+ * @returns The target the header must carry, or `undefined` when the method carries none
544
+ *
545
+ * @example
546
+ * ```ts
547
+ * inferHeaderTarget({ jsonrpc: '2.0', id: 1, method: 'resources/read', params: { uri: 'file:///a' } })
548
+ * // → 'file:///a'
549
+ * ```
550
+ */
551
+ function inferHeaderTarget(request) {
552
+ if (request.method === "tools/call" || request.method === "prompts/get") {
553
+ const name = request.params?.["name"];
554
+ return isString(name) ? name : void 0;
555
+ }
556
+ if (request.method === "resources/read") {
557
+ const uri = request.params?.["uri"];
558
+ return isString(uri) ? uri : void 0;
559
+ }
560
+ }
561
+ /**
529
562
  * Infers the first required MCP HTTP header that is missing or mismatched.
530
563
  *
531
564
  * @remarks
532
- * A modern request derives its protocol, method, and tools/call-only name expectations from
533
- * the JSON-RPC body. A legacy request body requires a protocol header after initialization,
534
- * while a supplied legacy session version additionally diagnoses a header that disagrees with
535
- * the active session. Messages name the expected value but never echo the client-supplied one.
565
+ * A modern request derives its protocol, method, and name expectations from the JSON-RPC body,
566
+ * the name expectation scoped to the methods {@link inferHeaderTarget} reads a target for. A
567
+ * name header carrying the Base64 sentinel is decoded through
568
+ * {@link import('@orkestrel/mcp').decodeSentinel} before the comparison, so a peer that had
569
+ * to encode its value still matches; a sentinel whose payload is invalid decodes to nothing
570
+ * and therefore mismatches, which is how an invalid header value is refused. A legacy request
571
+ * body requires a protocol header after initialization, while a supplied legacy session
572
+ * version additionally diagnoses a header that disagrees with the active session. Messages
573
+ * name the expected value but never echo the client-supplied one.
536
574
  *
537
575
  * @param request - The HTTP request carrying the headers
538
576
  * @param reference - The parsed invocation body, or the active legacy session version
@@ -591,22 +629,73 @@ function inferHeaderIssue(request, reference) {
591
629
  reason: "mismatched",
592
630
  message: `Mcp-Method header does not match the request body method '${message.method}'.`
593
631
  };
594
- if (message.method !== "tools/call") return void 0;
595
- const name = message.params?.["name"];
596
- if (!isString(name)) return void 0;
632
+ const target = inferHeaderTarget(message);
633
+ if (target === void 0) return void 0;
597
634
  const header = request.headers.get(MCP_NAME_HEADER);
598
635
  if (header === null) return {
599
636
  header: "Mcp-Name",
600
637
  reason: "missing",
601
- message: `Required Mcp-Name header is missing; the request body tool name is '${name}'.`
638
+ message: `Required Mcp-Name header is missing; the request body target is '${target}'.`
602
639
  };
603
- if (header !== name) return {
640
+ if (decodeSentinel(header) !== target) return {
604
641
  header: "Mcp-Name",
605
642
  reason: "mismatched",
606
- message: `Mcp-Name header does not match the request body tool name '${name}'.`
643
+ message: `Mcp-Name header does not match the request body target '${target}'.`
607
644
  };
608
645
  }
609
646
  /**
647
+ * Infers the refusal one `tools/call` earns for a `Mcp-Param-*` header the body contradicts.
648
+ *
649
+ * @remarks
650
+ * The custom-header half of the standard-header seam {@link inferHeaderIssue} owns, and it
651
+ * takes the SERVED definition's projections rather than a header issue: SEP-2243 scopes the
652
+ * rule to the `Mcp-Param-*` names the server's OWN tool definitions annotate, so a name no
653
+ * parameter claims is another party's header and travels through untouched.
654
+ *
655
+ * For each recognized parameter the body's value at the parameter's own property path fixes
656
+ * the expectation. A value the call omits or supplies as `null` requires no header, and a
657
+ * header sent anyway is refused because it asserts something the body never said. A value the
658
+ * call does supply requires its header: an absent one, a Base64 sentinel whose payload is
659
+ * invalid, and a decoded value that disagrees are each refused. An `integer` parameter
660
+ * compares numerically, so a peer that padded its decimal still matches. A supplied value
661
+ * whose runtime shape contradicts the declared type is left alone — the tool's own argument
662
+ * validation owns that disagreement, and refusing it here would report an argument fault as a
663
+ * header fault.
664
+ *
665
+ * Messages name the field and the body path the expectation came from, and never echo the
666
+ * value the peer supplied.
667
+ *
668
+ * @param request - The HTTP request carrying the headers
669
+ * @param parameters - The projections the served tool definition declares
670
+ * @param values - The call's `arguments` record
671
+ * @returns The refusal message for the first disagreeing parameter, or `undefined`
672
+ *
673
+ * @example
674
+ * ```ts
675
+ * inferParameterRefusal(request, [{ name: 'Region', path: ['region'], primitive: 'string' }], {})
676
+ * // → undefined when the request carries no `Mcp-Param-Region` either
677
+ * ```
678
+ */
679
+ function inferParameterRefusal(request, parameters, values) {
680
+ for (const parameter of parameters) {
681
+ let carried = values;
682
+ for (const key of parameter.path) carried = isRecord(carried) ? carried[key] : void 0;
683
+ const field = `${MCP_PARAM_PREFIX}${parameter.name}`;
684
+ const path = parameter.path.join(".");
685
+ const header = request.headers.get(field);
686
+ if (carried === void 0 || carried === null) {
687
+ if (header === null) continue;
688
+ return `${field} header carries a value the request body omits at '${path}'.`;
689
+ }
690
+ const expected = renderHeaderValue(carried, parameter.primitive);
691
+ if (expected === void 0) continue;
692
+ if (header === null) return `Required ${field} header is missing; the request body carries '${path}'.`;
693
+ const decoded = decodeSentinel(header);
694
+ if (decoded === void 0) return `${field} header value is not a valid Base64 sentinel.`;
695
+ if (!(parameter.primitive === "integer" ? decoded.trim() !== "" && Number(decoded) === Number(expected) : decoded === expected)) return `${field} header does not match the request body value at '${path}'.`;
696
+ }
697
+ }
698
+ /**
610
699
  * Infers the legacy revision an `initialize` request negotiates.
611
700
  *
612
701
  * @remarks
@@ -784,12 +873,17 @@ var HTTPDisconnect = class {
784
873
  * Creates the Streamable-HTTP POST handler used by `createMCPRoutes`.
785
874
  *
786
875
  * @remarks
787
- * Modern requests require matching protocol/method headers and a matching name header only
788
- * for `tools/call`; mismatch returns HTTP `400` + `-32020`. Headerless `initialize` is
789
- * accepted, while every other headerless request needs a live legacy session to supply its
790
- * pinned version. A legacy-shaped request carrying a protocol header is admitted only for a
791
- * legacy revision; any other value, the modern revision included, returns HTTP `400` + `-32022`
792
- * whose `supported` names the legacy revisions this door accepts. A present origin must occur in `origin.origins` unless validation is
876
+ * Modern requests require matching protocol/method headers and a matching name header on each
877
+ * method carrying a named target — `tools/call` and `prompts/get` against `params.name`,
878
+ * `resources/read` against `params.uri` with a Base64-sentinel value decoded before the
879
+ * comparison; a missing, mismatched, or invalidly encoded value returns HTTP `400` + `-32020`.
880
+ * A protocol header naming a MODERN revision holds the request to that revision whatever shape
881
+ * its body arrived in, so a body with no parsable modern `_meta` returns HTTP `400` + `-32602`.
882
+ * Headerless `initialize` is accepted, while every other headerless request needs a live legacy
883
+ * session to supply its pinned version. A legacy-shaped request carrying a protocol header is
884
+ * otherwise admitted only for a legacy revision; a revision this server does not implement
885
+ * returns HTTP `400` + `-32022` whose `supported` names the legacy revisions this door accepts.
886
+ * A present origin must occur in `origin.origins` unless validation is
793
887
  * explicitly delegated upstream. Modern dispatch errors use their protocol status map; legacy
794
888
  * errors remain in-band at HTTP `200`. A streamed response composes the fetch-standard request
795
889
  * signal with response-body cancellation and supplies the result to every dispatched modern
@@ -838,11 +932,42 @@ function createMCPPostHandler(mcp, options) {
838
932
  const era = isModernRequest(invocation) ? "modern" : "legacy";
839
933
  const id = invocation.id;
840
934
  const protocol = request.headers.get(MCP_PROTOCOL_VERSION_HEADER);
841
- if (era === "modern") {
935
+ if (era === "modern" || isMCPModernVersion(protocol)) {
842
936
  if (parseRequestContext(invocation) === void 0) return Response.json(buildJSONRPCError(id, JSONRPC_INVALID_PARAMS, "Invalid params: malformed modern request metadata"), { status: 400 });
843
937
  }
844
938
  const issue = inferHeaderIssue(request, invocation);
845
939
  if (issue !== void 0) return Response.json(buildJSONRPCError(id, MCP_HEADER_MISMATCH, issue.message), { status: 400 });
940
+ const called = invocation.params?.["name"];
941
+ if (era === "modern" && invocation.method === "tools/call" && isString(called)) {
942
+ let parameters = [];
943
+ let cursor = void 0;
944
+ for (let page = 0; page < MCP_LOOKUP_PAGES; page += 1) {
945
+ const answer = await mcp.dispatch({
946
+ jsonrpc: "2.0",
947
+ id: 0,
948
+ method: "tools/list",
949
+ params: {
950
+ _meta: invocation.params?.["_meta"],
951
+ ...cursor === void 0 ? {} : { cursor }
952
+ }
953
+ });
954
+ if (Symbol.asyncIterator in answer) {
955
+ answer.stop();
956
+ break;
957
+ }
958
+ const schema = extractToolSchema(answer, called);
959
+ if (schema !== void 0) {
960
+ parameters = buildHeaderParameters(schema) ?? [];
961
+ break;
962
+ }
963
+ const listing = answer.result;
964
+ const next = isRecord(listing) ? listing["nextCursor"] : void 0;
965
+ if (!isString(next)) break;
966
+ cursor = next;
967
+ }
968
+ const refusal = inferParameterRefusal(request, parameters, invocation.params?.["arguments"]);
969
+ if (refusal !== void 0) return Response.json(buildJSONRPCError(id, MCP_HEADER_MISMATCH, refusal), { status: 400 });
970
+ }
846
971
  if (era === "legacy") {
847
972
  if (protocol !== null && !isMCPLegacyVersion(protocol)) return Response.json(buildJSONRPCError(id, MCP_UNSUPPORTED_VERSION, `Unsupported MCP protocol version '${protocol}'`, {
848
973
  supported: SUPPORTED_LEGACY_PROTOCOL_VERSIONS,
@@ -903,7 +1028,8 @@ function createMCPPostHandler(mcp, options) {
903
1028
  * initialize result's `protocolVersion` is likewise captured, but only
904
1029
  * when it is a SUPPORTED value, and echoed as `mcp-protocol-version` alone on
905
1030
  * subsequent legacy requests. Modern requests instead derive protocol and method
906
- * headers from the message, plus the name header only for `tools/call`.
1031
+ * headers from the message, plus the name header only for `tools/call` — carried in the
1032
+ * protocol's Base64 sentinel form whenever the tool name cannot ride as plain ASCII.
907
1033
  * Before initialize returns, neither captured legacy header is sent.
908
1034
  * `close()` clears the captured protocol so a reconnect's `initialize`
909
1035
  * POST is headerless; the captured `session` persists across `close()`.
@@ -934,8 +1060,11 @@ var HTTPClientTransport = class {
934
1060
  #fetch;
935
1061
  #timeout;
936
1062
  #pending = /* @__PURE__ */ new Set();
1063
+ #parameters = /* @__PURE__ */ new Map();
1064
+ #stamps = /* @__PURE__ */ new WeakMap();
937
1065
  #session = void 0;
938
1066
  #protocol = void 0;
1067
+ #generation = 0;
939
1068
  #closed = false;
940
1069
  constructor(options) {
941
1070
  this.#emitter = new Emitter();
@@ -957,6 +1086,7 @@ var HTTPClientTransport = class {
957
1086
  this.#closed = false;
958
1087
  }
959
1088
  async send(message) {
1089
+ this.#stamp(message);
960
1090
  const request = new AbortController();
961
1091
  this.#pending.add(request);
962
1092
  try {
@@ -965,6 +1095,11 @@ var HTTPClientTransport = class {
965
1095
  this.#pending.delete(request);
966
1096
  }
967
1097
  }
1098
+ #stamp(message) {
1099
+ if (!isModernRequest(message) || message.method !== "tools/list") return;
1100
+ if (message.params?.["cursor"] === void 0) this.#generation += 1;
1101
+ this.#stamps.set(message, this.#generation);
1102
+ }
968
1103
  async #exchange(message, signal) {
969
1104
  let response;
970
1105
  try {
@@ -986,7 +1121,7 @@ var HTTPClientTransport = class {
986
1121
  }
987
1122
  const session = response.headers.get(MCP_SESSION_HEADER);
988
1123
  if (session !== null) this.#session = session;
989
- await this.#deliver(response);
1124
+ await this.#deliver(response, message);
990
1125
  }
991
1126
  async close() {
992
1127
  if (this.#closed) return;
@@ -1003,12 +1138,15 @@ var HTTPClientTransport = class {
1003
1138
  return {
1004
1139
  ...version === void 0 ? {} : { [MCP_PROTOCOL_VERSION_HEADER]: version },
1005
1140
  [MCP_METHOD_HEADER]: message.method,
1006
- ...message.method === "tools/call" && isString(name) ? { [MCP_NAME_HEADER]: name } : {}
1141
+ ...message.method === "tools/call" && isString(name) ? {
1142
+ [MCP_NAME_HEADER]: encodeSentinel(name),
1143
+ ...buildHeaderProjection(this.#parameters.get(name) ?? [], message.params?.["arguments"])
1144
+ } : {}
1007
1145
  };
1008
1146
  }
1009
1147
  return this.#protocol === void 0 ? {} : { [MCP_PROTOCOL_VERSION_HEADER]: this.#protocol };
1010
1148
  }
1011
- async #deliver(response) {
1149
+ async #deliver(response, sent) {
1012
1150
  if (response.status === 202) return;
1013
1151
  const type = response.headers.get("content-type") ?? "";
1014
1152
  let messages = [];
@@ -1022,13 +1160,43 @@ var HTTPClientTransport = class {
1022
1160
  } catch (error) {
1023
1161
  failure = { error };
1024
1162
  }
1025
- for (const message of messages) this.#capture(message);
1163
+ for (const message of messages) this.#capture(message, sent);
1026
1164
  if (!response.ok && messages.length === 0) throw buildResponseError(response, type);
1027
1165
  if (failure !== void 0) this.#emitter.emit("error", failure.error);
1028
1166
  }
1029
- #capture(message) {
1167
+ #capture(message, sent) {
1030
1168
  if (isJSONRPCResponse(message) && isRecord(message.result) && isMCPVersion(message.result["protocolVersion"])) this.#protocol = message.result["protocolVersion"];
1031
- this.#emitter.emit("message", message);
1169
+ this.#emitter.emit("message", this.#select(message, sent));
1170
+ }
1171
+ #select(message, sent) {
1172
+ if (!isModernRequest(sent) || sent.method !== "tools/list") return message;
1173
+ if (!isJSONRPCResponse(message) || message.error !== void 0) return message;
1174
+ const result = message.result;
1175
+ const listed = isRecord(result) ? result["tools"] : void 0;
1176
+ if (!isRecord(result) || !isArray(listed)) return message;
1177
+ const current = this.#stamps.get(sent) === this.#generation;
1178
+ if (current && sent.params?.["cursor"] === void 0) this.#parameters.clear();
1179
+ const kept = [];
1180
+ for (const tool of listed) {
1181
+ if (!isRecord(tool) || !isString(tool["name"])) {
1182
+ kept.push(tool);
1183
+ continue;
1184
+ }
1185
+ const parameters = buildHeaderParameters(tool["inputSchema"]);
1186
+ if (parameters === void 0) {
1187
+ this.#emitter.emit("error", /* @__PURE__ */ new Error(`MCP tool '${tool["name"]}' is excluded from tools/list: its inputSchema carries an invalid x-mcp-header annotation`));
1188
+ continue;
1189
+ }
1190
+ if (current) this.#parameters.set(tool["name"], parameters);
1191
+ kept.push(tool);
1192
+ }
1193
+ return {
1194
+ ...message,
1195
+ result: {
1196
+ ...result,
1197
+ tools: kept
1198
+ }
1199
+ };
1032
1200
  }
1033
1201
  };
1034
1202
  //#endregion
@@ -1172,8 +1340,13 @@ var MCPSession = class {
1172
1340
  * a non-JSON or non-message frame is surfaced on `error` and DROPPED, never thrown. It
1173
1341
  * also bridges the socket's `close` → this transport's `close`, and the socket's `error`.
1174
1342
  * - **Outbound (`send`).** `send(message)` writes one text frame
1175
- * (`nodeWs.send(JSON.stringify(message))`); the underlying wrapper no-ops a write on a
1176
- * non-open socket, so a closed connection drops silently rather than throwing.
1343
+ * (`nodeWs.send(JSON.stringify(message))`). The underlying wrapper no-ops a write on a
1344
+ * non-open socket and confirms nothing, so this bridge answers a closed channel from its own
1345
+ * state and the socket's `readyState`: a `send` after `close()`, after the peer's close, or on
1346
+ * a socket that is not `OPEN` REJECTS with `WebSocket transport is not connected` rather than
1347
+ * resolving on a frame nobody wrote. `bindServer` catches that rejection and routes it to the
1348
+ * dispatcher's `error` event, and it aborts every in-flight request the moment this transport's
1349
+ * `close` fires — so a peer that disconnects mid-request is answered by no write at all.
1177
1350
  * - **`close()`** removes the subscriptions `start()` installed on the socket, closes the
1178
1351
  * underlying socket (the RFC 6455 close handshake), and fires the transport's `close` event
1179
1352
  * (idempotent — a second `close`, or a socket-driven close, emits once). A frame that arrives
@@ -1210,6 +1383,7 @@ var WebSocketServerTransport = class {
1210
1383
  this.#socket.emitter.on("error", this.#failure);
1211
1384
  }
1212
1385
  async send(message) {
1386
+ if (this.#closed || this.#socket.readyState !== WEBSOCKET_READY_OPEN) throw new Error("WebSocket transport is not connected");
1213
1387
  this.#socket.send(JSON.stringify(message));
1214
1388
  }
1215
1389
  async close() {
@@ -1276,10 +1450,12 @@ var WebSocketServerTransport = class {
1276
1450
  * non-JSON / non-message frame surfaces on `error` and is dropped. The socket's `close`
1277
1451
  * / `error` bridge to this transport's events.
1278
1452
  * - **Outbound (`send`).** `send(message)` writes one masked text frame. A socket write is not
1279
- * confirmed, so this transport answers a closed channel from its OWN state: a `send` with no
1280
- * bound socket — before `start()`, after `close()`, or after the peer ended the socket —
1281
- * REJECTS with `WebSocket transport is not connected`. It neither drops the message (the
1282
- * browser face's posture) nor queues it for a connection this transport is not holding.
1453
+ * confirmed, so this transport answers a closed channel from its own state AND the socket's
1454
+ * `readyState`: a `send` with no bound socket — before `start()`, after `close()`, or after the
1455
+ * peer ended the socket — and a `send` on a bound socket that is not `OPEN` both REJECT with
1456
+ * `WebSocket transport is not connected`. It neither drops the message nor queues it for a
1457
+ * connection this transport is not holding — the browser face queues a pre-open send, and this
1458
+ * one, holding no connection to flush it onto, rejects that too.
1283
1459
  * - **`close()`** unsubscribes from the socket, closes it, and fires `close` (idempotent). An
1284
1460
  * upgrade still on the wire is DESTROYED, so a `close()` during the handshake ends the
1285
1461
  * transport at once instead of waiting for a peer that may never answer — the suspended
@@ -1331,7 +1507,7 @@ var WebSocketClientTransport = class {
1331
1507
  }
1332
1508
  async send(message) {
1333
1509
  const socket = this.#socket;
1334
- if (socket === void 0) throw new Error("WebSocket transport is not connected");
1510
+ if (socket === void 0 || socket.readyState !== WEBSOCKET_READY_OPEN) throw new Error("WebSocket transport is not connected");
1335
1511
  socket.send(JSON.stringify(message));
1336
1512
  }
1337
1513
  async close() {
@@ -2031,7 +2207,8 @@ function createStdioClientTransport(options) {
2031
2207
  * @param mcp - The transport-agnostic {@link MCPDispatcherInterface} to expose over stdio
2032
2208
  * @param options - Optional injectable `input` / `output` streams; see
2033
2209
  * {@link StdioServerOptions}
2034
- * @returns A `{ start(): void; stop(): void }` handle to arm / tear down the pump
2210
+ * @returns A {@link StdioServerInterface} handle to arm / tear down the pump; `stop()` ends
2211
+ * that handle's lifetime permanently
2035
2212
  *
2036
2213
  * @example
2037
2214
  * ```ts
@@ -2232,6 +2409,6 @@ function createMCPSession(options) {
2232
2409
  };
2233
2410
  }
2234
2411
  //#endregion
2235
- export { DEFAULT_MCP_DELIVERY, DEFAULT_MCP_KEEPALIVE_INTERVAL, DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, HTTPDisconnect, MCPSession, MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, SSE_BUFFERING_DISABLED, SSE_BUFFERING_HEADER, SSE_KEEPALIVE_COMMENT, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, allowsOrigin, bridgeMessageTransport, buildResponseError, createHTTPClientTransport, createMCPContinuation, createMCPPostHandler, createMCPRoutes, createMCPSession, createReadableStream, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, inferHeaderIssue, inferLegacyVersion, inferStatus, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, sendEventStream, upgradeRequestPath, writeLine };
2412
+ export { DEFAULT_MCP_DELIVERY, DEFAULT_MCP_KEEPALIVE_INTERVAL, DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, HTTPDisconnect, MCPSession, MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, SSE_BUFFERING_DISABLED, SSE_BUFFERING_HEADER, SSE_KEEPALIVE_COMMENT, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, allowsOrigin, bridgeMessageTransport, buildResponseError, createHTTPClientTransport, createMCPContinuation, createMCPPostHandler, createMCPRoutes, createMCPSession, createReadableStream, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, inferHeaderIssue, inferHeaderTarget, inferLegacyVersion, inferParameterRefusal, inferStatus, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, sendEventStream, upgradeRequestPath, writeLine };
2236
2413
 
2237
2414
  //# sourceMappingURL=index.js.map