@orkestrel/mcp 0.0.27 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/browser/index.d.ts +135 -273
- package/dist/src/browser/index.js +128 -431
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +617 -200
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +881 -547
- package/dist/src/core/index.d.ts +881 -547
- package/dist/src/core/index.js +606 -200
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +275 -591
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +216 -343
- package/dist/src/server/index.d.ts +216 -343
- package/dist/src/server/index.js +269 -576
- package/dist/src/server/index.js.map +1 -1
- package/package.json +22 -22
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { EmitterInterface } from '@orkestrel/emitter';
|
|
2
|
+
import { HTTPClientTransportOptions } from '@orkestrel/mcp';
|
|
2
3
|
import { IncomingMessage } from 'node:http';
|
|
3
4
|
import { JSONRPCInvocation } from '@orkestrel/mcp';
|
|
4
5
|
import { JSONRPCMessage } from '@orkestrel/mcp';
|
|
5
6
|
import { JSONRPCMessage as JSONRPCMessage_2 } from '@orkestrel/mcp';
|
|
6
7
|
import { JSONRPCResponse } from '@orkestrel/mcp';
|
|
7
|
-
import { MCPClientTransportEventMap } from '@orkestrel/mcp';
|
|
8
|
-
import { MCPClientTransportEventMap as MCPClientTransportEventMap_2 } from '@orkestrel/mcp';
|
|
9
|
-
import { MCPClientTransportInterface } from '@orkestrel/mcp';
|
|
10
|
-
import { MCPClientTransportInterface as MCPClientTransportInterface_2 } from '@orkestrel/mcp';
|
|
11
8
|
import { MCPContinuationInterface } from '@orkestrel/mcp';
|
|
12
9
|
import { MCPDispatcherInterface } from '@orkestrel/mcp';
|
|
13
10
|
import { MCPEra } from '@orkestrel/mcp';
|
|
14
11
|
import { MCPHeaderParameter } from '@orkestrel/mcp';
|
|
15
12
|
import { MCPLegacyVersion } from '@orkestrel/mcp';
|
|
13
|
+
import { MCPMessageTransportEventMap } from '@orkestrel/mcp';
|
|
14
|
+
import { MCPMessageTransportEventMap as MCPMessageTransportEventMap_2 } from '@orkestrel/mcp';
|
|
15
|
+
import { MCPMessageTransportInterface } from '@orkestrel/mcp';
|
|
16
|
+
import { MCPMessageTransportInterface as MCPMessageTransportInterface_2 } from '@orkestrel/mcp';
|
|
16
17
|
import { MCPStreamControllerInterface } from '@orkestrel/mcp';
|
|
17
18
|
import { MCPTransportInterface } from '@orkestrel/mcp';
|
|
18
19
|
import { MCPVersion } from '@orkestrel/mcp';
|
|
@@ -26,7 +27,7 @@ import { TokenSecret } from '@orkestrel/server';
|
|
|
26
27
|
import { UpgradeHandler } from '@orkestrel/server';
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* Checks whether the request's `Accept` header opts into a Server-Sent-Events response.
|
|
30
31
|
*
|
|
31
32
|
* @remarks
|
|
32
33
|
* Reads the fetch-standard `Request.headers.get('accept')` and returns `true` when it
|
|
@@ -36,12 +37,12 @@ import { UpgradeHandler } from '@orkestrel/server';
|
|
|
36
37
|
* — an absent / unmatched header returns `false`.
|
|
37
38
|
*
|
|
38
39
|
* @param request - The fetch-standard `Request`
|
|
39
|
-
* @returns
|
|
40
|
+
* @returns True if the client `Accept`s `text/event-stream`; false otherwise
|
|
40
41
|
*/
|
|
41
42
|
export declare function acceptsEventStream(request: Request): boolean;
|
|
42
43
|
|
|
43
44
|
/**
|
|
44
|
-
*
|
|
45
|
+
* Checks whether an HTTP request satisfies the endpoint's origin gate.
|
|
45
46
|
*
|
|
46
47
|
* @remarks
|
|
47
48
|
* Validation is enabled by default. A request without `Origin` is allowed. A canonical origin
|
|
@@ -52,18 +53,20 @@ export declare function acceptsEventStream(request: Request): boolean;
|
|
|
52
53
|
*
|
|
53
54
|
* @param request - The fetch-standard request to validate
|
|
54
55
|
* @param options - Shared origin validation and delegation options
|
|
55
|
-
* @returns
|
|
56
|
+
* @returns True if the request may reach MCP dispatch; false otherwise
|
|
56
57
|
*/
|
|
57
58
|
export declare function allowsOrigin(request: Request, options?: MCPOriginOptions): boolean;
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* {@link
|
|
63
|
-
*
|
|
64
|
-
* import('
|
|
65
|
-
*
|
|
66
|
-
*
|
|
61
|
+
* Creates the server-side mirror of
|
|
62
|
+
* {@link import('@orkestrel/mcp').createDuplexClientTransport}: the adapter that bridges a
|
|
63
|
+
* message-channel {@link MCPMessageTransportInterface}
|
|
64
|
+
* (the shape the stdio and WebSocket SERVER transports already implement) onto the
|
|
65
|
+
* environment-agnostic {@link import('@orkestrel/mcp').MCPTransportInterface} port — what
|
|
66
|
+
* {@link createStdioServer} and {@link createWebSocketServer} pipe through `bindServer`, so
|
|
67
|
+
* the request/reply/error pump those factories used to hand-roll identically now lives ONCE
|
|
68
|
+
* in the core binder. {@link import('@orkestrel/mcp').createDuplexClientTransport} adapts the
|
|
69
|
+
* same two contracts the other way.
|
|
67
70
|
*
|
|
68
71
|
* @remarks
|
|
69
72
|
* `send` decodes the already-serialized reply string back to a {@link JSONRPCMessage}
|
|
@@ -105,31 +108,22 @@ export declare function allowsOrigin(request: Request, options?: MCPOriginOption
|
|
|
105
108
|
* import { bindServer } from '@orkestrel/mcp'
|
|
106
109
|
*
|
|
107
110
|
* const transport = new StdioServerTransport(process.stdin, process.stdout)
|
|
108
|
-
* bindServer(mcp,
|
|
111
|
+
* bindServer(mcp, createDuplexServerTransport(transport))
|
|
109
112
|
* ```
|
|
110
113
|
*/
|
|
111
|
-
export declare function
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Builds the error for a non-success HTTP response that carried no JSON-RPC message.
|
|
115
|
-
*
|
|
116
|
-
* @param response - The response whose status is reported
|
|
117
|
-
* @param type - The response's content type, or an empty string when absent
|
|
118
|
-
* @returns An error naming the HTTP status and unsupported response shape
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```ts
|
|
122
|
-
* const error = buildResponseError(new Response('', { status: 500 }), '')
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
export declare function buildResponseError(response: Response, type: string): Error;
|
|
114
|
+
export declare function createDuplexServerTransport(transport: MCPMessageTransportInterface): MCPTransportInterface;
|
|
126
115
|
|
|
127
116
|
/**
|
|
128
117
|
* Creates the HTTP CLIENT transport for an {@link import('@orkestrel/mcp').MCPClientInterface}
|
|
129
|
-
* — a {@link
|
|
118
|
+
* — a {@link MCPMessageTransportInterface} that drives a REMOTE Streamable-HTTP MCP server
|
|
130
119
|
* over `fetch`. The egress mirror of {@link createMCPRoutes}.
|
|
131
120
|
*
|
|
132
121
|
* @remarks
|
|
122
|
+
* It returns the core {@link import('@orkestrel/mcp').HTTPClientTransport}, the same class the
|
|
123
|
+
* browser face's `createHTTPClientTransport` returns, because the class touches `fetch`,
|
|
124
|
+
* `Response`, `AbortController`, `AbortSignal`, and `WeakMap` alone.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
133
127
|
* Hand it to `createMCPClient({ transport })`: each JSON-RPC message the client sends is
|
|
134
128
|
* `POST`ed to `options.url` with `content-type: application/json` and an `Accept` of
|
|
135
129
|
* both `application/json` and `text/event-stream` (the server answers with EITHER — a
|
|
@@ -145,7 +139,7 @@ export declare function buildResponseError(response: Response, type: string): Er
|
|
|
145
139
|
* @param options - `url` (the remote endpoint; REQUIRED), optional `headers` merged onto
|
|
146
140
|
* every request, optional `fetch` (default `globalThis.fetch`), and optional `timeout`
|
|
147
141
|
* (ms, applied with `AbortSignal.timeout`); see {@link HTTPClientTransportOptions}
|
|
148
|
-
* @returns A working {@link
|
|
142
|
+
* @returns A working {@link MCPMessageTransportInterface} over `fetch`
|
|
149
143
|
*
|
|
150
144
|
* @example
|
|
151
145
|
* ```ts
|
|
@@ -159,7 +153,7 @@ export declare function buildResponseError(response: Response, type: string): Er
|
|
|
159
153
|
* const tools = await client.tools()
|
|
160
154
|
* ```
|
|
161
155
|
*/
|
|
162
|
-
export declare function createHTTPClientTransport(options: HTTPClientTransportOptions):
|
|
156
|
+
export declare function createHTTPClientTransport(options: HTTPClientTransportOptions): MCPMessageTransportInterface;
|
|
163
157
|
|
|
164
158
|
/**
|
|
165
159
|
* Adapts the installed server token primitives to the host-neutral MCP continuation port.
|
|
@@ -238,7 +232,7 @@ export declare function createMCPPostHandler<TState = unknown>(mcp: MCPDispatche
|
|
|
238
232
|
* When `streaming` is enabled (the default) and the client `Accept`s `text/event-stream`,
|
|
239
233
|
* the `200` reply is framed as a Streamable-HTTP SSE response (one `data:` event carrying
|
|
240
234
|
* the JSON-RPC envelope, then the stream ends) through `@orkestrel/server`'s generic
|
|
241
|
-
* {@link import('@orkestrel/server').
|
|
235
|
+
* {@link import('@orkestrel/server').createStream} seam; otherwise it is a plain JSON body.
|
|
242
236
|
*
|
|
243
237
|
* **Sessions are a SEPARATE, plug-and-play middleware.** `createMCPRoutes` mints / reads no
|
|
244
238
|
* session id. To make the transport STATEFUL, mount {@link
|
|
@@ -288,8 +282,9 @@ export declare function createMCPRoutes<TState = unknown>(mcp: MCPDispatcherInte
|
|
|
288
282
|
* can re-read it from a freshly-built forwarded `Request`). Resolves a session through {@link
|
|
289
283
|
* readSessionHeader}: a VALID id touches the entry and sets `context.state.session`; an
|
|
290
284
|
* ABSENT / unknown id whose (guarded) body parses to an `initialize` request ({@link
|
|
291
|
-
* isInitializeRequest}) MINTS a fresh {@link MCPSession} (`crypto.randomUUID()`, `
|
|
292
|
-
* and sets `context.state.session`; neither → {@link rejectUnknownSession}
|
|
285
|
+
* isInitializeRequest}) MINTS a fresh {@link MCPSession} (`crypto.randomUUID()`, the `session`
|
|
286
|
+
* options group) and sets `context.state.session`; neither → {@link rejectUnknownSession}
|
|
287
|
+
* (`404`). The
|
|
293
288
|
* minted entry pins the negotiated legacy revision, which is supplied to a later headerless
|
|
294
289
|
* live-session request. It then
|
|
295
290
|
* FORWARDS a fresh `Request` carrying the buffered `text` (`next(forwarded)`) — never the
|
|
@@ -300,7 +295,7 @@ export declare function createMCPRoutes<TState = unknown>(mcp: MCPDispatcherInte
|
|
|
300
295
|
* a `DELETE` arriving while the request was suspended is not undone.
|
|
301
296
|
* - **`GET {path}`.** Resolves the session the same way (no mint — only `initialize` mints);
|
|
302
297
|
* an invalid / unknown id is the same `404`. A valid session opens the resumable
|
|
303
|
-
* server→client stream through `@orkestrel/server`'s {@link import('@orkestrel/server').
|
|
298
|
+
* server→client stream through `@orkestrel/server`'s {@link import('@orkestrel/server').createStream}:
|
|
304
299
|
* replays every event after the client's `Last-Event-ID` ({@link readLastEventId}) BEFORE
|
|
305
300
|
* attaching the stream for live pushes, then attaches; cancellation of the streamed response
|
|
306
301
|
* body composes with `request.signal` and detaches it. Long-lived — never `end()`ed here.
|
|
@@ -315,10 +310,11 @@ export declare function createMCPRoutes<TState = unknown>(mcp: MCPDispatcherInte
|
|
|
315
310
|
* @typeParam TState - The consumer's `TState`, which MUST extend {@link MCPSessionState} so
|
|
316
311
|
* the resolved session can be threaded through `context.state.session`
|
|
317
312
|
* @param options - Optional `path` (default {@link DEFAULT_MCP_PATH}), `ttl` (idle-session
|
|
318
|
-
* sweep window, ms — omit for sessions that live until an explicit `DELETE`), `
|
|
319
|
-
* (the
|
|
320
|
-
*
|
|
321
|
-
*
|
|
313
|
+
* sweep window, ms — omit for sessions that live until an explicit `DELETE`), `session`
|
|
314
|
+
* (the knobs each minted {@link MCPSession} takes — `capacity`, the log's own `ttl`, and its
|
|
315
|
+
* `clock`), and `clock` (the deterministic epoch-ms clock this middleware keeps its own
|
|
316
|
+
* bookkeeping on and hands down to a session that names none; defaults to `Date.now`), plus
|
|
317
|
+
* the shared `origin` validation options; see {@link MCPSessionMiddlewareOptions}
|
|
322
318
|
* @returns A {@link MiddlewareHandler} that mints / validates sessions + serves the resumable
|
|
323
319
|
* `GET` / `DELETE`
|
|
324
320
|
*
|
|
@@ -334,16 +330,7 @@ export declare function createMCPRoutes<TState = unknown>(mcp: MCPDispatcherInte
|
|
|
334
330
|
* router.add(createMCPRoutes(createMCPLegacy(mcp))) // answers `initialize` too; pass `mcp` alone for modern-only
|
|
335
331
|
* ```
|
|
336
332
|
*/
|
|
337
|
-
export declare function createMCPSession<TState extends MCPSessionState>(options?:
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Creates a readable stream from its pull and cancellation behaviours.
|
|
341
|
-
*
|
|
342
|
-
* @param pull - The behaviour that supplies the stream's next chunk
|
|
343
|
-
* @param cancel - The behaviour that releases the stream after consumer cancellation
|
|
344
|
-
* @returns A readable stream backed by the supplied behaviours
|
|
345
|
-
*/
|
|
346
|
-
export declare function createReadableStream<T>(pull: (controller: ReadableStreamDefaultController<T>) => void | PromiseLike<void>, cancel: (reason?: unknown) => void | PromiseLike<void>): ReadableStream<T>;
|
|
333
|
+
export declare function createMCPSession<TState extends MCPSessionState>(options?: MCPSessionMiddlewareOptions): MiddlewareHandler<TState>;
|
|
347
334
|
|
|
348
335
|
/**
|
|
349
336
|
* Creates the stdio CLIENT transport for an {@link import('@orkestrel/mcp').MCPClientInterface}
|
|
@@ -393,7 +380,7 @@ export declare function createStdioClientTransport(options: StdioClientTransport
|
|
|
393
380
|
* Wraps `options.input` (default `process.stdin`) / `options.output` (default
|
|
394
381
|
* `process.stdout`) in a {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
|
|
395
382
|
* and pipes it through the core {@link import('@orkestrel/mcp').MCPTransportInterface} port
|
|
396
|
-
* through {@link
|
|
383
|
+
* through {@link createDuplexServerTransport} + {@link
|
|
397
384
|
* import('@orkestrel/mcp').bindServer}: each inbound REQUEST runs through `mcp.dispatch`, and
|
|
398
385
|
* a defined response is written back as a newline-terminated line — a NOTIFICATION
|
|
399
386
|
* writes nothing, and a non-request message is ignored. A `dispatch` / `send` fault
|
|
@@ -421,7 +408,7 @@ export declare function createStdioServer(mcp: MCPDispatcherInterface, options?:
|
|
|
421
408
|
|
|
422
409
|
/**
|
|
423
410
|
* Creates the WebSocket CLIENT transport for an {@link import('@orkestrel/mcp').MCPClientInterface}
|
|
424
|
-
* — a {@link
|
|
411
|
+
* — a {@link MCPMessageTransportInterface} that drives a REMOTE MCP server over a WebSocket. The
|
|
425
412
|
* egress mirror of {@link createWebSocketServer} and the WebSocket sibling of {@link
|
|
426
413
|
* createHTTPClientTransport}.
|
|
427
414
|
*
|
|
@@ -437,7 +424,7 @@ export declare function createStdioServer(mcp: MCPDispatcherInterface, options?:
|
|
|
437
424
|
*
|
|
438
425
|
* @param options - `url` (the remote WebSocket endpoint; REQUIRED) and optional `headers`
|
|
439
426
|
* merged onto the upgrade request; see {@link WebSocketClientTransportOptions}
|
|
440
|
-
* @returns A working {@link
|
|
427
|
+
* @returns A working {@link MCPMessageTransportInterface} over a WebSocket
|
|
441
428
|
*
|
|
442
429
|
* @example
|
|
443
430
|
* ```ts
|
|
@@ -451,7 +438,7 @@ export declare function createStdioServer(mcp: MCPDispatcherInterface, options?:
|
|
|
451
438
|
* const tools = await client.tools()
|
|
452
439
|
* ```
|
|
453
440
|
*/
|
|
454
|
-
export declare function createWebSocketClientTransport(options: WebSocketClientTransportOptions):
|
|
441
|
+
export declare function createWebSocketClientTransport(options: WebSocketClientTransportOptions): MCPMessageTransportInterface;
|
|
455
442
|
|
|
456
443
|
/**
|
|
457
444
|
* Creates the MCP WebSocket transport INGRESS — an {@link UpgradeHandler} that exposes a
|
|
@@ -473,7 +460,7 @@ export declare function createWebSocketClientTransport(options: WebSocketClientT
|
|
|
473
460
|
* only when the client's offer contains it, and sends UNMASKED frames), wraps it in a
|
|
474
461
|
* {@link WebSocketServerTransport}, and pipes it through the core {@link
|
|
475
462
|
* import('@orkestrel/mcp').MCPTransportInterface} port through {@link
|
|
476
|
-
*
|
|
463
|
+
* createDuplexServerTransport} + {@link import('@orkestrel/mcp').bindServer}:
|
|
477
464
|
* each inbound REQUEST runs through `mcp.dispatch`, and a defined response is written back
|
|
478
465
|
* as a frame — a NOTIFICATION sends nothing, and a non-request message (a stray response) is
|
|
479
466
|
* ignored. A `dispatch` / `send` fault surfaces on `mcp.emitter`'s `error` event rather than
|
|
@@ -510,21 +497,7 @@ export declare function createWebSocketClientTransport(options: WebSocketClientT
|
|
|
510
497
|
export declare function createWebSocketServer(mcp: MCPDispatcherInterface, options: WebSocketServerOptions): UpgradeHandler;
|
|
511
498
|
|
|
512
499
|
/**
|
|
513
|
-
*
|
|
514
|
-
* when it is not one — the per-event step {@link readEventStream} folds over.
|
|
515
|
-
*
|
|
516
|
-
* @remarks
|
|
517
|
-
* `JSON.parse`s the `data` (the server serializes the JSON-RPC envelope as the event's
|
|
518
|
-
* `data`) inside a try/catch and narrows the parsed value with `parseJSONRPCMessage`.
|
|
519
|
-
* Total: malformed JSON or a non-message value yields `undefined`, never throws.
|
|
520
|
-
*
|
|
521
|
-
* @param data - One SSE event's `data` payload
|
|
522
|
-
* @returns The decoded {@link JSONRPCMessage}, or `undefined`
|
|
523
|
-
*/
|
|
524
|
-
export declare function decodeEvent(data: string): JSONRPCMessage | undefined;
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* The default bound in milliseconds on one unconfirmed write to a stdio client transport's
|
|
500
|
+
* Sets the default bound in milliseconds on one unconfirmed write to a stdio client transport's
|
|
528
501
|
* child `stdin` — the `delivery` a `createStdioClientTransport` caller who supplies none gets.
|
|
529
502
|
*
|
|
530
503
|
* @remarks
|
|
@@ -537,7 +510,7 @@ export declare function decodeEvent(data: string): JSONRPCMessage | undefined;
|
|
|
537
510
|
export declare const DEFAULT_MCP_DELIVERY = 10000;
|
|
538
511
|
|
|
539
512
|
/**
|
|
540
|
-
*
|
|
513
|
+
* Sets the default interval in milliseconds between SSE keepalive comments on held-open MCP
|
|
541
514
|
* responses.
|
|
542
515
|
*
|
|
543
516
|
* @remarks
|
|
@@ -546,24 +519,24 @@ export declare const DEFAULT_MCP_DELIVERY = 10000;
|
|
|
546
519
|
*/
|
|
547
520
|
export declare const DEFAULT_MCP_KEEPALIVE_INTERVAL = 15000;
|
|
548
521
|
|
|
549
|
-
/**
|
|
522
|
+
/** Names the default request path `createMCPRoutes` mounts the transport's `POST` route at. */
|
|
550
523
|
export declare const DEFAULT_MCP_PATH = "/mcp";
|
|
551
524
|
|
|
552
525
|
/**
|
|
553
|
-
*
|
|
526
|
+
* Sets the default capacity of a session's FOLDED resumable event log (the per-{@link
|
|
554
527
|
* import('./MCPSession.js').MCPSession} replay log) — the maximum number of pushed
|
|
555
528
|
* server→client messages retained for replay before the OLDEST is evicted.
|
|
556
529
|
*
|
|
557
530
|
* @remarks
|
|
558
531
|
* Bounds the replay log's memory: only the most-recent {@link DEFAULT_MCP_SESSION_CAPACITY}
|
|
559
532
|
* pushes are retained, so a client reconnecting with a `Last-Event-ID` older than that window
|
|
560
|
-
* replays nothing (its cursor fell off the back). Override
|
|
561
|
-
* for a deeper / shallower window.
|
|
533
|
+
* replays nothing (its cursor fell off the back). Override through the `session` group of
|
|
534
|
+
* `createMCPSession`'s options (`session.capacity`) for a deeper / shallower window.
|
|
562
535
|
*/
|
|
563
536
|
export declare const DEFAULT_MCP_SESSION_CAPACITY = 1024;
|
|
564
537
|
|
|
565
538
|
/**
|
|
566
|
-
*
|
|
539
|
+
* Sets the default per-event idle lifetime (ms) of a session's folded resumable event log — an
|
|
567
540
|
* entry older than this is lazily evicted on the next access (no background timer), bounding
|
|
568
541
|
* how far back a reconnecting client may replay.
|
|
569
542
|
*
|
|
@@ -576,41 +549,22 @@ export declare const DEFAULT_MCP_SESSION_TTL = 300000;
|
|
|
576
549
|
|
|
577
550
|
/**
|
|
578
551
|
* Decodes and delivers each complete newline-framed line onto a {@link
|
|
579
|
-
*
|
|
552
|
+
* MCPMessageTransportEventMap} emitter — the shared per-chunk dispatch step both stdio
|
|
580
553
|
* transports run their framed lines through: the server transport frames with {@link
|
|
581
554
|
* extractLines}, the client transport takes its lines from the process supervisor.
|
|
582
555
|
*
|
|
583
556
|
* @remarks
|
|
584
|
-
* A blank line is skipped (a stray trailing newline). Every other line
|
|
585
|
-
*
|
|
586
|
-
* well-formed {@link JSONRPCMessage} emits `message`,
|
|
587
|
-
*
|
|
588
|
-
*
|
|
557
|
+
* A blank line is skipped (a stray trailing newline). Every other line runs through the
|
|
558
|
+
* shared {@link import('@orkestrel/mcp').deliverMessage} fold, the one inbound decode every
|
|
559
|
+
* transport in this package shares: a well-formed {@link JSONRPCMessage} emits `message`,
|
|
560
|
+
* unparsable text emits the caught parse error, and a well-formed non-message line emits
|
|
561
|
+
* `error` naming a non-JSON-RPC stdio line (total, never throws). Pure w.r.t. its own state
|
|
562
|
+
* — the emit is the caller-owned side effect.
|
|
589
563
|
*
|
|
590
564
|
* @param emitter - The transport's {@link EmitterInterface} to emit `message` / `error` onto
|
|
591
565
|
* @param lines - The complete lines to decode and deliver
|
|
592
566
|
*/
|
|
593
|
-
export declare function dispatchLines(emitter: EmitterInterface<
|
|
594
|
-
|
|
595
|
-
/**
|
|
596
|
-
* One entry of an {@link MCPSessionInterface}'s folded replay log — a single pushed {@link
|
|
597
|
-
* JSONRPCMessage} tagged with the monotone event `id` the session assigned and the `timestamp`
|
|
598
|
-
* it was appended at (for the lazy-TTL replay window).
|
|
599
|
-
*
|
|
600
|
-
* @remarks
|
|
601
|
-
* - `id` — the session-assigned, monotonically-increasing event id (a base36 string), the
|
|
602
|
-
* value a resumable client echoes back as its `Last-Event-ID` to replay from here.
|
|
603
|
-
* - `message` — the server→client {@link JSONRPCMessage} that was pushed.
|
|
604
|
-
* - `timestamp` — the epoch-ms instant the entry was appended, read by the TTL eviction.
|
|
605
|
-
*
|
|
606
|
-
* A plain value record (no behavior) — the unit {@link MCPSessionInterface.replay}
|
|
607
|
-
* returns.
|
|
608
|
-
*/
|
|
609
|
-
export declare interface EventStoreEntry {
|
|
610
|
-
readonly id: string;
|
|
611
|
-
readonly message: JSONRPCMessage;
|
|
612
|
-
readonly timestamp: number;
|
|
613
|
-
}
|
|
567
|
+
export declare function dispatchLines(emitter: EmitterInterface<MCPMessageTransportEventMap>, lines: readonly string[]): void;
|
|
614
568
|
|
|
615
569
|
/**
|
|
616
570
|
* Folds one more chunk of raw stdio bytes into a newline-framed buffer — the shared
|
|
@@ -631,98 +585,6 @@ export declare interface EventStoreEntry {
|
|
|
631
585
|
*/
|
|
632
586
|
export declare function extractLines(buffer: string, chunk: string): LineExtraction;
|
|
633
587
|
|
|
634
|
-
/**
|
|
635
|
-
* The HTTP CLIENT transport for the Model Context Protocol — a
|
|
636
|
-
* {@link MCPClientTransportInterface} that drives a REMOTE Streamable-HTTP MCP server over
|
|
637
|
-
* `fetch`, the egress mirror of the server's `createMCPRoutes`.
|
|
638
|
-
*
|
|
639
|
-
* @remarks
|
|
640
|
-
* - **Request/response over `fetch`.** `send(message)` POSTs the JSON-serialized
|
|
641
|
-
* message to `options.url` with `content-type: application/json` and an
|
|
642
|
-
* `Accept` of BOTH `application/json` and `text/event-stream` (so the server may
|
|
643
|
-
* answer with either framing) — plus any `options.headers` (for example, an `Authorization`
|
|
644
|
-
* bearer). It then decodes the reply and emits each decoded {@link JSONRPCMessage} on
|
|
645
|
-
* the `message` event the {@link import('@orkestrel/mcp').MCPClientInterface} subscribes
|
|
646
|
-
* to.
|
|
647
|
-
* - **Both reply framings.** A `200` with an `application/json` body is parsed with
|
|
648
|
-
* `parseJSONRPCMessage`; a `200` with a `text/event-stream` body is decoded with the
|
|
649
|
-
* `@orkestrel/sse` {@link import('@orkestrel/sse').SSEParserInterface} ({@link
|
|
650
|
-
* readEventStream}) — the inverse of the server's `openStream` seam, so the wire
|
|
651
|
-
* round-trips. A `202`
|
|
652
|
-
* Accepted (a notification) carries no body and emits nothing.
|
|
653
|
-
* - **Session and protocol headers.** `start()` is a no-op (a
|
|
654
|
-
* request/response transport opens no long-lived connection). The
|
|
655
|
-
* `mcp-session-id` response header, when a STATEFUL server sends one (on
|
|
656
|
-
* `initialize`), is captured into `session` and then ECHOED as the
|
|
657
|
-
* `mcp-session-id` request header on every SUBSEQUENT request — so an
|
|
658
|
-
* `MCPClient` passes a stateful server's session validation. The
|
|
659
|
-
* initialize result's `protocolVersion` is likewise captured, but only
|
|
660
|
-
* when it is a SUPPORTED value, and echoed as `mcp-protocol-version` alone on
|
|
661
|
-
* subsequent legacy requests. Modern requests instead derive protocol and method
|
|
662
|
-
* headers from the message, plus the name header only for `tools/call` — carried in the
|
|
663
|
-
* protocol's Base64 sentinel form whenever the tool name cannot ride as plain ASCII.
|
|
664
|
-
* Before initialize returns, neither captured legacy header is sent.
|
|
665
|
-
* `close()` clears the captured protocol so a reconnect's `initialize`
|
|
666
|
-
* POST is headerless; the captured `session` persists across `close()`.
|
|
667
|
-
* - **`close()` releases what is in flight.** Every `fetch` this transport still has open is
|
|
668
|
-
* ABORTED, which cancels the response body a `send` is reading — an SSE reply the server
|
|
669
|
-
* never ends would otherwise outlive the transport, with nothing left able to reach it. The
|
|
670
|
-
* aborted read surfaces on `error` and the `send` reporting it resolves. `close()` is
|
|
671
|
-
* idempotent (one `close` event per connected lifetime), and `start()` opens the next one.
|
|
672
|
-
* - **Total at the boundary.** Every reply is narrowed (`parseJSONRPCMessage`,
|
|
673
|
-
* the SSE decoder). A non-message success reply is dropped, never asserted. A non-success
|
|
674
|
-
* reply that carries no valid JSON-RPC message rejects `send` with its HTTP status and body
|
|
675
|
-
* shape. A valid JSON-RPC error body is emitted at any HTTP status. A `fetch` / decode failure
|
|
676
|
-
* on a success response surfaces on the `error` event rather than escaping `send`.
|
|
677
|
-
* - **Observable.** Owns the `emitter` ({@link MCPClientTransportEventMap}); fires
|
|
678
|
-
* `message` per decoded reply, `error` on a fault, and `close` on `close()`.
|
|
679
|
-
*
|
|
680
|
-
* @example
|
|
681
|
-
* ```ts
|
|
682
|
-
* const transport = new HTTPClientTransport({ url: 'http://localhost:3000/mcp' })
|
|
683
|
-
* const client = new MCPClient({ transport })
|
|
684
|
-
* await client.connect()
|
|
685
|
-
* ```
|
|
686
|
-
*/
|
|
687
|
-
export declare class HTTPClientTransport implements MCPClientTransportInterface_2 {
|
|
688
|
-
#private;
|
|
689
|
-
constructor(options: HTTPClientTransportOptions);
|
|
690
|
-
get emitter(): EmitterInterface<MCPClientTransportEventMap_2>;
|
|
691
|
-
get session(): string | undefined;
|
|
692
|
-
get duplex(): boolean;
|
|
693
|
-
start(): Promise<void>;
|
|
694
|
-
send(message: JSONRPCMessage_2): Promise<void>;
|
|
695
|
-
close(): Promise<void>;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* Options for `createHTTPClientTransport` — the remote MCP server's URL and any extra
|
|
700
|
-
* request headers.
|
|
701
|
-
*
|
|
702
|
-
* @remarks
|
|
703
|
-
* - `url` — the absolute URL of the remote server's Streamable-HTTP endpoint (the
|
|
704
|
-
* `POST` target every JSON-RPC message is written to, for example,
|
|
705
|
-
* `http://localhost:3000/mcp`). REQUIRED.
|
|
706
|
-
* - `headers` — extra request headers merged onto every `POST` (for example, an
|
|
707
|
-
* `Authorization` bearer for a guarded server). The transport always sets
|
|
708
|
-
* `content-type: application/json` and an `Accept` of both `application/json` and
|
|
709
|
-
* `text/event-stream` (so the server may answer with either framing); a key supplied
|
|
710
|
-
* here is merged on top.
|
|
711
|
-
* - `fetch` — the `fetch` implementation to issue each `POST` with; defaults to
|
|
712
|
-
* `globalThis.fetch`. Injectable for a test double or a non-global `fetch`.
|
|
713
|
-
* - `timeout` — an optional per-request timeout in milliseconds; when set, each
|
|
714
|
-
* `fetch` call composes that deadline with the transport's own close through
|
|
715
|
-
* `AbortSignal.any([close, AbortSignal.timeout(timeout)])`, so whichever fires first
|
|
716
|
-
* ends the request. Omit for no transport-level deadline; the close signal is passed
|
|
717
|
-
* either way.
|
|
718
|
-
*/
|
|
719
|
-
export declare interface HTTPClientTransportOptions {
|
|
720
|
-
readonly url: string;
|
|
721
|
-
readonly headers?: Readonly<Record<string, string>>;
|
|
722
|
-
readonly fetch?: typeof fetch;
|
|
723
|
-
readonly timeout?: number;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
588
|
/**
|
|
727
589
|
* Composes one incoming HTTP request lifetime with one MCP-owned SSE response lifetime.
|
|
728
590
|
*
|
|
@@ -751,10 +613,10 @@ export declare interface HTTPClientTransportOptions {
|
|
|
751
613
|
* @example
|
|
752
614
|
* ```ts
|
|
753
615
|
* import { HTTPDisconnect } from '@orkestrel/mcp/server'
|
|
754
|
-
* import {
|
|
616
|
+
* import { createStream } from '@orkestrel/server'
|
|
755
617
|
*
|
|
756
618
|
* const disconnect = new HTTPDisconnect(request.signal, { interval: 15_000 })
|
|
757
|
-
* const stream =
|
|
619
|
+
* const stream = createStream()
|
|
758
620
|
* const response = disconnect.bridge(stream)
|
|
759
621
|
* ```
|
|
760
622
|
*/
|
|
@@ -769,8 +631,8 @@ export declare class HTTPDisconnect {
|
|
|
769
631
|
*/
|
|
770
632
|
constructor(signal: AbortSignal, options?: MCPKeepaliveOptions);
|
|
771
633
|
/**
|
|
772
|
-
*
|
|
773
|
-
* its graceful completion.
|
|
634
|
+
* Returns the signal aborted by the incoming request, or by any end of this response that
|
|
635
|
+
* is not its graceful completion.
|
|
774
636
|
*
|
|
775
637
|
* @returns The composed lifecycle signal
|
|
776
638
|
*/
|
|
@@ -816,7 +678,7 @@ export declare class HTTPDisconnect {
|
|
|
816
678
|
*/
|
|
817
679
|
export declare interface HTTPHandlerOptions<TState = unknown> {
|
|
818
680
|
readonly streaming?: boolean;
|
|
819
|
-
/**
|
|
681
|
+
/** Requires the session layer's value; `origins` is ignored when `enabled` is `false`. */
|
|
820
682
|
readonly origin?: MCPOriginOptions;
|
|
821
683
|
readonly keepalive?: MCPKeepaliveOptions;
|
|
822
684
|
readonly caller?: MCPCallerHandler<TState>;
|
|
@@ -839,7 +701,7 @@ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHand
|
|
|
839
701
|
}
|
|
840
702
|
|
|
841
703
|
/**
|
|
842
|
-
* Infers the first required MCP HTTP header
|
|
704
|
+
* Infers the first required MCP HTTP header a request's own body contradicts.
|
|
843
705
|
*
|
|
844
706
|
* @remarks
|
|
845
707
|
* A modern request derives its protocol, method, and name expectations from the JSON-RPC body,
|
|
@@ -848,12 +710,14 @@ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHand
|
|
|
848
710
|
* {@link import('@orkestrel/mcp').decodeSentinel} before the comparison, so a peer that had
|
|
849
711
|
* to encode its value still matches; a sentinel whose payload is invalid decodes to nothing
|
|
850
712
|
* and therefore mismatches, which is how an invalid header value is refused. A legacy request
|
|
851
|
-
* body requires a protocol header after initialization
|
|
852
|
-
*
|
|
853
|
-
*
|
|
713
|
+
* body requires a protocol header after initialization. Messages name the expected value but
|
|
714
|
+
* never echo the client-supplied one.
|
|
715
|
+
*
|
|
716
|
+
* The expectation a LIVE SESSION supplies is a different rule over a different input, so it
|
|
717
|
+
* is {@link inferSessionHeaderIssue} rather than a second arm of this one.
|
|
854
718
|
*
|
|
855
719
|
* @param request - The HTTP request carrying the headers
|
|
856
|
-
* @param
|
|
720
|
+
* @param invocation - The parsed invocation body the expectations are derived from
|
|
857
721
|
* @returns The first header issue, or `undefined` when the applicable headers agree
|
|
858
722
|
*
|
|
859
723
|
* @example
|
|
@@ -862,7 +726,7 @@ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHand
|
|
|
862
726
|
* issue?.header // 'Mcp-Method' when that field is absent or mismatched
|
|
863
727
|
* ```
|
|
864
728
|
*/
|
|
865
|
-
export declare function inferHeaderIssue(request: Request,
|
|
729
|
+
export declare function inferHeaderIssue(request: Request, invocation: JSONRPCInvocation): MCPHeaderIssue | undefined;
|
|
866
730
|
|
|
867
731
|
/**
|
|
868
732
|
* Infers the target one modern request's `Mcp-Name` header must carry.
|
|
@@ -942,6 +806,29 @@ export declare function inferLegacyVersion(request: JSONRPCInvocation): MCPLegac
|
|
|
942
806
|
*/
|
|
943
807
|
export declare function inferParameterRefusal(request: Request, parameters: readonly MCPHeaderParameter[], values: unknown): string | undefined;
|
|
944
808
|
|
|
809
|
+
/**
|
|
810
|
+
* Infers the protocol header issue an active legacy session's pinned revision diagnoses.
|
|
811
|
+
*
|
|
812
|
+
* @remarks
|
|
813
|
+
* The session layer's rule, distinct from the body-derived one {@link inferHeaderIssue} owns:
|
|
814
|
+
* a live legacy session pinned its revision at `initialize`, so every later request on that
|
|
815
|
+
* session must name the same one. An absent header reads as `missing`, which the session
|
|
816
|
+
* middleware answers by SUPPLYING the pinned revision rather than refusing; a present header
|
|
817
|
+
* naming another revision reads as `mismatched` and is refused. The message names the session's
|
|
818
|
+
* revision and never echoes the client-supplied value.
|
|
819
|
+
*
|
|
820
|
+
* @param request - The HTTP request carrying the headers
|
|
821
|
+
* @param version - The legacy revision the active session pinned at `initialize`
|
|
822
|
+
* @returns The protocol header issue, or `undefined` when the header agrees
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* ```ts
|
|
826
|
+
* const issue = inferSessionHeaderIssue(request, '2025-06-18')
|
|
827
|
+
* issue?.reason // 'missing' when the request carries no protocol header
|
|
828
|
+
* ```
|
|
829
|
+
*/
|
|
830
|
+
export declare function inferSessionHeaderIssue(request: Request, version: MCPVersion): MCPHeaderIssue | undefined;
|
|
831
|
+
|
|
945
832
|
/**
|
|
946
833
|
* Infers the HTTP status for one MCP dispatch outcome without changing its JSON-RPC body.
|
|
947
834
|
*
|
|
@@ -958,7 +845,7 @@ export declare function inferParameterRefusal(request: Request, parameters: read
|
|
|
958
845
|
export declare function inferStatus(response: JSONRPCResponse | undefined, era: MCPEra): number;
|
|
959
846
|
|
|
960
847
|
/**
|
|
961
|
-
*
|
|
848
|
+
* Represents the result of folding one more chunk of raw stdio bytes into a newline-framed
|
|
962
849
|
* buffer — every COMPLETE line extracted (newline-terminated in the wire bytes) plus
|
|
963
850
|
* the trailing partial line carried forward as the new `remainder`.
|
|
964
851
|
*
|
|
@@ -971,44 +858,6 @@ export declare interface LineExtraction {
|
|
|
971
858
|
readonly remainder: string;
|
|
972
859
|
}
|
|
973
860
|
|
|
974
|
-
/** The modern Streamable-HTTP request header carrying the JSON-RPC method name. */
|
|
975
|
-
export declare const MCP_METHOD_HEADER = "mcp-method";
|
|
976
|
-
|
|
977
|
-
/** The modern Streamable-HTTP request header carrying a named method's target. */
|
|
978
|
-
export declare const MCP_NAME_HEADER = "mcp-name";
|
|
979
|
-
|
|
980
|
-
/**
|
|
981
|
-
* The Streamable-HTTP transport header carrying the negotiated MCP protocol version
|
|
982
|
-
* on every post-initialize client request.
|
|
983
|
-
*
|
|
984
|
-
* @remarks
|
|
985
|
-
* Required by MCP 2025-06-18 after initialization. Both HTTP client transports
|
|
986
|
-
* capture the initialize result's `protocolVersion` and send it on subsequent
|
|
987
|
-
* requests; `createMCPRoutes` rejects a present unsupported value before dispatch.
|
|
988
|
-
*/
|
|
989
|
-
export declare const MCP_PROTOCOL_VERSION_HEADER = "mcp-protocol-version";
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* The Streamable-HTTP transport header that carries the MCP session id. When a {@link
|
|
993
|
-
* import('./middlewares.js').createMCPSession} middleware is mounted, it SETS this header on
|
|
994
|
-
* the `initialize` response (the minted id) and READS it on every subsequent request
|
|
995
|
-
* (validating the session); the stateless `createMCPRoutes` default neither sets nor reads it.
|
|
996
|
-
*/
|
|
997
|
-
export declare const MCP_SESSION_HEADER = "mcp-session-id";
|
|
998
|
-
|
|
999
|
-
/**
|
|
1000
|
-
* The WebSocket subprotocol the MCP-over-WebSocket transports negotiate — sent by the
|
|
1001
|
-
* client in `Sec-WebSocket-Protocol`, echoed by the server in its `101` handshake.
|
|
1002
|
-
*
|
|
1003
|
-
* @remarks
|
|
1004
|
-
* `createWebSocketServer` echoes it in the upgrade response and `createWebSocketClientTransport`
|
|
1005
|
-
* requests it, so an MCP WebSocket endpoint is distinguishable from any other WebSocket on the
|
|
1006
|
-
* same path. The default WebSocket upgrade path is {@link DEFAULT_MCP_PATH} (the same `'/mcp'`
|
|
1007
|
-
* the HTTP transport mounts at) — the upgrade is selected by the `Upgrade: websocket` header,
|
|
1008
|
-
* not a separate path.
|
|
1009
|
-
*/
|
|
1010
|
-
export declare const MCP_WEBSOCKET_SUBPROTOCOL = "mcp";
|
|
1011
|
-
|
|
1012
861
|
/**
|
|
1013
862
|
* Extracts consumer-asserted caller context synchronously from an HTTP request after the
|
|
1014
863
|
* transport has validated it for dispatch.
|
|
@@ -1027,7 +876,8 @@ export declare const MCP_WEBSOCKET_SUBPROTOCOL = "mcp";
|
|
|
1027
876
|
export declare type MCPCallerHandler<TState = unknown> = (request: Request, context: RouteContext<string, TState> | undefined) => unknown;
|
|
1028
877
|
|
|
1029
878
|
/**
|
|
1030
|
-
*
|
|
879
|
+
* Reports one required MCP HTTP header that is absent or disagrees with its server-derived
|
|
880
|
+
* value.
|
|
1031
881
|
*
|
|
1032
882
|
* @remarks
|
|
1033
883
|
* - `header` — the canonical HTTP field name safe to show to an integrator.
|
|
@@ -1042,7 +892,7 @@ export declare interface MCPHeaderIssue {
|
|
|
1042
892
|
}
|
|
1043
893
|
|
|
1044
894
|
/**
|
|
1045
|
-
*
|
|
895
|
+
* Configures the shared SSE keepalive for held-open HTTP responses.
|
|
1046
896
|
*
|
|
1047
897
|
* @remarks
|
|
1048
898
|
* - `interval` — milliseconds between SSE comment frames. Defaults to {@link
|
|
@@ -1055,7 +905,7 @@ export declare interface MCPKeepaliveOptions {
|
|
|
1055
905
|
}
|
|
1056
906
|
|
|
1057
907
|
/**
|
|
1058
|
-
*
|
|
908
|
+
* Configures the protocol-required HTTP `Origin` validation shared by the route and session
|
|
1059
909
|
* enforcement sites.
|
|
1060
910
|
*
|
|
1061
911
|
* @remarks
|
|
@@ -1071,12 +921,12 @@ export declare interface MCPOriginOptions {
|
|
|
1071
921
|
}
|
|
1072
922
|
|
|
1073
923
|
/**
|
|
1074
|
-
*
|
|
924
|
+
* Represents one MCP transport session — the per-session entity a {@link
|
|
1075
925
|
* import('./middlewares.js').createMCPSession} middleware owns, keyed by its `id`, carrying the
|
|
1076
926
|
* resumable server→client push channel with its bounded replay log FOLDED IN.
|
|
1077
927
|
*
|
|
1078
928
|
* @remarks
|
|
1079
|
-
*
|
|
929
|
+
* One entity carries the whole session: it holds the
|
|
1080
930
|
* session `id`, its OWN bounded, replayable log of pushed server→client messages (the
|
|
1081
931
|
* resumable GET-SSE channel — a private `#events` `Map` + a monotone `#counter`, with
|
|
1082
932
|
* `capacity` / `ttl` eviction, not a separate store), and the set of open
|
|
@@ -1088,7 +938,7 @@ export declare interface MCPOriginOptions {
|
|
|
1088
938
|
* SSE event (`stream.write({ id, data })`). A push with NO attached stream is still logged,
|
|
1089
939
|
* so a client that connects (or reconnects with a `Last-Event-ID`) LATER replays it from the
|
|
1090
940
|
* log. A `write` to a closed stream is a safe no-op (the {@link
|
|
1091
|
-
* `@orkestrel/server`'s `
|
|
941
|
+
* `@orkestrel/server`'s `createStream` contract), so a just-disconnected stream that
|
|
1092
942
|
* has not yet been `detach`ed never throws. A replayed event and the live one carry the
|
|
1093
943
|
* IDENTICAL id (the log assigns it once).
|
|
1094
944
|
*
|
|
@@ -1113,9 +963,10 @@ export declare interface MCPOriginOptions {
|
|
|
1113
963
|
* The middleware opens the stream (the spine seam) and registers it here; this class only
|
|
1114
964
|
* serializes a message onto the already-open streams.
|
|
1115
965
|
*
|
|
1116
|
-
* - **Injected clock.**
|
|
1117
|
-
* `Date.now
|
|
1118
|
-
* timer
|
|
966
|
+
* - **Injected clock.** {@link import('./types.js').MCPSessionOptions.clock} supplies the
|
|
967
|
+
* epoch-ms clock the lazy TTL sweep reads, defaulting to `Date.now` — so a test drives TTL
|
|
968
|
+
* eviction with an elapsed clock rather than a real timer, and the middleware that mints a
|
|
969
|
+
* session hands its own clock down instead of leaving the log on wall-clock time.
|
|
1119
970
|
*
|
|
1120
971
|
* @example
|
|
1121
972
|
* ```ts
|
|
@@ -1131,15 +982,15 @@ export declare class MCPSession implements MCPSessionInterface {
|
|
|
1131
982
|
get id(): string;
|
|
1132
983
|
attach(stream: StreamInterface): void;
|
|
1133
984
|
detach(stream: StreamInterface): void;
|
|
1134
|
-
push(message: JSONRPCMessage
|
|
1135
|
-
replay(afterId: string
|
|
985
|
+
push(message: JSONRPCMessage): string;
|
|
986
|
+
replay(afterId: string): readonly MCPSessionEvent[];
|
|
1136
987
|
}
|
|
1137
988
|
|
|
1138
989
|
/**
|
|
1139
|
-
*
|
|
1140
|
-
* keeps per minted session — the live {@link MCPSession} entity plus the epoch-ms
|
|
1141
|
-
* was last touched (the lazy-TTL sweep's idle clock, independent of the session's
|
|
1142
|
-
* replay-log TTL).
|
|
990
|
+
* Represents the closure store entry a {@link import('./middlewares.js').createMCPSession}
|
|
991
|
+
* middleware keeps per minted session — the live {@link MCPSession} entity plus the epoch-ms
|
|
992
|
+
* instant it was last touched (the lazy-TTL sweep's idle clock, independent of the session's
|
|
993
|
+
* own replay-log TTL).
|
|
1143
994
|
*
|
|
1144
995
|
* @remarks
|
|
1145
996
|
* - `session` — the live {@link MCPSession} entity the store keys by session id.
|
|
@@ -1151,12 +1002,32 @@ export declare class MCPSession implements MCPSessionInterface {
|
|
|
1151
1002
|
export declare interface MCPSessionEntry {
|
|
1152
1003
|
readonly session: MCPSession;
|
|
1153
1004
|
readonly touched: number;
|
|
1154
|
-
/**
|
|
1005
|
+
/** Holds the legacy revision negotiated when this session was minted. */
|
|
1155
1006
|
readonly version: MCPVersion;
|
|
1156
1007
|
}
|
|
1157
1008
|
|
|
1158
1009
|
/**
|
|
1159
|
-
*
|
|
1010
|
+
* Represents one entry of an {@link MCPSessionInterface}'s folded replay log — a single pushed
|
|
1011
|
+
* {@link JSONRPCMessage} tagged with the monotone event `id` the session assigned and the
|
|
1012
|
+
* `timestamp` it was appended at (for the lazy-TTL replay window).
|
|
1013
|
+
*
|
|
1014
|
+
* @remarks
|
|
1015
|
+
* - `id` — the session-assigned, monotonically-increasing event id (a base36 string), the
|
|
1016
|
+
* value a resumable client echoes back as its `Last-Event-ID` to replay from here.
|
|
1017
|
+
* - `message` — the server→client {@link JSONRPCMessage} that was pushed.
|
|
1018
|
+
* - `timestamp` — the epoch-ms instant the entry was appended, read by the TTL eviction.
|
|
1019
|
+
*
|
|
1020
|
+
* A plain value record (no behavior) — the unit {@link MCPSessionInterface.replay}
|
|
1021
|
+
* returns.
|
|
1022
|
+
*/
|
|
1023
|
+
export declare interface MCPSessionEvent {
|
|
1024
|
+
readonly id: string;
|
|
1025
|
+
readonly message: JSONRPCMessage;
|
|
1026
|
+
readonly timestamp: number;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Represents one MCP transport session — the per-session entity a {@link
|
|
1160
1031
|
* import('./middlewares.js').createMCPSession} middleware owns (the {@link
|
|
1161
1032
|
* import('./MCPSession.js').MCPSession} entity), carrying the resumable server→client push
|
|
1162
1033
|
* channel with its bounded replay log FOLDED IN.
|
|
@@ -1181,7 +1052,7 @@ export declare interface MCPSessionInterface {
|
|
|
1181
1052
|
attach(stream: StreamInterface): void;
|
|
1182
1053
|
detach(stream: StreamInterface): void;
|
|
1183
1054
|
push(message: JSONRPCMessage): string;
|
|
1184
|
-
replay(afterId: string): readonly
|
|
1055
|
+
replay(afterId: string): readonly MCPSessionEvent[];
|
|
1185
1056
|
}
|
|
1186
1057
|
|
|
1187
1058
|
/**
|
|
@@ -1196,12 +1067,11 @@ export declare interface MCPSessionInterface {
|
|
|
1196
1067
|
* is treated as ABSENT and lazily evicted on the next access (no background timer — the
|
|
1197
1068
|
* `createRateLimiter` lazy-window idiom). Omit it for sessions that live until an explicit
|
|
1198
1069
|
* `DELETE`.
|
|
1199
|
-
* - `
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
* the session; this `capacity` bounds its replay log — independent knobs.)
|
|
1070
|
+
* - `session` — the knobs forwarded to each minted {@link MCPSession}: `capacity` bounds its
|
|
1071
|
+
* replay log and `ttl` is that log's per-event lifetime. This type's own `ttl` bounds the
|
|
1072
|
+
* SESSION instead. An omitted leaf takes its {@link MCPSessionOptions} default, and an
|
|
1073
|
+
* omitted `session.clock` inherits this type's own `clock`, so one injected clock governs
|
|
1074
|
+
* both the store sweep and the log sweep unless a caller names a different one.
|
|
1205
1075
|
* - `clock` — the `() => number` epoch-ms clock {@link import('./middlewares.js').createMCPSession}
|
|
1206
1076
|
* uses directly for its own session-touch / TTL-sweep bookkeeping; defaults to `Date.now`. The
|
|
1207
1077
|
* deterministic clock a TTL test advances explicitly instead of racing a real idle window
|
|
@@ -1214,18 +1084,44 @@ export declare interface MCPSessionInterface {
|
|
|
1214
1084
|
* - `keepalive` — the SSE liveness options for the held-open resumable response. `interval`
|
|
1215
1085
|
* defaults to {@link import('./constants.js').DEFAULT_MCP_KEEPALIVE_INTERVAL}.
|
|
1216
1086
|
*/
|
|
1217
|
-
export declare interface
|
|
1087
|
+
export declare interface MCPSessionMiddlewareOptions {
|
|
1218
1088
|
readonly path?: string;
|
|
1219
1089
|
readonly ttl?: number;
|
|
1220
|
-
readonly
|
|
1090
|
+
readonly session?: MCPSessionOptions;
|
|
1221
1091
|
readonly clock?: () => number;
|
|
1222
|
-
/**
|
|
1092
|
+
/** Requires the route layer's value; `origins` is ignored when `enabled` is `false`. */
|
|
1223
1093
|
readonly origin?: MCPOriginOptions;
|
|
1224
1094
|
readonly keepalive?: MCPKeepaliveOptions;
|
|
1225
1095
|
}
|
|
1226
1096
|
|
|
1227
1097
|
/**
|
|
1228
|
-
*
|
|
1098
|
+
* Options for the {@link MCPSession} entity — its folded replay log's capacity and per-event
|
|
1099
|
+
* lifetime.
|
|
1100
|
+
*
|
|
1101
|
+
* @remarks
|
|
1102
|
+
* - `capacity` — the maximum number of pushed server→client messages retained for replay
|
|
1103
|
+
* before the OLDEST is evicted. Omit it for the {@link
|
|
1104
|
+
* import('./constants.js').DEFAULT_MCP_SESSION_CAPACITY} default.
|
|
1105
|
+
* - `ttl` — the PER-EVENT idle lifetime in milliseconds: a log entry older than `ttl` is
|
|
1106
|
+
* dropped by the lazy sweep `push` and `replay` run, which bounds how far a reconnecting
|
|
1107
|
+
* client may replay. Omit it for the {@link
|
|
1108
|
+
* import('./constants.js').DEFAULT_MCP_SESSION_TTL} default; a non-positive value means no
|
|
1109
|
+
* entry ever ages out by time.
|
|
1110
|
+
* - `clock` — the `() => number` epoch-ms clock the log's lazy TTL sweep reads; defaults to
|
|
1111
|
+
* `Date.now`.
|
|
1112
|
+
*
|
|
1113
|
+
* The middleware's own knobs — the owned path, the idle-SESSION sweep window, origin
|
|
1114
|
+
* validation, and keepalive — live on {@link MCPSessionMiddlewareOptions}. The two `ttl`
|
|
1115
|
+
* values measure different things, which is why they sit on different types.
|
|
1116
|
+
*/
|
|
1117
|
+
export declare interface MCPSessionOptions {
|
|
1118
|
+
readonly capacity?: number;
|
|
1119
|
+
readonly ttl?: number;
|
|
1120
|
+
readonly clock?: () => number;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Declares the `context.state` slice a {@link import('./middlewares.js').createMCPSession}
|
|
1229
1125
|
* middleware sets on a validated / minted request — a consumer's `TState` extends
|
|
1230
1126
|
* this so the downstream route handler can read `context.state.session` to `push`
|
|
1231
1127
|
* a server-initiated message onto the session's resumable stream.
|
|
@@ -1240,27 +1136,6 @@ export declare interface MCPSessionState {
|
|
|
1240
1136
|
readonly session?: MCPSessionInterface;
|
|
1241
1137
|
}
|
|
1242
1138
|
|
|
1243
|
-
/**
|
|
1244
|
-
* Decodes a `fetch` Response's Server-Sent-Events body into the JSON-RPC messages it
|
|
1245
|
-
* carried — the CLIENT-side inverse of the server's Streamable-HTTP SSE response.
|
|
1246
|
-
*
|
|
1247
|
-
* @remarks
|
|
1248
|
-
* Reads the whole `response.body` stream chunk-by-chunk through a `TextDecoder({
|
|
1249
|
-
* stream: true })` (handling a multi-byte char split across reads) and `@orkestrel/sse`'s
|
|
1250
|
-
* {@link SSEParserInterface} (handling a partial line / in-progress event split across
|
|
1251
|
-
* reads), then narrows each dispatched event's `data` to a {@link JSONRPCMessage} with
|
|
1252
|
-
* `parseJSONRPCMessage` (so a non-message / non-JSON `data:` event is DROPPED, never
|
|
1253
|
-
* thrown — total). It reuses the SAME `SSEParser` the server's `openStream` seam
|
|
1254
|
-
* serializes against, so the wire round-trips. A `null` body (no stream) yields no
|
|
1255
|
-
* messages; the {@link import('./transports/HTTPClientTransport.js').HTTPClientTransport}
|
|
1256
|
-
* reads a request/response SSE reply (the server sends one `data:` event then ends), so
|
|
1257
|
-
* this drains to completion.
|
|
1258
|
-
*
|
|
1259
|
-
* @param response - The SSE `fetch` Response to decode (its `body` is read to completion)
|
|
1260
|
-
* @returns Every {@link JSONRPCMessage} the stream carried, in order
|
|
1261
|
-
*/
|
|
1262
|
-
export declare function readEventStream(response: Response): Promise<readonly JSONRPCMessage[]>;
|
|
1263
|
-
|
|
1264
1139
|
/**
|
|
1265
1140
|
* Reads the request's `Last-Event-ID` header — the SSE resume cursor a client sends when it
|
|
1266
1141
|
* reconnects to the resumable `GET {path}` stream, or `undefined` when absent.
|
|
@@ -1338,27 +1213,26 @@ export declare function rejectUnknownSession(): Response;
|
|
|
1338
1213
|
* ```ts
|
|
1339
1214
|
* const answer = await mcp.dispatch(invocation, { signal: disconnect.signal })
|
|
1340
1215
|
* if (answer !== undefined && Symbol.asyncIterator in answer) {
|
|
1341
|
-
* const sse =
|
|
1216
|
+
* const sse = createStream()
|
|
1342
1217
|
* queueMicrotask(() => void sendEventStream(answer, sse))
|
|
1343
1218
|
* }
|
|
1344
1219
|
* ```
|
|
1345
1220
|
*/
|
|
1346
1221
|
export declare function sendEventStream(stream: MCPStreamControllerInterface, sse: StreamInterface): Promise<void>;
|
|
1347
1222
|
|
|
1348
|
-
/**
|
|
1223
|
+
/** Names the `X-Accel-Buffering` value that disables reverse-proxy buffering. */
|
|
1349
1224
|
export declare const SSE_BUFFERING_DISABLED = "no";
|
|
1350
1225
|
|
|
1351
|
-
/**
|
|
1226
|
+
/** Names the reverse-proxy response header controlling buffering of an SSE response. */
|
|
1352
1227
|
export declare const SSE_BUFFERING_HEADER = "x-accel-buffering";
|
|
1353
1228
|
|
|
1354
|
-
/**
|
|
1229
|
+
/** Names the comment text written by the held-open MCP response keepalive. */
|
|
1355
1230
|
export declare const SSE_KEEPALIVE_COMMENT = "keepalive";
|
|
1356
1231
|
|
|
1357
1232
|
/**
|
|
1358
|
-
*
|
|
1359
|
-
* {@link StdioClientTransportInterface}
|
|
1360
|
-
*
|
|
1361
|
-
* import('./HTTPClientTransport.js').HTTPClientTransport} and {@link
|
|
1233
|
+
* Drives a CHILD PROCESS MCP server over newline-delimited JSON-RPC on `stdin`/`stdout` —
|
|
1234
|
+
* a {@link StdioClientTransportInterface}, the stdio sibling of {@link
|
|
1235
|
+
* import('@orkestrel/mcp').HTTPClientTransport} and {@link
|
|
1362
1236
|
* import('./WebSocketClientTransport.js').WebSocketClientTransport}.
|
|
1363
1237
|
*
|
|
1364
1238
|
* @remarks
|
|
@@ -1399,7 +1273,7 @@ export declare const SSE_KEEPALIVE_COMMENT = "keepalive";
|
|
|
1399
1273
|
* never moves again, so a detached descendant writing to the inherited stderr after the cutoff
|
|
1400
1274
|
* cannot grow it. See {@link StdioClientTransportInterface.evidence} for the readings and the
|
|
1401
1275
|
* byte bound.
|
|
1402
|
-
* - **Observable.** Owns the `emitter` ({@link
|
|
1276
|
+
* - **Observable.** Owns the `emitter` ({@link MCPMessageTransportEventMap}); the
|
|
1403
1277
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1404
1278
|
* fault, including the child spawn cause the supervisor surfaces and the notice that this
|
|
1405
1279
|
* lifetime's `evidence` was cut off at the `drain` bound), distinct from the emitter's own
|
|
@@ -1415,7 +1289,7 @@ export declare const SSE_KEEPALIVE_COMMENT = "keepalive";
|
|
|
1415
1289
|
export declare class StdioClientTransport implements StdioClientTransportInterface {
|
|
1416
1290
|
#private;
|
|
1417
1291
|
constructor(options: StdioClientTransportOptions);
|
|
1418
|
-
get emitter(): EmitterInterface<
|
|
1292
|
+
get emitter(): EmitterInterface<MCPMessageTransportEventMap_2>;
|
|
1419
1293
|
get session(): string | undefined;
|
|
1420
1294
|
get duplex(): boolean;
|
|
1421
1295
|
get evidence(): string | undefined;
|
|
@@ -1435,23 +1309,23 @@ export declare class StdioClientTransport implements StdioClientTransportInterfa
|
|
|
1435
1309
|
}
|
|
1436
1310
|
|
|
1437
1311
|
/**
|
|
1438
|
-
*
|
|
1439
|
-
* that also reports the supervised child's stderr tail, the
|
|
1440
|
-
* startup leaves behind.
|
|
1312
|
+
* Declares the contract `createStdioClientTransport` returns — a
|
|
1313
|
+
* {@link MCPMessageTransportInterface} that also reports the supervised child's stderr tail, the
|
|
1314
|
+
* diagnostic a child that dies at startup leaves behind.
|
|
1441
1315
|
*
|
|
1442
1316
|
* @remarks
|
|
1443
1317
|
* This contract adds `evidence` and changes nothing else: `emitter`, `session`, `duplex`,
|
|
1444
1318
|
* `start`, `send`, and `close` are the shared client-transport surface, unchanged. It sits here
|
|
1445
|
-
* rather than on {@link
|
|
1319
|
+
* rather than on {@link MCPMessageTransportInterface} because a transport that supervises no child —
|
|
1446
1320
|
* Streamable HTTP, WebSocket, a `MessagePort` pair — has no such tail, and a member every one
|
|
1447
1321
|
* of them answers `undefined` to forever is a stdio detail rather than a shared contract. A
|
|
1448
|
-
* consumer that widens this value back to {@link
|
|
1322
|
+
* consumer that widens this value back to {@link MCPMessageTransportInterface}, including by
|
|
1449
1323
|
* reading `client.transport`, loses the reader and must keep the original reference.
|
|
1450
1324
|
*/
|
|
1451
|
-
export declare interface StdioClientTransportInterface extends
|
|
1325
|
+
export declare interface StdioClientTransportInterface extends MCPMessageTransportInterface {
|
|
1452
1326
|
/**
|
|
1453
|
-
*
|
|
1454
|
-
* captured at that child's end afterwards.
|
|
1327
|
+
* Reports the supervised child's decoded stderr tail — live while a child is held, and the
|
|
1328
|
+
* value captured at that child's end afterwards.
|
|
1455
1329
|
*
|
|
1456
1330
|
* @remarks
|
|
1457
1331
|
* - **Readings.** `undefined` while no child has run and none has been captured — before the
|
|
@@ -1545,9 +1419,9 @@ export declare interface StdioClientTransportOptions {
|
|
|
1545
1419
|
}
|
|
1546
1420
|
|
|
1547
1421
|
/**
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1550
|
-
*
|
|
1422
|
+
* Arms and tears down the newline-delimited JSON-RPC pump over the {@link StdioServerOptions}
|
|
1423
|
+
* stream pair — the stdio INGRESS handle {@link import('./factories.js').createStdioServer}
|
|
1424
|
+
* returns.
|
|
1551
1425
|
*
|
|
1552
1426
|
* @remarks
|
|
1553
1427
|
* - `start()` — arm the pump: subscribe to `input`, and dispatch every complete line through
|
|
@@ -1584,15 +1458,14 @@ export declare interface StdioServerOptions {
|
|
|
1584
1458
|
}
|
|
1585
1459
|
|
|
1586
1460
|
/**
|
|
1587
|
-
*
|
|
1588
|
-
*
|
|
1589
|
-
*
|
|
1590
|
-
*
|
|
1591
|
-
* `mcp.dispatch` over, the stdio mirror of {@link
|
|
1461
|
+
* Wraps an injectable readable/writable stream pair (`process.stdin`/`process.stdout` in
|
|
1462
|
+
* production, a test double in tests) as a {@link MCPMessageTransportInterface} — the
|
|
1463
|
+
* newline-delimited JSON-RPC channel {@link import('../factories.js').createStdioServer}
|
|
1464
|
+
* pumps `mcp.dispatch` over, the stdio mirror of {@link
|
|
1592
1465
|
* import('./WebSocketServerTransport.js').WebSocketServerTransport}.
|
|
1593
1466
|
*
|
|
1594
1467
|
* @remarks
|
|
1595
|
-
* - **Reuses `
|
|
1468
|
+
* - **Reuses `MCPMessageTransportInterface`.** The same generic carrier the HTTP
|
|
1596
1469
|
* and WebSocket server transports implement — `emitter` (`message` / `close` /
|
|
1597
1470
|
* `error`), `start`, `send`, `close`. `session` is `undefined` (the stateless v1).
|
|
1598
1471
|
* - **Inbound (`message`).** `start()` subscribes to `input`'s `data` event; each
|
|
@@ -1618,14 +1491,14 @@ export declare interface StdioServerOptions {
|
|
|
1618
1491
|
* listener receives data. The injected streams are owned by the caller (typically
|
|
1619
1492
|
* `process.stdin`/`process.stdout`), so the transport never destroys, ends, or blanket-clears
|
|
1620
1493
|
* them.
|
|
1621
|
-
* - **Observable.** Owns the `emitter` ({@link
|
|
1494
|
+
* - **Observable.** Owns the `emitter` ({@link MCPMessageTransportEventMap}); the
|
|
1622
1495
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1623
1496
|
* fault), distinct from the emitter's own listener-error channel.
|
|
1624
1497
|
*/
|
|
1625
|
-
export declare class StdioServerTransport implements
|
|
1498
|
+
export declare class StdioServerTransport implements MCPMessageTransportInterface_2 {
|
|
1626
1499
|
#private;
|
|
1627
1500
|
constructor(input: NodeJS.ReadableStream, output: NodeJS.WritableStream);
|
|
1628
|
-
get emitter(): EmitterInterface<
|
|
1501
|
+
get emitter(): EmitterInterface<MCPMessageTransportEventMap_2>;
|
|
1629
1502
|
get session(): string | undefined;
|
|
1630
1503
|
get duplex(): boolean;
|
|
1631
1504
|
start(): Promise<void>;
|
|
@@ -1664,10 +1537,10 @@ export declare class StdioServerTransport implements MCPClientTransportInterface
|
|
|
1664
1537
|
export declare function upgradeRequestPath(request: IncomingMessage): string;
|
|
1665
1538
|
|
|
1666
1539
|
/**
|
|
1667
|
-
*
|
|
1668
|
-
* {@link
|
|
1540
|
+
* Drives a REMOTE MCP server over a WebSocket — a CLIENT
|
|
1541
|
+
* {@link MCPMessageTransportInterface} for the Model Context Protocol, the
|
|
1669
1542
|
* egress mirror of {@link import('./factories.js').createWebSocketServer} and the WebSocket
|
|
1670
|
-
* sibling of {@link import('
|
|
1543
|
+
* sibling of {@link import('@orkestrel/mcp').HTTPClientTransport}.
|
|
1671
1544
|
*
|
|
1672
1545
|
* @remarks
|
|
1673
1546
|
* - **Persistent bidirectional channel (unlike the HTTP transport).** `start()` performs the
|
|
@@ -1685,8 +1558,8 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
|
|
|
1685
1558
|
* transport while the handshake was on the wire, both WIN — the socket that arrives late is
|
|
1686
1559
|
* DESTROYED and never bound, so no orphan is left re-emitting frames at nobody. Both
|
|
1687
1560
|
* `start()` calls still resolve; exactly one socket is ever bound.
|
|
1688
|
-
* - **Inbound (`message`).** Each decoded text frame
|
|
1689
|
-
*
|
|
1561
|
+
* - **Inbound (`message`).** Each decoded text frame runs through the shared `deliverMessage`
|
|
1562
|
+
* fold (parse, then narrow) — a {@link JSONRPCMessage} re-emits on this transport's `message`
|
|
1690
1563
|
* event (the reply the {@link import('@orkestrel/mcp').MCPClientInterface} correlates by `id`); a
|
|
1691
1564
|
* non-JSON / non-message frame surfaces on `error` and is dropped. The socket's `close`
|
|
1692
1565
|
* / `error` bridge to this transport's events.
|
|
@@ -1704,7 +1577,7 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
|
|
|
1704
1577
|
* - **URL scheme.** `options.url` accepts a `ws://` / `wss://` URL or an `http://` / `https://`
|
|
1705
1578
|
* one; a `ws(s)` scheme is converted to `http(s)` for the underlying upgrade request (`wss`
|
|
1706
1579
|
* → TLS through `node:https`). Either reaches the same endpoint.
|
|
1707
|
-
* - **Observable.** Owns the `emitter` ({@link
|
|
1580
|
+
* - **Observable.** Owns the `emitter` ({@link MCPMessageTransportEventMap}); every emit
|
|
1708
1581
|
* the emitter isolates a listener throw (a buggy observer never corrupts the transport);
|
|
1709
1582
|
* `error` is a DOMAIN event (a transport-level fault).
|
|
1710
1583
|
*
|
|
@@ -1715,10 +1588,10 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
|
|
|
1715
1588
|
* await client.connect() // start() handshakes, then the MCP initialize runs over WS frames
|
|
1716
1589
|
* ```
|
|
1717
1590
|
*/
|
|
1718
|
-
export declare class WebSocketClientTransport implements
|
|
1591
|
+
export declare class WebSocketClientTransport implements MCPMessageTransportInterface_2 {
|
|
1719
1592
|
#private;
|
|
1720
1593
|
constructor(options: WebSocketClientTransportOptions);
|
|
1721
|
-
get emitter(): EmitterInterface<
|
|
1594
|
+
get emitter(): EmitterInterface<MCPMessageTransportEventMap_2>;
|
|
1722
1595
|
get session(): string | undefined;
|
|
1723
1596
|
get duplex(): boolean;
|
|
1724
1597
|
start(): Promise<void>;
|
|
@@ -1768,7 +1641,7 @@ export declare interface WebSocketClientTransportOptions {
|
|
|
1768
1641
|
* transport mounts at). A protocol-upgrade request to any OTHER path is DECLINED
|
|
1769
1642
|
* (the handler returns `false`, so the spine fans it to the next handler or destroys it).
|
|
1770
1643
|
* - `subprotocol` — the WebSocket subprotocol selected in the `101` handshake's
|
|
1771
|
-
* `Sec-WebSocket-Protocol`; defaults to {@link import('
|
|
1644
|
+
* `Sec-WebSocket-Protocol`; defaults to {@link import('@orkestrel/mcp').MCP_WEBSOCKET_SUBPROTOCOL}
|
|
1772
1645
|
* (`'mcp'`). It is sent only when the client's offer contains that token.
|
|
1773
1646
|
*
|
|
1774
1647
|
* Auth / origin policy is deliberately ABSENT: like the HTTP transport, the WebSocket
|
|
@@ -1782,21 +1655,21 @@ export declare interface WebSocketServerOptions {
|
|
|
1782
1655
|
}
|
|
1783
1656
|
|
|
1784
1657
|
/**
|
|
1785
|
-
*
|
|
1786
|
-
* {@link
|
|
1787
|
-
*
|
|
1658
|
+
* Wraps a {@link NodeWebSocketInterface} (the RFC 6455 wire wrapper) as a
|
|
1659
|
+
* {@link MCPMessageTransportInterface} — the per-connection JSON-RPC-over-WebSocket SERVER
|
|
1660
|
+
* bridge, the bidirectional JSON-RPC message channel
|
|
1788
1661
|
* `createWebSocketServer` pumps `mcp.dispatch` over and the egress mirror's
|
|
1789
1662
|
* {@link import('./WebSocketClientTransport.js').WebSocketClientTransport} reuses.
|
|
1790
1663
|
*
|
|
1791
1664
|
* @remarks
|
|
1792
|
-
* - **Reuses `
|
|
1665
|
+
* - **Reuses `MCPMessageTransportInterface`.** It IS the same generic carrier the HTTP
|
|
1793
1666
|
* client transport implements — `emitter` (`message` / `close` / `error`), `start`,
|
|
1794
1667
|
* `send`, `close` — so the WebSocket server and client both speak ONE transport contract,
|
|
1795
1668
|
* no near-duplicate sibling interface. `session` is `undefined` (the stateless v1; a
|
|
1796
1669
|
* session id is the deferred sessions tier). The name keeps the role explicit even though
|
|
1797
1670
|
* the shape is shared.
|
|
1798
1671
|
* - **Inbound (`message`).** `start()` subscribes to the socket's `message` event; each text
|
|
1799
|
-
* frame
|
|
1672
|
+
* frame runs through the shared `deliverMessage` fold (parse, then narrow) — a
|
|
1800
1673
|
* well-formed {@link JSONRPCMessage} is re-emitted on this transport's `message` event (the
|
|
1801
1674
|
* parsed envelope the {@link import('@orkestrel/mcp').MCPServerInterface} pump dispatches), while
|
|
1802
1675
|
* a non-JSON or non-message frame is surfaced on `error` and DROPPED, never thrown. It
|
|
@@ -1814,14 +1687,14 @@ export declare interface WebSocketServerOptions {
|
|
|
1814
1687
|
* (idempotent — a second `close`, or a socket-driven close, emits once). A frame that arrives
|
|
1815
1688
|
* between that release and the peer's close echo reaches nothing: the socket-driven close path
|
|
1816
1689
|
* releases the same way, so a closed transport is never subscribed to a live socket.
|
|
1817
|
-
* - **Observable.** Owns the `emitter` ({@link
|
|
1690
|
+
* - **Observable.** Owns the `emitter` ({@link MCPMessageTransportEventMap}); the emitter
|
|
1818
1691
|
* isolates a listener throw (a buggy observer never corrupts the bridge). `error` is a
|
|
1819
1692
|
* DOMAIN event (a transport-level fault), distinct from the emitter's listener-error channel.
|
|
1820
1693
|
*/
|
|
1821
|
-
export declare class WebSocketServerTransport implements
|
|
1694
|
+
export declare class WebSocketServerTransport implements MCPMessageTransportInterface_2 {
|
|
1822
1695
|
#private;
|
|
1823
1696
|
constructor(socket: NodeWebSocketInterface);
|
|
1824
|
-
get emitter(): EmitterInterface<
|
|
1697
|
+
get emitter(): EmitterInterface<MCPMessageTransportEventMap_2>;
|
|
1825
1698
|
get session(): string | undefined;
|
|
1826
1699
|
get duplex(): boolean;
|
|
1827
1700
|
start(): Promise<void>;
|