@orkestrel/mcp 0.0.5 → 0.0.7
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 +41 -108
- package/dist/src/browser/index.js +55 -120
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +118 -53
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +77 -19
- package/dist/src/core/index.d.ts +77 -19
- package/dist/src/core/index.js +117 -54
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +147 -115
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +70 -29
- package/dist/src/server/index.d.ts +70 -29
- package/dist/src/server/index.js +149 -118
- package/dist/src/server/index.js.map +1 -1
- package/package.json +35 -34
package/dist/src/core/index.d.ts
CHANGED
|
@@ -144,10 +144,10 @@ export declare type ClientTransportEventMap = {
|
|
|
144
144
|
*
|
|
145
145
|
* @remarks
|
|
146
146
|
* The mirror of the server's "a transport pumps strings through `handle`": here the
|
|
147
|
-
* {@link MCPClientInterface} hands the transport
|
|
148
|
-
*
|
|
147
|
+
* {@link MCPClientInterface} hands the transport one {@link JSONRPCMessage} via
|
|
148
|
+
* `send`, and the transport delivers each decoded reply back through the
|
|
149
149
|
* `message` event the client subscribed to. The minimal carrier surface (§21): a
|
|
150
|
-
* `start` (open the connection / arm any reader), `send` (write
|
|
150
|
+
* `start` (open the connection / arm any reader), `send` (write one message),
|
|
151
151
|
* and `close` (tear down). `session` exposes a server-assigned session id once a
|
|
152
152
|
* stateful transport has one (`undefined` for the stateless v1) — reserved for the
|
|
153
153
|
* later sessions tier. Concrete transports (the HTTP transport over `fetch`, a future
|
|
@@ -165,7 +165,7 @@ export declare interface ClientTransportInterface {
|
|
|
165
165
|
*/
|
|
166
166
|
start(): Promise<void>;
|
|
167
167
|
/**
|
|
168
|
-
* Send one JSON-RPC message
|
|
168
|
+
* Send one JSON-RPC message to the remote server.
|
|
169
169
|
*
|
|
170
170
|
* @remarks
|
|
171
171
|
* Each decoded reply is surfaced on the `emitter`'s `message` event — `send`
|
|
@@ -173,10 +173,10 @@ export declare interface ClientTransportInterface {
|
|
|
173
173
|
* transport, its synchronous reply emitted), not when a logical response arrives;
|
|
174
174
|
* the {@link MCPClientInterface} awaits the response through its `id` correlation.
|
|
175
175
|
*
|
|
176
|
-
* @param message -
|
|
177
|
-
* @returns Resolves once the message
|
|
176
|
+
* @param message - The message to write to the wire
|
|
177
|
+
* @returns Resolves once the message has been sent
|
|
178
178
|
*/
|
|
179
|
-
send(message: JSONRPCMessage
|
|
179
|
+
send(message: JSONRPCMessage): Promise<void>;
|
|
180
180
|
/**
|
|
181
181
|
* Close the transport — end the connection and release resources.
|
|
182
182
|
*
|
|
@@ -194,8 +194,8 @@ export declare interface ClientTransportInterface {
|
|
|
194
194
|
* @remarks
|
|
195
195
|
* Hand the RESULT to `createMCPClient({ transport })`, then pass the SAME
|
|
196
196
|
* `transport` to {@link import('./helpers.js').bindClient} to complete the inbound
|
|
197
|
-
* wiring: `send` serializes each outbound {@link JSONRPCMessage}
|
|
198
|
-
*
|
|
197
|
+
* wiring: `send` serializes each outbound {@link JSONRPCMessage} and writes it via
|
|
198
|
+
* `transport.send`; `close` closes the underlying
|
|
199
199
|
* `transport`; `start` is a no-op (the duplex channel is already open by the time
|
|
200
200
|
* it is handed in — there is no separate connect step at this layer); `session` is
|
|
201
201
|
* always `undefined` (session correlation is a higher-level concern the duplex port
|
|
@@ -224,7 +224,8 @@ export declare function createDuplexClientTransport(transport: MCPTransportInter
|
|
|
224
224
|
* @remarks
|
|
225
225
|
* The egress mirror of {@link createMCPServer}: where the server exposes a local tool
|
|
226
226
|
* registry over MCP, the client USES a remote server's tools. `connect()` handshakes,
|
|
227
|
-
* `tools()` lists + wraps the remote
|
|
227
|
+
* validates and exposes the negotiated protocol, `tools()` lists + wraps the remote
|
|
228
|
+
* tools (each `execute` calls back over the wire),
|
|
228
229
|
* and `call(name, args)` runs a remote `tools/call` (a remote tool failure throws
|
|
229
230
|
* locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}
|
|
230
231
|
* isolates it). The transport is injected — a concrete one (the HTTP transport over
|
|
@@ -379,6 +380,20 @@ export declare function isJSONRPCRequest(value: unknown): value is JSONRPCReques
|
|
|
379
380
|
*/
|
|
380
381
|
export declare function isJSONRPCResponse(value: unknown): value is JSONRPCResponse;
|
|
381
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Determine whether an unknown value is an {@link MCPError}.
|
|
385
|
+
*
|
|
386
|
+
* @param value - The unknown value to inspect
|
|
387
|
+
* @returns `true` only when the value is an `MCPError`
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```ts
|
|
391
|
+
* isMCPError(new MCPError('Method not found', -32601)) // true
|
|
392
|
+
* isMCPError(new Error('Method not found')) // false
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
export declare function isMCPError(value: unknown): value is MCPError;
|
|
396
|
+
|
|
382
397
|
/**
|
|
383
398
|
* Determine whether a value is a valid JSON-RPC REQUEST `id` — a string, a number,
|
|
384
399
|
* or absent.
|
|
@@ -502,8 +517,9 @@ export declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
|
502
517
|
*
|
|
503
518
|
* @remarks
|
|
504
519
|
* - **The mirror of `MCPServer`.** The server DISPATCHES requests over a tool registry;
|
|
505
|
-
* this client ISSUES them over a transport. `connect` runs `initialize
|
|
506
|
-
* `notifications/initialized`; `tools()`
|
|
520
|
+
* this client ISSUES them over a transport. `connect` runs `initialize`, validates and
|
|
521
|
+
* exposes the negotiated `protocol`, then sends `notifications/initialized`; `tools()`
|
|
522
|
+
* lists the remote tools and wraps each as a
|
|
507
523
|
* local {@link ToolInterface} whose `execute` calls back through `call`; `call` runs a
|
|
508
524
|
* remote `tools/call` and returns the tool's value (a remote `isError: true` throws
|
|
509
525
|
* locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}
|
|
@@ -536,6 +552,7 @@ export declare class MCPClient implements MCPClientInterface {
|
|
|
536
552
|
constructor(options: MCPClientOptions);
|
|
537
553
|
get emitter(): EmitterInterface<MCPClientEventMap>;
|
|
538
554
|
get connected(): boolean;
|
|
555
|
+
get protocol(): string | undefined;
|
|
539
556
|
get transport(): ClientTransportInterface;
|
|
540
557
|
on<K extends keyof MCPClientEventMap>(event: K, handler: (...args: MCPClientEventMap[K]) => void): void;
|
|
541
558
|
connect(): Promise<void>;
|
|
@@ -580,7 +597,8 @@ export declare type MCPClientEventMap = {
|
|
|
580
597
|
* @remarks
|
|
581
598
|
* - **The mirror of {@link MCPServerInterface}.** Where the server DISPATCHES requests
|
|
582
599
|
* over a tool registry, the client ISSUES them over a transport: `connect` runs the
|
|
583
|
-
* `initialize` handshake
|
|
600
|
+
* `initialize` handshake, validates and exposes the negotiated `protocol` (then sends
|
|
601
|
+
* `notifications/initialized`); `tools()` lists
|
|
584
602
|
* the remote tools and wraps each as a local {@link ToolInterface} whose `execute`
|
|
585
603
|
* calls back through `call`; `call(name, args)` runs a remote `tools/call` and
|
|
586
604
|
* returns the tool's value (a remote tool FAILURE — `isError: true` — throws locally,
|
|
@@ -604,6 +622,11 @@ export declare interface MCPClientInterface {
|
|
|
604
622
|
readonly emitter: EmitterInterface<MCPClientEventMap>;
|
|
605
623
|
/** Whether the `initialize` handshake has completed and the client is connected. */
|
|
606
624
|
readonly connected: boolean;
|
|
625
|
+
/**
|
|
626
|
+
* The MCP protocol revision negotiated by {@link connect}, or `undefined` before
|
|
627
|
+
* connecting and after {@link disconnect}.
|
|
628
|
+
*/
|
|
629
|
+
readonly protocol: string | undefined;
|
|
607
630
|
/** The injected transport the client drives the remote server over. */
|
|
608
631
|
readonly transport: ClientTransportInterface;
|
|
609
632
|
/**
|
|
@@ -616,11 +639,14 @@ export declare interface MCPClientInterface {
|
|
|
616
639
|
on<K extends keyof MCPClientEventMap>(event: K, handler: (...args: MCPClientEventMap[K]) => void): void;
|
|
617
640
|
/**
|
|
618
641
|
* Connect to the remote server — open the transport and run the `initialize`
|
|
619
|
-
* handshake
|
|
642
|
+
* handshake, validate its negotiated protocol, then send
|
|
643
|
+
* `notifications/initialized`.
|
|
620
644
|
*
|
|
621
645
|
* @remarks
|
|
622
646
|
* Idempotent — a second `connect` while already connected is a no-op. On success
|
|
623
|
-
* the `connect` event fires.
|
|
647
|
+
* {@link protocol} contains a supported revision and the `connect` event fires. A
|
|
648
|
+
* non-string or unsupported revision closes the transport and rejects without
|
|
649
|
+
* connecting or sending the initialized notification.
|
|
624
650
|
*
|
|
625
651
|
* @returns Resolves once the handshake completes and the client is connected
|
|
626
652
|
*/
|
|
@@ -631,7 +657,7 @@ export declare interface MCPClientInterface {
|
|
|
631
657
|
*
|
|
632
658
|
* @remarks
|
|
633
659
|
* Idempotent — a second `disconnect` while already disconnected is a no-op. The
|
|
634
|
-
* `disconnect` event fires
|
|
660
|
+
* `disconnect` event fires and {@link protocol} becomes `undefined`.
|
|
635
661
|
*
|
|
636
662
|
* @returns Resolves once the transport is closed
|
|
637
663
|
*/
|
|
@@ -703,6 +729,37 @@ export declare interface MCPContent {
|
|
|
703
729
|
readonly text: string;
|
|
704
730
|
}
|
|
705
731
|
|
|
732
|
+
/**
|
|
733
|
+
* A remote Model Context Protocol JSON-RPC error, preserving its machine-readable
|
|
734
|
+
* numeric code and optional structured context.
|
|
735
|
+
*
|
|
736
|
+
* @remarks
|
|
737
|
+
* {@link MCPClient} throws this error only for a remote JSON-RPC `error` response.
|
|
738
|
+
* Local lifecycle and transport conditions such as disconnects and request timeouts
|
|
739
|
+
* remain plain `Error`s. `context` carries the response's optional `error.data`
|
|
740
|
+
* unchanged and is `undefined` when the peer omitted it.
|
|
741
|
+
*
|
|
742
|
+
* @example
|
|
743
|
+
* ```ts
|
|
744
|
+
* const error = new MCPError('Method not found', -32601, { method: 'missing' })
|
|
745
|
+
* error.code // -32601
|
|
746
|
+
* error.context // { method: 'missing' }
|
|
747
|
+
* ```
|
|
748
|
+
*/
|
|
749
|
+
export declare class MCPError extends Error {
|
|
750
|
+
readonly name = "MCPError";
|
|
751
|
+
readonly code: number;
|
|
752
|
+
readonly context: unknown;
|
|
753
|
+
/**
|
|
754
|
+
* Create a remote MCP protocol error.
|
|
755
|
+
*
|
|
756
|
+
* @param message - The human-readable JSON-RPC error message
|
|
757
|
+
* @param code - The machine-readable numeric JSON-RPC error code
|
|
758
|
+
* @param context - The optional JSON-RPC `error.data` payload
|
|
759
|
+
*/
|
|
760
|
+
constructor(message: string, code: number, context?: unknown);
|
|
761
|
+
}
|
|
762
|
+
|
|
706
763
|
/**
|
|
707
764
|
* A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0
|
|
708
765
|
* requests over a live {@link ToolManagerInterface}, with NO transport coupling.
|
|
@@ -928,13 +985,14 @@ export declare interface MCPTransportInterface {
|
|
|
928
985
|
export declare function parseJSONRPCMessage(value: unknown): JSONRPCMessage | undefined;
|
|
929
986
|
|
|
930
987
|
/**
|
|
931
|
-
* The MCP protocol revisions this server can negotiate
|
|
932
|
-
* {@link MCP_PROTOCOL_VERSION} plus a prior rev a client may still request.
|
|
988
|
+
* The MCP protocol revisions this server can negotiate.
|
|
933
989
|
*
|
|
934
990
|
* @remarks
|
|
935
991
|
* `initialize` echoes the client's requested `protocolVersion` when it appears in
|
|
936
992
|
* this list, else falls back to {@link MCP_PROTOCOL_VERSION}. Frozen so the list is
|
|
937
|
-
* an immutable contract.
|
|
993
|
+
* an immutable contract. The package does not advertise `2025-03-26` because that
|
|
994
|
+
* revision mandates JSON-RPC batching, while this package accepts only individual
|
|
995
|
+
* JSON-RPC messages.
|
|
938
996
|
*/
|
|
939
997
|
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
|
|
940
998
|
|
package/dist/src/core/index.js
CHANGED
|
@@ -5,15 +5,16 @@ import { Tool } from "@orkestrel/agent";
|
|
|
5
5
|
/** The MCP protocol revision this server implements (the default negotiated version). */
|
|
6
6
|
var MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
7
7
|
/**
|
|
8
|
-
* The MCP protocol revisions this server can negotiate
|
|
9
|
-
* {@link MCP_PROTOCOL_VERSION} plus a prior rev a client may still request.
|
|
8
|
+
* The MCP protocol revisions this server can negotiate.
|
|
10
9
|
*
|
|
11
10
|
* @remarks
|
|
12
11
|
* `initialize` echoes the client's requested `protocolVersion` when it appears in
|
|
13
12
|
* this list, else falls back to {@link MCP_PROTOCOL_VERSION}. Frozen so the list is
|
|
14
|
-
* an immutable contract.
|
|
13
|
+
* an immutable contract. The package does not advertise `2025-03-26` because that
|
|
14
|
+
* revision mandates JSON-RPC batching, while this package accepts only individual
|
|
15
|
+
* JSON-RPC messages.
|
|
15
16
|
*/
|
|
16
|
-
var SUPPORTED_PROTOCOL_VERSIONS = Object.freeze(["2025-06-18"
|
|
17
|
+
var SUPPORTED_PROTOCOL_VERSIONS = Object.freeze(["2025-06-18"]);
|
|
17
18
|
/** JSON-RPC 2.0 reserved error: invalid JSON was received (the message did not parse). */
|
|
18
19
|
var JSONRPC_PARSE_ERROR = -32700;
|
|
19
20
|
/** JSON-RPC 2.0 reserved error: the payload was not a valid Request object. */
|
|
@@ -34,6 +35,61 @@ var DEFAULT_MCP_CLIENT_VERSION = "1.0.0";
|
|
|
34
35
|
*/
|
|
35
36
|
var DEFAULT_MCP_REQUEST_TIMEOUT = 3e4;
|
|
36
37
|
//#endregion
|
|
38
|
+
//#region src/core/errors.ts
|
|
39
|
+
/**
|
|
40
|
+
* A remote Model Context Protocol JSON-RPC error, preserving its machine-readable
|
|
41
|
+
* numeric code and optional structured context.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* {@link MCPClient} throws this error only for a remote JSON-RPC `error` response.
|
|
45
|
+
* Local lifecycle and transport conditions such as disconnects and request timeouts
|
|
46
|
+
* remain plain `Error`s. `context` carries the response's optional `error.data`
|
|
47
|
+
* unchanged and is `undefined` when the peer omitted it.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const error = new MCPError('Method not found', -32601, { method: 'missing' })
|
|
52
|
+
* error.code // -32601
|
|
53
|
+
* error.context // { method: 'missing' }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
var MCPError = class extends Error {
|
|
57
|
+
name = "MCPError";
|
|
58
|
+
code;
|
|
59
|
+
context;
|
|
60
|
+
/**
|
|
61
|
+
* Create a remote MCP protocol error.
|
|
62
|
+
*
|
|
63
|
+
* @param message - The human-readable JSON-RPC error message
|
|
64
|
+
* @param code - The machine-readable numeric JSON-RPC error code
|
|
65
|
+
* @param context - The optional JSON-RPC `error.data` payload
|
|
66
|
+
*/
|
|
67
|
+
constructor(message, code, context) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.code = code;
|
|
70
|
+
this.context = context;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Determine whether an unknown value is an {@link MCPError}.
|
|
75
|
+
*
|
|
76
|
+
* @param value - The unknown value to inspect
|
|
77
|
+
* @returns `true` only when the value is an `MCPError`
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* isMCPError(new MCPError('Method not found', -32601)) // true
|
|
82
|
+
* isMCPError(new Error('Method not found')) // false
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
function isMCPError(value) {
|
|
86
|
+
try {
|
|
87
|
+
return value instanceof MCPError;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
37
93
|
//#region src/core/validators.ts
|
|
38
94
|
/**
|
|
39
95
|
* Determine whether a value is a valid JSON-RPC REQUEST `id` — a string, a number,
|
|
@@ -313,18 +369,16 @@ function initializeResult(name, version, requested) {
|
|
|
313
369
|
*/
|
|
314
370
|
function bindServer(server, transport) {
|
|
315
371
|
let active = true;
|
|
316
|
-
transport.listen((message) => {
|
|
372
|
+
transport.listen(async (message) => {
|
|
317
373
|
if (!active) return;
|
|
318
|
-
|
|
374
|
+
try {
|
|
375
|
+
const response = await server.handle(message);
|
|
376
|
+
if (response !== void 0) await transport.send(response);
|
|
377
|
+
} catch (error) {
|
|
319
378
|
try {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
server.emitter.emit("error", error);
|
|
325
|
-
} catch {}
|
|
326
|
-
}
|
|
327
|
-
})();
|
|
379
|
+
server.emitter.emit("error", error);
|
|
380
|
+
} catch {}
|
|
381
|
+
}
|
|
328
382
|
});
|
|
329
383
|
transport.closed(() => {
|
|
330
384
|
active = false;
|
|
@@ -449,8 +503,8 @@ var MCPServer = class {
|
|
|
449
503
|
#tools;
|
|
450
504
|
constructor(options) {
|
|
451
505
|
this.#emitter = new Emitter({
|
|
452
|
-
on: options.on,
|
|
453
|
-
error: options.error
|
|
506
|
+
...options.on !== void 0 ? { on: options.on } : {},
|
|
507
|
+
...options.error !== void 0 ? { error: options.error } : {}
|
|
454
508
|
});
|
|
455
509
|
this.#name = options.name;
|
|
456
510
|
this.#version = options.version;
|
|
@@ -515,8 +569,9 @@ var MCPServer = class {
|
|
|
515
569
|
*
|
|
516
570
|
* @remarks
|
|
517
571
|
* - **The mirror of `MCPServer`.** The server DISPATCHES requests over a tool registry;
|
|
518
|
-
* this client ISSUES them over a transport. `connect` runs `initialize
|
|
519
|
-
* `notifications/initialized`; `tools()`
|
|
572
|
+
* this client ISSUES them over a transport. `connect` runs `initialize`, validates and
|
|
573
|
+
* exposes the negotiated `protocol`, then sends `notifications/initialized`; `tools()`
|
|
574
|
+
* lists the remote tools and wraps each as a
|
|
520
575
|
* local {@link ToolInterface} whose `execute` calls back through `call`; `call` runs a
|
|
521
576
|
* remote `tools/call` and returns the tool's value (a remote `isError: true` throws
|
|
522
577
|
* locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}
|
|
@@ -553,10 +608,11 @@ var MCPClient = class {
|
|
|
553
608
|
#pending = /* @__PURE__ */ new Map();
|
|
554
609
|
#nextId = 0;
|
|
555
610
|
#connected = false;
|
|
611
|
+
#protocol = void 0;
|
|
556
612
|
constructor(options) {
|
|
557
613
|
this.#emitter = new Emitter({
|
|
558
|
-
on: options.on,
|
|
559
|
-
error: options.error
|
|
614
|
+
...options.on !== void 0 ? { on: options.on } : {},
|
|
615
|
+
...options.error !== void 0 ? { error: options.error } : {}
|
|
560
616
|
});
|
|
561
617
|
this.#transport = options.transport;
|
|
562
618
|
this.#name = options.name ?? "taverna";
|
|
@@ -570,6 +626,9 @@ var MCPClient = class {
|
|
|
570
626
|
get connected() {
|
|
571
627
|
return this.#connected;
|
|
572
628
|
}
|
|
629
|
+
get protocol() {
|
|
630
|
+
return this.#protocol;
|
|
631
|
+
}
|
|
573
632
|
get transport() {
|
|
574
633
|
return this.#transport;
|
|
575
634
|
}
|
|
@@ -579,7 +638,7 @@ var MCPClient = class {
|
|
|
579
638
|
async connect() {
|
|
580
639
|
if (this.#connected) return;
|
|
581
640
|
await this.#transport.start();
|
|
582
|
-
await this.#request("initialize", {
|
|
641
|
+
const result = await this.#request("initialize", {
|
|
583
642
|
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
584
643
|
capabilities: {},
|
|
585
644
|
clientInfo: {
|
|
@@ -587,6 +646,13 @@ var MCPClient = class {
|
|
|
587
646
|
version: this.#version
|
|
588
647
|
}
|
|
589
648
|
});
|
|
649
|
+
const protocol = isRecord(result) ? result["protocolVersion"] : void 0;
|
|
650
|
+
if (!isString(protocol) || !SUPPORTED_PROTOCOL_VERSIONS.includes(protocol)) {
|
|
651
|
+
await this.#transport.close();
|
|
652
|
+
if (isString(protocol)) throw new Error(`MCP server negotiated unsupported protocol version '${protocol}'`);
|
|
653
|
+
throw new Error("MCP server returned a non-string protocol version");
|
|
654
|
+
}
|
|
655
|
+
this.#protocol = protocol;
|
|
590
656
|
this.#connected = true;
|
|
591
657
|
await this.#transport.send({
|
|
592
658
|
jsonrpc: "2.0",
|
|
@@ -597,8 +663,8 @@ var MCPClient = class {
|
|
|
597
663
|
async disconnect() {
|
|
598
664
|
if (!this.#connected) return;
|
|
599
665
|
this.#connected = false;
|
|
600
|
-
|
|
601
|
-
this.#pending.
|
|
666
|
+
this.#protocol = void 0;
|
|
667
|
+
for (const id of this.#pending.keys()) this.#settle(id, /* @__PURE__ */ new Error("MCP client disconnected"), true);
|
|
602
668
|
await this.#transport.close();
|
|
603
669
|
this.#emitter.emit("disconnect");
|
|
604
670
|
}
|
|
@@ -638,38 +704,24 @@ var MCPClient = class {
|
|
|
638
704
|
};
|
|
639
705
|
return new Promise((resolve, reject) => {
|
|
640
706
|
const deadline = AbortSignal.timeout(this.#timeout);
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
deadline.removeEventListener("abort", onDeadline);
|
|
644
|
-
};
|
|
645
|
-
const onDeadline = () => {
|
|
646
|
-
settle();
|
|
647
|
-
reject(/* @__PURE__ */ new Error(`MCP request '${method}' timed out after ${this.#timeout}ms`));
|
|
648
|
-
};
|
|
649
|
-
deadline.addEventListener("abort", onDeadline, { once: true });
|
|
707
|
+
const timeout = this.#timeoutRequest.bind(this, id, method);
|
|
708
|
+
deadline.addEventListener("abort", timeout, { once: true });
|
|
650
709
|
this.#pending.set(id, {
|
|
651
|
-
resolve
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
reject: (error) => {
|
|
656
|
-
settle();
|
|
657
|
-
reject(error);
|
|
658
|
-
}
|
|
710
|
+
resolve,
|
|
711
|
+
reject,
|
|
712
|
+
deadline,
|
|
713
|
+
timeout
|
|
659
714
|
});
|
|
660
715
|
this.#transport.send(request).catch((error) => {
|
|
661
|
-
|
|
662
|
-
if (pending === void 0) return;
|
|
663
|
-
pending.reject(error instanceof Error ? error : new Error(String(error)));
|
|
716
|
+
this.#settle(id, error instanceof Error ? error : new Error(String(error)), true);
|
|
664
717
|
});
|
|
665
718
|
});
|
|
666
719
|
}
|
|
667
720
|
#receive(message) {
|
|
668
721
|
if (isJSONRPCResponse(message) && isRequestId(message.id)) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
else pending.resolve(message.result);
|
|
722
|
+
if (this.#pending.has(message.id)) {
|
|
723
|
+
if (message.error !== void 0) this.#settle(message.id, new MCPError(message.error.message, message.error.code, message.error.data), true);
|
|
724
|
+
else this.#settle(message.id, message.result, false);
|
|
673
725
|
return;
|
|
674
726
|
}
|
|
675
727
|
}
|
|
@@ -680,7 +732,7 @@ var MCPClient = class {
|
|
|
680
732
|
const description = descriptor["description"];
|
|
681
733
|
const options = {
|
|
682
734
|
name,
|
|
683
|
-
execute:
|
|
735
|
+
execute: this.call.bind(this, name)
|
|
684
736
|
};
|
|
685
737
|
if (isString(description)) options.description = description;
|
|
686
738
|
if (isRecord(inputSchema)) options.parameters = inputSchema;
|
|
@@ -692,6 +744,17 @@ var MCPClient = class {
|
|
|
692
744
|
for (const block of result["content"]) if (isRecord(block) && isString(block["text"])) parts.push(block["text"]);
|
|
693
745
|
return parts.join("\n");
|
|
694
746
|
}
|
|
747
|
+
#timeoutRequest(id, method) {
|
|
748
|
+
this.#settle(id, /* @__PURE__ */ new Error(`MCP request '${method}' timed out after ${this.#timeout}ms`), true);
|
|
749
|
+
}
|
|
750
|
+
#settle(id, value, failed) {
|
|
751
|
+
const pending = this.#pending.get(id);
|
|
752
|
+
if (pending === void 0) return;
|
|
753
|
+
this.#pending.delete(id);
|
|
754
|
+
pending.deadline.removeEventListener("abort", pending.timeout);
|
|
755
|
+
if (failed) pending.reject(value);
|
|
756
|
+
else pending.resolve(value);
|
|
757
|
+
}
|
|
695
758
|
};
|
|
696
759
|
//#endregion
|
|
697
760
|
//#region src/core/factories.ts
|
|
@@ -741,7 +804,8 @@ function createMCPServer(options) {
|
|
|
741
804
|
* @remarks
|
|
742
805
|
* The egress mirror of {@link createMCPServer}: where the server exposes a local tool
|
|
743
806
|
* registry over MCP, the client USES a remote server's tools. `connect()` handshakes,
|
|
744
|
-
* `tools()` lists + wraps the remote
|
|
807
|
+
* validates and exposes the negotiated protocol, `tools()` lists + wraps the remote
|
|
808
|
+
* tools (each `execute` calls back over the wire),
|
|
745
809
|
* and `call(name, args)` runs a remote `tools/call` (a remote tool failure throws
|
|
746
810
|
* locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}
|
|
747
811
|
* isolates it). The transport is injected — a concrete one (the HTTP transport over
|
|
@@ -779,8 +843,8 @@ function createMCPClient(options) {
|
|
|
779
843
|
* @remarks
|
|
780
844
|
* Hand the RESULT to `createMCPClient({ transport })`, then pass the SAME
|
|
781
845
|
* `transport` to {@link import('./helpers.js').bindClient} to complete the inbound
|
|
782
|
-
* wiring: `send` serializes each outbound {@link JSONRPCMessage}
|
|
783
|
-
*
|
|
846
|
+
* wiring: `send` serializes each outbound {@link JSONRPCMessage} and writes it via
|
|
847
|
+
* `transport.send`; `close` closes the underlying
|
|
784
848
|
* `transport`; `start` is a no-op (the duplex channel is already open by the time
|
|
785
849
|
* it is handed in — there is no separate connect step at this layer); `session` is
|
|
786
850
|
* always `undefined` (session correlation is a higher-level concern the duplex port
|
|
@@ -804,8 +868,7 @@ function createDuplexClientTransport(transport) {
|
|
|
804
868
|
session: void 0,
|
|
805
869
|
async start() {},
|
|
806
870
|
async send(message) {
|
|
807
|
-
|
|
808
|
-
for (const one of messages) await transport.send(JSON.stringify(one));
|
|
871
|
+
await transport.send(JSON.stringify(message));
|
|
809
872
|
},
|
|
810
873
|
async close() {
|
|
811
874
|
await transport.close();
|
|
@@ -813,6 +876,6 @@ function createDuplexClientTransport(transport) {
|
|
|
813
876
|
};
|
|
814
877
|
}
|
|
815
878
|
//#endregion
|
|
816
|
-
export { DEFAULT_MCP_CLIENT_NAME, DEFAULT_MCP_CLIENT_VERSION, DEFAULT_MCP_REQUEST_TIMEOUT, JSONRPC_INVALID_PARAMS, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_PARSE_ERROR, JSONRPC_SERVER_ERROR, MCPClient, MCPServer, MCP_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, bindClient, bindServer, buildToolDescriptors, buildToolResult, createDuplexClientTransport, createMCPClient, createMCPServer, initializeResult, isInitializeRequest, isJSONRPCMessage, isJSONRPCRequest, isJSONRPCResponse, isRequestId, jsonRPCError, jsonRPCResult, parseJSONRPCMessage };
|
|
879
|
+
export { DEFAULT_MCP_CLIENT_NAME, DEFAULT_MCP_CLIENT_VERSION, DEFAULT_MCP_REQUEST_TIMEOUT, JSONRPC_INVALID_PARAMS, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_PARSE_ERROR, JSONRPC_SERVER_ERROR, MCPClient, MCPError, MCPServer, MCP_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, bindClient, bindServer, buildToolDescriptors, buildToolResult, createDuplexClientTransport, createMCPClient, createMCPServer, initializeResult, isInitializeRequest, isJSONRPCMessage, isJSONRPCRequest, isJSONRPCResponse, isMCPError, isRequestId, jsonRPCError, jsonRPCResult, parseJSONRPCMessage };
|
|
817
880
|
|
|
818
881
|
//# sourceMappingURL=index.js.map
|