@orkestrel/mcp 0.0.3 → 0.0.5
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/dist/src/browser/index.d.ts +631 -0
- package/dist/src/browser/index.js +755 -0
- package/dist/src/browser/index.js.map +1 -0
- package/dist/src/core/index.cjs +173 -0
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +136 -0
- package/dist/src/core/index.d.ts +136 -0
- package/dist/src/core/index.js +171 -1
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +92 -38
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +68 -22
- package/dist/src/server/index.d.ts +68 -22
- package/dist/src/server/index.js +93 -40
- package/dist/src/server/index.js.map +1 -1
- package/package.json +29 -17
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ClientTransportEventMap } from '../core/index.ts';
|
|
2
2
|
import { ClientTransportEventMap as ClientTransportEventMap_2 } from '../../core/index.ts';
|
|
3
|
-
import { ClientTransportInterface } from '
|
|
4
|
-
import { ClientTransportInterface as ClientTransportInterface_2 } from '
|
|
3
|
+
import { ClientTransportInterface } from '../core/index.ts';
|
|
4
|
+
import { ClientTransportInterface as ClientTransportInterface_2 } from '../../core/index.ts';
|
|
5
5
|
import { EmitterInterface } from '@orkestrel/emitter';
|
|
6
6
|
import { IncomingMessage } from 'node:http';
|
|
7
7
|
import { JSONRPCMessage } from '../core/index.ts';
|
|
8
8
|
import { JSONRPCMessage as JSONRPCMessage_2 } from '../../core/index.ts';
|
|
9
9
|
import { MCPServerInterface } from '../core/index.ts';
|
|
10
|
+
import { MCPTransportInterface } from '../core/index.ts';
|
|
10
11
|
import { MiddlewareHandler } from '@orkestrel/server';
|
|
11
12
|
import { NodeWebSocketInterface } from '@orkestrel/websocket';
|
|
12
13
|
import { RouteInput } from '@orkestrel/router';
|
|
@@ -28,6 +29,49 @@ import { UpgradeHandler } from '@orkestrel/server';
|
|
|
28
29
|
*/
|
|
29
30
|
export declare function acceptsEventStream(request: Request): boolean;
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Bridge a message-channel {@link ClientTransportInterface} (the shape the stdio and
|
|
34
|
+
* WebSocket SERVER transports already implement) into the environment-agnostic
|
|
35
|
+
* {@link import('@src/core').MCPTransportInterface} port — the adapter
|
|
36
|
+
* {@link import('./factories.js').createStdioServer} and {@link
|
|
37
|
+
* import('./factories.js').createWebSocketServer} pipe through `bindServer`, so the
|
|
38
|
+
* request/reply/error pump those two factories used to hand-roll identically now
|
|
39
|
+
* lives ONCE in the core binder.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* `send` decodes the already-serialized reply string back to a {@link JSONRPCMessage}
|
|
43
|
+
* and writes it via `transport.send` (the SAME `JSON.stringify` the underlying
|
|
44
|
+
* transport already performs, so the wire bytes are unchanged). `listen` filters
|
|
45
|
+
* `transport`'s `message` event to REQUESTS ONLY — a stray response is ignored,
|
|
46
|
+
* exactly as the prior hand-rolled pumps did — and re-serializes each one back to a
|
|
47
|
+
* string for `bindServer`. `closed` bridges `transport`'s `close` event. `close`
|
|
48
|
+
* closes the underlying `transport`.
|
|
49
|
+
*
|
|
50
|
+
* @remarks Per {@link import('@src/core').MCPTransportInterface}, `listen`/`closed`
|
|
51
|
+
* each hold THE SINGLE current handler (a second call REPLACES the first, never adds).
|
|
52
|
+
* Since the underlying `transport.emitter` is ADD-based (`on` subscribes, never
|
|
53
|
+
* replaces), this bridge installs ONE stable emitter listener per event on first use
|
|
54
|
+
* and re-routes it to whichever handler is CURRENTLY registered (`undefined` while
|
|
55
|
+
* none is), so rebinding never double-dispatches.
|
|
56
|
+
*
|
|
57
|
+
* @remarks A response whose `result` serializes away (e.g. `undefined`) is dropped by
|
|
58
|
+
* the message validators on the wire's decode side — an asymmetry the stdio/WS carrier
|
|
59
|
+
* shares with the streamable-HTTP face, since both round-trip through `JSON.stringify`
|
|
60
|
+
* / `JSON.parse` before re-validation.
|
|
61
|
+
*
|
|
62
|
+
* @param transport - The message-channel transport to bridge (stdio or WebSocket)
|
|
63
|
+
* @returns An {@link import('@src/core').MCPTransportInterface} `bindServer` can drive
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* import { bindServer } from '@src/core'
|
|
68
|
+
*
|
|
69
|
+
* const transport = new StdioServerTransport(process.stdin, process.stdout)
|
|
70
|
+
* bindServer(mcp, bridgeMessageTransport(transport))
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function bridgeMessageTransport(transport: ClientTransportInterface): MCPTransportInterface;
|
|
74
|
+
|
|
31
75
|
/**
|
|
32
76
|
* Create the HTTP CLIENT transport for an {@link import('@src/core').MCPClientInterface}
|
|
33
77
|
* — a {@link ClientTransportInterface} that drives a REMOTE Streamable-HTTP MCP server
|
|
@@ -61,7 +105,7 @@ export declare function acceptsEventStream(request: Request): boolean;
|
|
|
61
105
|
* const tools = await client.tools()
|
|
62
106
|
* ```
|
|
63
107
|
*/
|
|
64
|
-
export declare function createHTTPClientTransport(options: HTTPClientTransportOptions):
|
|
108
|
+
export declare function createHTTPClientTransport(options: HTTPClientTransportOptions): ClientTransportInterface;
|
|
65
109
|
|
|
66
110
|
/**
|
|
67
111
|
* Create the MCP Streamable-HTTP transport routes — mounts a transport-agnostic
|
|
@@ -202,7 +246,7 @@ export declare function createMCPSession<TState extends MCPSessionState>(options
|
|
|
202
246
|
* const tools = await client.tools()
|
|
203
247
|
* ```
|
|
204
248
|
*/
|
|
205
|
-
export declare function createStdioClientTransport(options: StdioClientTransportOptions):
|
|
249
|
+
export declare function createStdioClientTransport(options: StdioClientTransportOptions): ClientTransportInterface;
|
|
206
250
|
|
|
207
251
|
/**
|
|
208
252
|
* Create the MCP stdio transport INGRESS — pumps a transport-agnostic {@link
|
|
@@ -212,12 +256,13 @@ export declare function createStdioClientTransport(options: StdioClientTransport
|
|
|
212
256
|
* @remarks
|
|
213
257
|
* Wraps `options.input` (default `process.stdin`) / `options.output` (default
|
|
214
258
|
* `process.stdout`) in a {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
|
|
215
|
-
* and
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* escaping the (async) message
|
|
259
|
+
* and pipes it through the core {@link import('@src/core').MCPTransportInterface} port
|
|
260
|
+
* via {@link import('./helpers.js').bridgeMessageTransport} + {@link
|
|
261
|
+
* import('@src/core').bindServer}: each inbound REQUEST runs through `mcp.dispatch`, and
|
|
262
|
+
* a defined response is written back as a newline-terminated line — a NOTIFICATION
|
|
263
|
+
* writes nothing, and a non-request message is ignored. A `dispatch` / `send` fault
|
|
264
|
+
* surfaces on `mcp.emitter`'s `error` event rather than escaping the (async) message
|
|
265
|
+
* pump.
|
|
221
266
|
*
|
|
222
267
|
* @param mcp - The transport-agnostic {@link MCPServerInterface} to expose over stdio
|
|
223
268
|
* @param options - Optional injectable `input` / `output` streams; see
|
|
@@ -270,7 +315,7 @@ export declare function createStdioServer(mcp: MCPServerInterface, options?: Std
|
|
|
270
315
|
* const tools = await client.tools()
|
|
271
316
|
* ```
|
|
272
317
|
*/
|
|
273
|
-
export declare function createWebSocketClientTransport(options: WebSocketClientTransportOptions):
|
|
318
|
+
export declare function createWebSocketClientTransport(options: WebSocketClientTransportOptions): ClientTransportInterface;
|
|
274
319
|
|
|
275
320
|
/**
|
|
276
321
|
* Create the MCP WebSocket transport INGRESS — an {@link UpgradeHandler} that exposes a
|
|
@@ -290,12 +335,13 @@ export declare function createWebSocketClientTransport(options: WebSocketClientT
|
|
|
290
335
|
* - **Claims (returns `true`)** otherwise: it builds `createNodeWebSocket({ socket, key, head,
|
|
291
336
|
* protocol })` (SERVER mode → writes the `101` handshake, echoing the `subprotocol`, default
|
|
292
337
|
* {@link MCP_WEBSOCKET_SUBPROTOCOL} `'mcp'`, and sends UNMASKED frames), wraps it in a
|
|
293
|
-
* {@link WebSocketServerTransport}, and
|
|
294
|
-
* import('@src/core').
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
338
|
+
* {@link WebSocketServerTransport}, and pipes it through the core {@link
|
|
339
|
+
* import('@src/core').MCPTransportInterface} port via {@link
|
|
340
|
+
* import('./helpers.js').bridgeMessageTransport} + {@link import('@src/core').bindServer}:
|
|
341
|
+
* each inbound REQUEST runs through `mcp.dispatch`, and a defined response is written back
|
|
342
|
+
* as a frame — a NOTIFICATION sends nothing, and a non-request message (a stray response) is
|
|
343
|
+
* ignored. A `dispatch` / `send` fault surfaces on `mcp.emitter`'s `error` event rather than
|
|
344
|
+
* escaping the (async) message pump.
|
|
299
345
|
*
|
|
300
346
|
* It is MECHANISM, not policy: compose an auth guard IN FRONT by registering an upgrade
|
|
301
347
|
* handler BEFORE this one — that handler can claim (decline + destroy) an unauthenticated
|
|
@@ -454,7 +500,7 @@ export declare function extractLines(buffer: string, chunk: string): LineExtract
|
|
|
454
500
|
* await client.connect()
|
|
455
501
|
* ```
|
|
456
502
|
*/
|
|
457
|
-
export declare class HTTPClientTransport implements
|
|
503
|
+
export declare class HTTPClientTransport implements ClientTransportInterface_2 {
|
|
458
504
|
#private;
|
|
459
505
|
constructor(options: HTTPClientTransportOptions);
|
|
460
506
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -814,7 +860,7 @@ export declare function rejectUnknownSession(): Response;
|
|
|
814
860
|
* await client.connect() // start() spawns the child, then the MCP initialize runs over stdio
|
|
815
861
|
* ```
|
|
816
862
|
*/
|
|
817
|
-
export declare class StdioClientTransport implements
|
|
863
|
+
export declare class StdioClientTransport implements ClientTransportInterface_2 {
|
|
818
864
|
#private;
|
|
819
865
|
constructor(options: StdioClientTransportOptions);
|
|
820
866
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -886,7 +932,7 @@ export declare interface StdioServerOptions {
|
|
|
886
932
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
887
933
|
* fault), distinct from the emitter's own listener-error channel.
|
|
888
934
|
*/
|
|
889
|
-
export declare class StdioServerTransport implements
|
|
935
|
+
export declare class StdioServerTransport implements ClientTransportInterface_2 {
|
|
890
936
|
#private;
|
|
891
937
|
constructor(input: NodeJS.ReadableStream, output: NodeJS.WritableStream);
|
|
892
938
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -949,7 +995,7 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
|
|
|
949
995
|
* await client.connect() // start() handshakes, then the MCP initialize runs over WS frames
|
|
950
996
|
* ```
|
|
951
997
|
*/
|
|
952
|
-
export declare class WebSocketClientTransport implements
|
|
998
|
+
export declare class WebSocketClientTransport implements ClientTransportInterface_2 {
|
|
953
999
|
#private;
|
|
954
1000
|
constructor(options: WebSocketClientTransportOptions);
|
|
955
1001
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -1031,7 +1077,7 @@ export declare interface WebSocketServerOptions {
|
|
|
1031
1077
|
* isolates a listener throw (a buggy observer never corrupts the bridge). `error` is a
|
|
1032
1078
|
* DOMAIN event (a transport-level fault), distinct from the emitter's listener-error channel.
|
|
1033
1079
|
*/
|
|
1034
|
-
export declare class WebSocketServerTransport implements
|
|
1080
|
+
export declare class WebSocketServerTransport implements ClientTransportInterface_2 {
|
|
1035
1081
|
#private;
|
|
1036
1082
|
constructor(socket: NodeWebSocketInterface);
|
|
1037
1083
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ClientTransportEventMap } from '../core/index.ts';
|
|
2
2
|
import { ClientTransportEventMap as ClientTransportEventMap_2 } from '../../core/index.ts';
|
|
3
|
-
import { ClientTransportInterface } from '
|
|
4
|
-
import { ClientTransportInterface as ClientTransportInterface_2 } from '
|
|
3
|
+
import { ClientTransportInterface } from '../core/index.ts';
|
|
4
|
+
import { ClientTransportInterface as ClientTransportInterface_2 } from '../../core/index.ts';
|
|
5
5
|
import { EmitterInterface } from '@orkestrel/emitter';
|
|
6
6
|
import { IncomingMessage } from 'node:http';
|
|
7
7
|
import { JSONRPCMessage } from '../core/index.ts';
|
|
8
8
|
import { JSONRPCMessage as JSONRPCMessage_2 } from '../../core/index.ts';
|
|
9
9
|
import { MCPServerInterface } from '../core/index.ts';
|
|
10
|
+
import { MCPTransportInterface } from '../core/index.ts';
|
|
10
11
|
import { MiddlewareHandler } from '@orkestrel/server';
|
|
11
12
|
import { NodeWebSocketInterface } from '@orkestrel/websocket';
|
|
12
13
|
import { RouteInput } from '@orkestrel/router';
|
|
@@ -28,6 +29,49 @@ import { UpgradeHandler } from '@orkestrel/server';
|
|
|
28
29
|
*/
|
|
29
30
|
export declare function acceptsEventStream(request: Request): boolean;
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Bridge a message-channel {@link ClientTransportInterface} (the shape the stdio and
|
|
34
|
+
* WebSocket SERVER transports already implement) into the environment-agnostic
|
|
35
|
+
* {@link import('@src/core').MCPTransportInterface} port — the adapter
|
|
36
|
+
* {@link import('./factories.js').createStdioServer} and {@link
|
|
37
|
+
* import('./factories.js').createWebSocketServer} pipe through `bindServer`, so the
|
|
38
|
+
* request/reply/error pump those two factories used to hand-roll identically now
|
|
39
|
+
* lives ONCE in the core binder.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* `send` decodes the already-serialized reply string back to a {@link JSONRPCMessage}
|
|
43
|
+
* and writes it via `transport.send` (the SAME `JSON.stringify` the underlying
|
|
44
|
+
* transport already performs, so the wire bytes are unchanged). `listen` filters
|
|
45
|
+
* `transport`'s `message` event to REQUESTS ONLY — a stray response is ignored,
|
|
46
|
+
* exactly as the prior hand-rolled pumps did — and re-serializes each one back to a
|
|
47
|
+
* string for `bindServer`. `closed` bridges `transport`'s `close` event. `close`
|
|
48
|
+
* closes the underlying `transport`.
|
|
49
|
+
*
|
|
50
|
+
* @remarks Per {@link import('@src/core').MCPTransportInterface}, `listen`/`closed`
|
|
51
|
+
* each hold THE SINGLE current handler (a second call REPLACES the first, never adds).
|
|
52
|
+
* Since the underlying `transport.emitter` is ADD-based (`on` subscribes, never
|
|
53
|
+
* replaces), this bridge installs ONE stable emitter listener per event on first use
|
|
54
|
+
* and re-routes it to whichever handler is CURRENTLY registered (`undefined` while
|
|
55
|
+
* none is), so rebinding never double-dispatches.
|
|
56
|
+
*
|
|
57
|
+
* @remarks A response whose `result` serializes away (e.g. `undefined`) is dropped by
|
|
58
|
+
* the message validators on the wire's decode side — an asymmetry the stdio/WS carrier
|
|
59
|
+
* shares with the streamable-HTTP face, since both round-trip through `JSON.stringify`
|
|
60
|
+
* / `JSON.parse` before re-validation.
|
|
61
|
+
*
|
|
62
|
+
* @param transport - The message-channel transport to bridge (stdio or WebSocket)
|
|
63
|
+
* @returns An {@link import('@src/core').MCPTransportInterface} `bindServer` can drive
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* import { bindServer } from '@src/core'
|
|
68
|
+
*
|
|
69
|
+
* const transport = new StdioServerTransport(process.stdin, process.stdout)
|
|
70
|
+
* bindServer(mcp, bridgeMessageTransport(transport))
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function bridgeMessageTransport(transport: ClientTransportInterface): MCPTransportInterface;
|
|
74
|
+
|
|
31
75
|
/**
|
|
32
76
|
* Create the HTTP CLIENT transport for an {@link import('@src/core').MCPClientInterface}
|
|
33
77
|
* — a {@link ClientTransportInterface} that drives a REMOTE Streamable-HTTP MCP server
|
|
@@ -61,7 +105,7 @@ export declare function acceptsEventStream(request: Request): boolean;
|
|
|
61
105
|
* const tools = await client.tools()
|
|
62
106
|
* ```
|
|
63
107
|
*/
|
|
64
|
-
export declare function createHTTPClientTransport(options: HTTPClientTransportOptions):
|
|
108
|
+
export declare function createHTTPClientTransport(options: HTTPClientTransportOptions): ClientTransportInterface;
|
|
65
109
|
|
|
66
110
|
/**
|
|
67
111
|
* Create the MCP Streamable-HTTP transport routes — mounts a transport-agnostic
|
|
@@ -202,7 +246,7 @@ export declare function createMCPSession<TState extends MCPSessionState>(options
|
|
|
202
246
|
* const tools = await client.tools()
|
|
203
247
|
* ```
|
|
204
248
|
*/
|
|
205
|
-
export declare function createStdioClientTransport(options: StdioClientTransportOptions):
|
|
249
|
+
export declare function createStdioClientTransport(options: StdioClientTransportOptions): ClientTransportInterface;
|
|
206
250
|
|
|
207
251
|
/**
|
|
208
252
|
* Create the MCP stdio transport INGRESS — pumps a transport-agnostic {@link
|
|
@@ -212,12 +256,13 @@ export declare function createStdioClientTransport(options: StdioClientTransport
|
|
|
212
256
|
* @remarks
|
|
213
257
|
* Wraps `options.input` (default `process.stdin`) / `options.output` (default
|
|
214
258
|
* `process.stdout`) in a {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
|
|
215
|
-
* and
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* escaping the (async) message
|
|
259
|
+
* and pipes it through the core {@link import('@src/core').MCPTransportInterface} port
|
|
260
|
+
* via {@link import('./helpers.js').bridgeMessageTransport} + {@link
|
|
261
|
+
* import('@src/core').bindServer}: each inbound REQUEST runs through `mcp.dispatch`, and
|
|
262
|
+
* a defined response is written back as a newline-terminated line — a NOTIFICATION
|
|
263
|
+
* writes nothing, and a non-request message is ignored. A `dispatch` / `send` fault
|
|
264
|
+
* surfaces on `mcp.emitter`'s `error` event rather than escaping the (async) message
|
|
265
|
+
* pump.
|
|
221
266
|
*
|
|
222
267
|
* @param mcp - The transport-agnostic {@link MCPServerInterface} to expose over stdio
|
|
223
268
|
* @param options - Optional injectable `input` / `output` streams; see
|
|
@@ -270,7 +315,7 @@ export declare function createStdioServer(mcp: MCPServerInterface, options?: Std
|
|
|
270
315
|
* const tools = await client.tools()
|
|
271
316
|
* ```
|
|
272
317
|
*/
|
|
273
|
-
export declare function createWebSocketClientTransport(options: WebSocketClientTransportOptions):
|
|
318
|
+
export declare function createWebSocketClientTransport(options: WebSocketClientTransportOptions): ClientTransportInterface;
|
|
274
319
|
|
|
275
320
|
/**
|
|
276
321
|
* Create the MCP WebSocket transport INGRESS — an {@link UpgradeHandler} that exposes a
|
|
@@ -290,12 +335,13 @@ export declare function createWebSocketClientTransport(options: WebSocketClientT
|
|
|
290
335
|
* - **Claims (returns `true`)** otherwise: it builds `createNodeWebSocket({ socket, key, head,
|
|
291
336
|
* protocol })` (SERVER mode → writes the `101` handshake, echoing the `subprotocol`, default
|
|
292
337
|
* {@link MCP_WEBSOCKET_SUBPROTOCOL} `'mcp'`, and sends UNMASKED frames), wraps it in a
|
|
293
|
-
* {@link WebSocketServerTransport}, and
|
|
294
|
-
* import('@src/core').
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
338
|
+
* {@link WebSocketServerTransport}, and pipes it through the core {@link
|
|
339
|
+
* import('@src/core').MCPTransportInterface} port via {@link
|
|
340
|
+
* import('./helpers.js').bridgeMessageTransport} + {@link import('@src/core').bindServer}:
|
|
341
|
+
* each inbound REQUEST runs through `mcp.dispatch`, and a defined response is written back
|
|
342
|
+
* as a frame — a NOTIFICATION sends nothing, and a non-request message (a stray response) is
|
|
343
|
+
* ignored. A `dispatch` / `send` fault surfaces on `mcp.emitter`'s `error` event rather than
|
|
344
|
+
* escaping the (async) message pump.
|
|
299
345
|
*
|
|
300
346
|
* It is MECHANISM, not policy: compose an auth guard IN FRONT by registering an upgrade
|
|
301
347
|
* handler BEFORE this one — that handler can claim (decline + destroy) an unauthenticated
|
|
@@ -454,7 +500,7 @@ export declare function extractLines(buffer: string, chunk: string): LineExtract
|
|
|
454
500
|
* await client.connect()
|
|
455
501
|
* ```
|
|
456
502
|
*/
|
|
457
|
-
export declare class HTTPClientTransport implements
|
|
503
|
+
export declare class HTTPClientTransport implements ClientTransportInterface_2 {
|
|
458
504
|
#private;
|
|
459
505
|
constructor(options: HTTPClientTransportOptions);
|
|
460
506
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -814,7 +860,7 @@ export declare function rejectUnknownSession(): Response;
|
|
|
814
860
|
* await client.connect() // start() spawns the child, then the MCP initialize runs over stdio
|
|
815
861
|
* ```
|
|
816
862
|
*/
|
|
817
|
-
export declare class StdioClientTransport implements
|
|
863
|
+
export declare class StdioClientTransport implements ClientTransportInterface_2 {
|
|
818
864
|
#private;
|
|
819
865
|
constructor(options: StdioClientTransportOptions);
|
|
820
866
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -886,7 +932,7 @@ export declare interface StdioServerOptions {
|
|
|
886
932
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
887
933
|
* fault), distinct from the emitter's own listener-error channel.
|
|
888
934
|
*/
|
|
889
|
-
export declare class StdioServerTransport implements
|
|
935
|
+
export declare class StdioServerTransport implements ClientTransportInterface_2 {
|
|
890
936
|
#private;
|
|
891
937
|
constructor(input: NodeJS.ReadableStream, output: NodeJS.WritableStream);
|
|
892
938
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -949,7 +995,7 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
|
|
|
949
995
|
* await client.connect() // start() handshakes, then the MCP initialize runs over WS frames
|
|
950
996
|
* ```
|
|
951
997
|
*/
|
|
952
|
-
export declare class WebSocketClientTransport implements
|
|
998
|
+
export declare class WebSocketClientTransport implements ClientTransportInterface_2 {
|
|
953
999
|
#private;
|
|
954
1000
|
constructor(options: WebSocketClientTransportOptions);
|
|
955
1001
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
|
@@ -1031,7 +1077,7 @@ export declare interface WebSocketServerOptions {
|
|
|
1031
1077
|
* isolates a listener throw (a buggy observer never corrupts the bridge). `error` is a
|
|
1032
1078
|
* DOMAIN event (a transport-level fault), distinct from the emitter's listener-error channel.
|
|
1033
1079
|
*/
|
|
1034
|
-
export declare class WebSocketServerTransport implements
|
|
1080
|
+
export declare class WebSocketServerTransport implements ClientTransportInterface_2 {
|
|
1035
1081
|
#private;
|
|
1036
1082
|
constructor(socket: NodeWebSocketInterface);
|
|
1037
1083
|
get emitter(): EmitterInterface<ClientTransportEventMap_2>;
|
package/dist/src/server/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSSEParser } from "@orkestrel/sse";
|
|
2
|
-
import { JSONRPC_INVALID_REQUEST, JSONRPC_PARSE_ERROR, isInitializeRequest, isJSONRPCRequest, jsonRPCError, parseJSONRPCMessage } from "../core/index.js";
|
|
2
|
+
import { JSONRPC_INVALID_REQUEST, JSONRPC_PARSE_ERROR, bindServer, isInitializeRequest, isJSONRPCRequest, jsonRPCError, parseJSONRPCMessage } from "../core/index.js";
|
|
3
3
|
import { isString } from "@orkestrel/contract";
|
|
4
4
|
import { Emitter } from "@orkestrel/emitter";
|
|
5
5
|
import { randomBytes } from "node:crypto";
|
|
@@ -263,6 +263,81 @@ function dispatchLines(emitter, lines) {
|
|
|
263
263
|
emitter.emit("message", message);
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Bridge a message-channel {@link ClientTransportInterface} (the shape the stdio and
|
|
268
|
+
* WebSocket SERVER transports already implement) into the environment-agnostic
|
|
269
|
+
* {@link import('@src/core').MCPTransportInterface} port — the adapter
|
|
270
|
+
* {@link import('./factories.js').createStdioServer} and {@link
|
|
271
|
+
* import('./factories.js').createWebSocketServer} pipe through `bindServer`, so the
|
|
272
|
+
* request/reply/error pump those two factories used to hand-roll identically now
|
|
273
|
+
* lives ONCE in the core binder.
|
|
274
|
+
*
|
|
275
|
+
* @remarks
|
|
276
|
+
* `send` decodes the already-serialized reply string back to a {@link JSONRPCMessage}
|
|
277
|
+
* and writes it via `transport.send` (the SAME `JSON.stringify` the underlying
|
|
278
|
+
* transport already performs, so the wire bytes are unchanged). `listen` filters
|
|
279
|
+
* `transport`'s `message` event to REQUESTS ONLY — a stray response is ignored,
|
|
280
|
+
* exactly as the prior hand-rolled pumps did — and re-serializes each one back to a
|
|
281
|
+
* string for `bindServer`. `closed` bridges `transport`'s `close` event. `close`
|
|
282
|
+
* closes the underlying `transport`.
|
|
283
|
+
*
|
|
284
|
+
* @remarks Per {@link import('@src/core').MCPTransportInterface}, `listen`/`closed`
|
|
285
|
+
* each hold THE SINGLE current handler (a second call REPLACES the first, never adds).
|
|
286
|
+
* Since the underlying `transport.emitter` is ADD-based (`on` subscribes, never
|
|
287
|
+
* replaces), this bridge installs ONE stable emitter listener per event on first use
|
|
288
|
+
* and re-routes it to whichever handler is CURRENTLY registered (`undefined` while
|
|
289
|
+
* none is), so rebinding never double-dispatches.
|
|
290
|
+
*
|
|
291
|
+
* @remarks A response whose `result` serializes away (e.g. `undefined`) is dropped by
|
|
292
|
+
* the message validators on the wire's decode side — an asymmetry the stdio/WS carrier
|
|
293
|
+
* shares with the streamable-HTTP face, since both round-trip through `JSON.stringify`
|
|
294
|
+
* / `JSON.parse` before re-validation.
|
|
295
|
+
*
|
|
296
|
+
* @param transport - The message-channel transport to bridge (stdio or WebSocket)
|
|
297
|
+
* @returns An {@link import('@src/core').MCPTransportInterface} `bindServer` can drive
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* import { bindServer } from '@src/core'
|
|
302
|
+
*
|
|
303
|
+
* const transport = new StdioServerTransport(process.stdin, process.stdout)
|
|
304
|
+
* bindServer(mcp, bridgeMessageTransport(transport))
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
function bridgeMessageTransport(transport) {
|
|
308
|
+
let onMessage;
|
|
309
|
+
let onClosed;
|
|
310
|
+
let subscribed = false;
|
|
311
|
+
function subscribe() {
|
|
312
|
+
if (subscribed) return;
|
|
313
|
+
subscribed = true;
|
|
314
|
+
transport.emitter.on("message", (message) => {
|
|
315
|
+
if (!isJSONRPCRequest(message)) return;
|
|
316
|
+
onMessage?.(JSON.stringify(message));
|
|
317
|
+
});
|
|
318
|
+
transport.emitter.on("close", () => {
|
|
319
|
+
onClosed?.();
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
async send(message) {
|
|
324
|
+
const decoded = decodeEvent(message);
|
|
325
|
+
if (decoded === void 0) return;
|
|
326
|
+
await transport.send(decoded);
|
|
327
|
+
},
|
|
328
|
+
listen(handler) {
|
|
329
|
+
subscribe();
|
|
330
|
+
onMessage = handler;
|
|
331
|
+
},
|
|
332
|
+
closed(handler) {
|
|
333
|
+
subscribe();
|
|
334
|
+
onClosed = handler;
|
|
335
|
+
},
|
|
336
|
+
async close() {
|
|
337
|
+
await transport.close();
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
266
341
|
//#endregion
|
|
267
342
|
//#region src/server/transports/HTTPClientTransport.ts
|
|
268
343
|
/**
|
|
@@ -1030,12 +1105,13 @@ function createHTTPClientTransport(options) {
|
|
|
1030
1105
|
* - **Claims (returns `true`)** otherwise: it builds `createNodeWebSocket({ socket, key, head,
|
|
1031
1106
|
* protocol })` (SERVER mode → writes the `101` handshake, echoing the `subprotocol`, default
|
|
1032
1107
|
* {@link MCP_WEBSOCKET_SUBPROTOCOL} `'mcp'`, and sends UNMASKED frames), wraps it in a
|
|
1033
|
-
* {@link WebSocketServerTransport}, and
|
|
1034
|
-
* import('@src/core').
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1108
|
+
* {@link WebSocketServerTransport}, and pipes it through the core {@link
|
|
1109
|
+
* import('@src/core').MCPTransportInterface} port via {@link
|
|
1110
|
+
* import('./helpers.js').bridgeMessageTransport} + {@link import('@src/core').bindServer}:
|
|
1111
|
+
* each inbound REQUEST runs through `mcp.dispatch`, and a defined response is written back
|
|
1112
|
+
* as a frame — a NOTIFICATION sends nothing, and a non-request message (a stray response) is
|
|
1113
|
+
* ignored. A `dispatch` / `send` fault surfaces on `mcp.emitter`'s `error` event rather than
|
|
1114
|
+
* escaping the (async) message pump.
|
|
1039
1115
|
*
|
|
1040
1116
|
* It is MECHANISM, not policy: compose an auth guard IN FRONT by registering an upgrade
|
|
1041
1117
|
* handler BEFORE this one — that handler can claim (decline + destroy) an unauthenticated
|
|
@@ -1072,19 +1148,7 @@ function createWebSocketServer(mcp, options) {
|
|
|
1072
1148
|
head,
|
|
1073
1149
|
protocol: subprotocol
|
|
1074
1150
|
}));
|
|
1075
|
-
|
|
1076
|
-
if (!isJSONRPCRequest(message)) return;
|
|
1077
|
-
(async () => {
|
|
1078
|
-
try {
|
|
1079
|
-
const response = await mcp.dispatch(message);
|
|
1080
|
-
if (response !== void 0) await transport.send(response);
|
|
1081
|
-
} catch (error) {
|
|
1082
|
-
try {
|
|
1083
|
-
transport.emitter.emit("error", error);
|
|
1084
|
-
} catch {}
|
|
1085
|
-
}
|
|
1086
|
-
})();
|
|
1087
|
-
});
|
|
1151
|
+
bindServer(mcp, bridgeMessageTransport(transport));
|
|
1088
1152
|
transport.start();
|
|
1089
1153
|
return true;
|
|
1090
1154
|
};
|
|
@@ -1166,12 +1230,13 @@ function createStdioClientTransport(options) {
|
|
|
1166
1230
|
* @remarks
|
|
1167
1231
|
* Wraps `options.input` (default `process.stdin`) / `options.output` (default
|
|
1168
1232
|
* `process.stdout`) in a {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
|
|
1169
|
-
* and
|
|
1170
|
-
*
|
|
1171
|
-
*
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
* escaping the (async) message
|
|
1233
|
+
* and pipes it through the core {@link import('@src/core').MCPTransportInterface} port
|
|
1234
|
+
* via {@link import('./helpers.js').bridgeMessageTransport} + {@link
|
|
1235
|
+
* import('@src/core').bindServer}: each inbound REQUEST runs through `mcp.dispatch`, and
|
|
1236
|
+
* a defined response is written back as a newline-terminated line — a NOTIFICATION
|
|
1237
|
+
* writes nothing, and a non-request message is ignored. A `dispatch` / `send` fault
|
|
1238
|
+
* surfaces on `mcp.emitter`'s `error` event rather than escaping the (async) message
|
|
1239
|
+
* pump.
|
|
1175
1240
|
*
|
|
1176
1241
|
* @param mcp - The transport-agnostic {@link MCPServerInterface} to expose over stdio
|
|
1177
1242
|
* @param options - Optional injectable `input` / `output` streams; see
|
|
@@ -1189,19 +1254,7 @@ function createStdioClientTransport(options) {
|
|
|
1189
1254
|
*/
|
|
1190
1255
|
function createStdioServer(mcp, options) {
|
|
1191
1256
|
const transport = new StdioServerTransport(options?.input ?? process.stdin, options?.output ?? process.stdout);
|
|
1192
|
-
|
|
1193
|
-
if (!isJSONRPCRequest(message)) return;
|
|
1194
|
-
(async () => {
|
|
1195
|
-
try {
|
|
1196
|
-
const response = await mcp.dispatch(message);
|
|
1197
|
-
if (response !== void 0) await transport.send(response);
|
|
1198
|
-
} catch (error) {
|
|
1199
|
-
try {
|
|
1200
|
-
transport.emitter.emit("error", error);
|
|
1201
|
-
} catch {}
|
|
1202
|
-
}
|
|
1203
|
-
})();
|
|
1204
|
-
});
|
|
1257
|
+
bindServer(mcp, bridgeMessageTransport(transport));
|
|
1205
1258
|
return {
|
|
1206
1259
|
start() {
|
|
1207
1260
|
transport.start();
|
|
@@ -1339,6 +1392,6 @@ function createMCPSession(options) {
|
|
|
1339
1392
|
}
|
|
1340
1393
|
}
|
|
1341
1394
|
//#endregion
|
|
1342
|
-
export { DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, MCPSession, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, createHTTPClientTransport, createMCPRoutes, createMCPSession, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, upgradeRequestPath };
|
|
1395
|
+
export { DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, MCPSession, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, bridgeMessageTransport, createHTTPClientTransport, createMCPRoutes, createMCPSession, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, upgradeRequestPath };
|
|
1343
1396
|
|
|
1344
1397
|
//# sourceMappingURL=index.js.map
|