@orkestrel/mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/src/core/index.cjs +673 -0
- package/dist/src/core/index.cjs.map +1 -0
- package/dist/src/core/index.d.cts +805 -0
- package/dist/src/core/index.d.ts +805 -0
- package/dist/src/core/index.js +648 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/server/index.cjs +1372 -0
- package/dist/src/server/index.cjs.map +1 -0
- package/dist/src/server/index.d.cts +1044 -0
- package/dist/src/server/index.d.ts +1044 -0
- package/dist/src/server/index.js +1344 -0
- package/dist/src/server/index.js.map +1 -0
- package/package.json +106 -0
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
import { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
2
|
+
import { EmitterHooks } from '@orkestrel/emitter';
|
|
3
|
+
import { EmitterInterface } from '@orkestrel/emitter';
|
|
4
|
+
import { ToolInterface } from '@orkestrel/agent';
|
|
5
|
+
import { ToolManagerInterface } from '@orkestrel/agent';
|
|
6
|
+
import { ToolResult } from '@orkestrel/agent';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Map a {@link ToolManagerInterface}'s definitions to MCP `tools/list` descriptors
|
|
10
|
+
* — renaming `parameters` to the wire's `inputSchema`.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Each {@link import('@orkestrel/agent').ToolDefinition} carries through its
|
|
14
|
+
* `name` and (when present) `description`; its open JSON-Schema `parameters`
|
|
15
|
+
* becomes `inputSchema`, defaulting to an empty object schema (`{ type: 'object' }`)
|
|
16
|
+
* when a tool declares none (MCP requires an `inputSchema`).
|
|
17
|
+
*
|
|
18
|
+
* @param manager - The tool registry to describe
|
|
19
|
+
* @returns One {@link MCPToolDescriptor} per registered tool, in registry order
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildToolDescriptors(manager: ToolManagerInterface): readonly MCPToolDescriptor[];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Map an executed tool's {@link ToolResult} to an MCP {@link MCPToolResult} — the
|
|
25
|
+
* value (or error) as a `text` content block.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* The {@link ToolManagerInterface} already isolates a thrown tool into
|
|
29
|
+
* `result.error` (so the server adds NO try/catch around `execute`): when `error`
|
|
30
|
+
* is present, this builds an `isError: true` result carrying the error text, so the
|
|
31
|
+
* model sees the failure as a tool result it can react to rather than a protocol
|
|
32
|
+
* error; otherwise it serializes `result.value` (via `JSON.stringify`) into one
|
|
33
|
+
* `text` block.
|
|
34
|
+
*
|
|
35
|
+
* @param result - The tool's execution outcome
|
|
36
|
+
* @returns The MCP tool-call result
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildToolResult(result: ToolResult): MCPToolResult;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The observable events of a {@link ClientTransportInterface} (§13) — the moments the
|
|
42
|
+
* {@link MCPClientInterface} (and any tracer) subscribes to via `transport.emitter.on`.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* - `message` — a JSON-RPC message ARRIVED from the remote server (a response the
|
|
46
|
+
* client correlates to a pending request by `id`, or a server-initiated
|
|
47
|
+
* notification). The transport decodes the wire bytes (a JSON body or an SSE
|
|
48
|
+
* `data:` event) and emits the parsed {@link JSONRPCMessage}.
|
|
49
|
+
* - `close` — the transport's connection ended (a stream closed, `close()` ran).
|
|
50
|
+
* - `error` — a transport-level fault (a malformed message, a network error); the
|
|
51
|
+
* payload is typed `unknown` (§13). This is a DOMAIN event, distinct from the emitter's
|
|
52
|
+
* own listener-error channel: a listener throw is routed to the emitter's `error` handler
|
|
53
|
+
* (the `error` option), never onto this map. Declared as a `type` alias (§4.5) so the
|
|
54
|
+
* type-literal satisfies `EventMap` structurally.
|
|
55
|
+
*/
|
|
56
|
+
export declare type ClientTransportEventMap = {
|
|
57
|
+
/** A JSON-RPC message arrived from the remote server (a response, or a notification). */
|
|
58
|
+
readonly message: readonly [message: JSONRPCMessage];
|
|
59
|
+
/** The transport's connection ended. */
|
|
60
|
+
readonly close: readonly [];
|
|
61
|
+
/** A transport-level fault — the caught error (typed `unknown`, §13). */
|
|
62
|
+
readonly error: readonly [error: unknown];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A transport-agnostic carrier for the MCP CLIENT — pumps JSON-RPC messages to a
|
|
67
|
+
* remote server and surfaces the server's replies on its `emitter`'s `message`
|
|
68
|
+
* event, with NO knowledge of the protocol it carries.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* The mirror of the server's "a transport pumps strings through `handle`": here the
|
|
72
|
+
* {@link MCPClientInterface} hands the transport a {@link JSONRPCMessage} (or a batch)
|
|
73
|
+
* via `send`, and the transport delivers each decoded reply back through the
|
|
74
|
+
* `message` event the client subscribed to. The minimal carrier surface (§21): a
|
|
75
|
+
* `start` (open the connection / arm any reader), `send` (write a message or batch),
|
|
76
|
+
* and `close` (tear down). `session` exposes a server-assigned session id once a
|
|
77
|
+
* stateful transport has one (`undefined` for the stateless v1) — reserved for the
|
|
78
|
+
* later sessions tier. Concrete transports (the HTTP transport over `fetch`, a future
|
|
79
|
+
* WebSocket one) live in `src/server/mcp`; the in-process loopback transport in the
|
|
80
|
+
* tests is one too.
|
|
81
|
+
*/
|
|
82
|
+
export declare interface ClientTransportInterface {
|
|
83
|
+
readonly emitter: EmitterInterface<ClientTransportEventMap>;
|
|
84
|
+
/** A server-assigned session id once a stateful transport has one; `undefined` otherwise. */
|
|
85
|
+
readonly session: string | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Open the transport — establish the connection and arm any reply reader.
|
|
88
|
+
*
|
|
89
|
+
* @returns Resolves once the transport is ready to `send`
|
|
90
|
+
*/
|
|
91
|
+
start(): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Send one JSON-RPC message (or a batch) to the remote server.
|
|
94
|
+
*
|
|
95
|
+
* @remarks
|
|
96
|
+
* Each decoded reply is surfaced on the `emitter`'s `message` event — `send`
|
|
97
|
+
* itself resolves once the message has been written (and, for a request/response
|
|
98
|
+
* transport, its synchronous reply emitted), not when a logical response arrives;
|
|
99
|
+
* the {@link MCPClientInterface} awaits the response through its `id` correlation.
|
|
100
|
+
*
|
|
101
|
+
* @param message - One message, or a batch of them, to write to the wire
|
|
102
|
+
* @returns Resolves once the message(s) have been sent
|
|
103
|
+
*/
|
|
104
|
+
send(message: JSONRPCMessage | readonly JSONRPCMessage[]): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Close the transport — end the connection and release resources.
|
|
107
|
+
*
|
|
108
|
+
* @returns Resolves once the transport is closed
|
|
109
|
+
*/
|
|
110
|
+
close(): Promise<void>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create a transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE
|
|
115
|
+
* MCP server over an injected {@link import('./types.js').ClientTransportInterface},
|
|
116
|
+
* runs the `initialize` handshake, and exposes the server's tools as local
|
|
117
|
+
* {@link import('@orkestrel/agent').ToolInterface}s an agent can run.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* The egress mirror of {@link createMCPServer}: where the server exposes a local tool
|
|
121
|
+
* registry over MCP, the client USES a remote server's tools. `connect()` handshakes,
|
|
122
|
+
* `tools()` lists + wraps the remote tools (each `execute` calls back over the wire),
|
|
123
|
+
* and `call(name, args)` runs a remote `tools/call` (a remote tool failure throws
|
|
124
|
+
* locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}
|
|
125
|
+
* isolates it). The transport is injected — a concrete one (the HTTP transport over
|
|
126
|
+
* `fetch`) lives in `@src/server`; the client itself is provider-agnostic. Subscribe
|
|
127
|
+
* to `connect` / `disconnect` / `notification` via `client.on(...)` (or
|
|
128
|
+
* `client.emitter.on(...)`).
|
|
129
|
+
*
|
|
130
|
+
* @param options - `transport` (the carrier; REQUIRED), `name` / `version` (the client
|
|
131
|
+
* identity), `timeout` (the per-request deadline), and the reserved `on`
|
|
132
|
+
* {@link import('@orkestrel/emitter').EmitterHooks} (see {@link MCPClientOptions})
|
|
133
|
+
* @returns A working {@link MCPClientInterface}
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* import { createMCPClient } from '@src/core'
|
|
138
|
+
* import { createHTTPClientTransport } from '@src/server'
|
|
139
|
+
*
|
|
140
|
+
* const client = createMCPClient({
|
|
141
|
+
* transport: createHTTPClientTransport({ url: 'http://localhost:3000/mcp' }),
|
|
142
|
+
* })
|
|
143
|
+
* await client.connect()
|
|
144
|
+
* agent.context.tools.add(await client.tools()) // give the agent the remote tools
|
|
145
|
+
* const value = await client.call('search', { query: 'mcp' })
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export declare function createMCPClient(options: MCPClientOptions): MCPClientInterface;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Create a transport-agnostic Model Context Protocol server — exposes a live
|
|
152
|
+
* {@link import('@orkestrel/agent').ToolManagerInterface} over JSON-RPC 2.0
|
|
153
|
+
* (`initialize` / `ping` / `tools/list` / `tools/call`).
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* Pump raw message strings through `handle` (parse → dispatch → serialize) from a
|
|
157
|
+
* transport, or call the typed `dispatch` directly with an already-parsed request.
|
|
158
|
+
* The server is provider-agnostic — JSON-RPC plus the tool registry, with no HTTP
|
|
159
|
+
* and no model. The {@link import('@orkestrel/agent').ToolManagerInterface} already
|
|
160
|
+
* isolates a thrown tool into a result error (surfaced as an MCP `isError: true`
|
|
161
|
+
* tool result), so a misbehaving tool never crashes a dispatch. Subscribe to the
|
|
162
|
+
* `request` event via `server.emitter.on('request', …)` for tracing.
|
|
163
|
+
*
|
|
164
|
+
* @param options - `name` / `version` (the server identity), `tools` (the live
|
|
165
|
+
* registry to expose), an optional `description`, and the reserved `on`
|
|
166
|
+
* {@link import('@orkestrel/emitter').EmitterHooks} (see {@link MCPServerOptions})
|
|
167
|
+
* @returns A working {@link MCPServerInterface}
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* import { createMCPServer, createTool, createToolManager } from '@src/core'
|
|
172
|
+
*
|
|
173
|
+
* const tools = createToolManager()
|
|
174
|
+
* tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))
|
|
175
|
+
*
|
|
176
|
+
* const server = createMCPServer({ name: 'calculator', version: '1.0.0', tools })
|
|
177
|
+
* server.emitter.on('request', (method, id) => log(method, id))
|
|
178
|
+
*
|
|
179
|
+
* // A transport pumps message strings through `handle`:
|
|
180
|
+
* const reply = await server.handle('{"jsonrpc":"2.0","method":"tools/list","id":1}')
|
|
181
|
+
* // reply → '{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"add","inputSchema":{"type":"object"}}]}}'
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export declare function createMCPServer(options: MCPServerOptions): MCPServerInterface;
|
|
185
|
+
|
|
186
|
+
/** The default client name reported in the MCP `initialize` handshake (`clientInfo.name`). */
|
|
187
|
+
export declare const DEFAULT_MCP_CLIENT_NAME = "taverna";
|
|
188
|
+
|
|
189
|
+
/** The default client version reported in the MCP `initialize` handshake (`clientInfo.version`). */
|
|
190
|
+
export declare const DEFAULT_MCP_CLIENT_VERSION = "1.0.0";
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The default per-request deadline (ms) an `MCPClient` applies when `options.timeout`
|
|
194
|
+
* is unset — a request the remote server does not answer within it rejects.
|
|
195
|
+
*/
|
|
196
|
+
export declare const DEFAULT_MCP_REQUEST_TIMEOUT = 30000;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Build the MCP `initialize` result — the negotiated protocol version, the
|
|
200
|
+
* advertised capabilities, and the server identity.
|
|
201
|
+
*
|
|
202
|
+
* @remarks
|
|
203
|
+
* Version negotiation echoes the client's `requested` version when it is one of the
|
|
204
|
+
* {@link SUPPORTED_PROTOCOL_VERSIONS}, else falls back to {@link MCP_PROTOCOL_VERSION}.
|
|
205
|
+
* `capabilities.tools` is an empty object — this server advertises the tools
|
|
206
|
+
* capability with no sub-options (no list-changed notification yet).
|
|
207
|
+
*
|
|
208
|
+
* @param name - The server name (echoed in `serverInfo`)
|
|
209
|
+
* @param version - The server version (echoed in `serverInfo`)
|
|
210
|
+
* @param requested - The client's requested protocol version (negotiated when supported)
|
|
211
|
+
* @returns The `initialize` result payload
|
|
212
|
+
*/
|
|
213
|
+
export declare function initializeResult(name: string, version: string, requested?: string): Readonly<Record<string, unknown>>;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Determine whether a parsed value is an MCP `initialize` request — a
|
|
217
|
+
* {@link JSONRPCRequest} whose `method` is `'initialize'`.
|
|
218
|
+
*
|
|
219
|
+
* @param value - The already-parsed value to test
|
|
220
|
+
* @returns `true` when `value` is a valid `initialize` request
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* isInitializeRequest({ jsonrpc: '2.0', method: 'initialize', id: 1 }) // true
|
|
225
|
+
* isInitializeRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // false
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
export declare function isInitializeRequest(value: unknown): value is JSONRPCRequest;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Determine whether a parsed value is a {@link JSONRPCMessage} — a request or a
|
|
232
|
+
* response.
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* The union of {@link isJSONRPCRequest} and {@link isJSONRPCResponse}. Total (§14).
|
|
236
|
+
*
|
|
237
|
+
* @param value - The already-parsed value to test
|
|
238
|
+
* @returns `true` when `value` is a valid JSON-RPC request or response
|
|
239
|
+
*/
|
|
240
|
+
export declare function isJSONRPCMessage(value: unknown): value is JSONRPCMessage;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Determine whether a parsed value is a {@link JSONRPCRequest}.
|
|
244
|
+
*
|
|
245
|
+
* @remarks
|
|
246
|
+
* A request is a record with `jsonrpc === '2.0'` and a string `method`. `id`, when
|
|
247
|
+
* present, must be a string or number; its ABSENCE is valid — that marks a
|
|
248
|
+
* NOTIFICATION (a fire-and-forget request that yields no response). `params`, when
|
|
249
|
+
* present, must be a record. Total (§14): any other input returns `false`.
|
|
250
|
+
*
|
|
251
|
+
* @param value - The already-parsed value to test
|
|
252
|
+
* @returns `true` when `value` is a valid JSON-RPC request
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```ts
|
|
256
|
+
* isJSONRPCRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // true
|
|
257
|
+
* isJSONRPCRequest({ jsonrpc: '2.0', method: 'notifications/initialized' }) // true — a notification
|
|
258
|
+
* isJSONRPCRequest({ jsonrpc: '1.0', method: 'ping' }) // false
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export declare function isJSONRPCRequest(value: unknown): value is JSONRPCRequest;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Determine whether a parsed value is a {@link JSONRPCResponse}.
|
|
265
|
+
*
|
|
266
|
+
* @remarks
|
|
267
|
+
* A response is a record with `jsonrpc === '2.0'`, an `id` that is a string,
|
|
268
|
+
* number, or `null`, and EXACTLY ONE of a `result` (any value, including
|
|
269
|
+
* `undefined`'s absence) or an `error` (a record with a numeric `code` and string
|
|
270
|
+
* `message`). Total (§14).
|
|
271
|
+
*
|
|
272
|
+
* @param value - The already-parsed value to test
|
|
273
|
+
* @returns `true` when `value` is a valid JSON-RPC response
|
|
274
|
+
*/
|
|
275
|
+
export declare function isJSONRPCResponse(value: unknown): value is JSONRPCResponse;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Determine whether a value is a valid JSON-RPC REQUEST `id` — a string, a number,
|
|
279
|
+
* or absent.
|
|
280
|
+
*
|
|
281
|
+
* @remarks
|
|
282
|
+
* A request id is a string, a number, or `undefined` (its ABSENCE marks a
|
|
283
|
+
* NOTIFICATION). `null` is NOT a valid request id — it is valid only on a RESPONSE.
|
|
284
|
+
* Total (§14): any other input returns `false`.
|
|
285
|
+
*
|
|
286
|
+
* @param value - The already-parsed value to test
|
|
287
|
+
* @returns `true` when `value` is a string, a number, or `undefined`
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* isRequestId(1) // true
|
|
292
|
+
* isRequestId('abc') // true
|
|
293
|
+
* isRequestId(undefined) // true — a notification
|
|
294
|
+
* isRequestId(null) // false — valid only on a response
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
export declare function isRequestId(value: unknown): value is string | number | undefined;
|
|
298
|
+
|
|
299
|
+
/** JSON-RPC 2.0 reserved error: the method's parameters were invalid. */
|
|
300
|
+
export declare const JSONRPC_INVALID_PARAMS = -32602;
|
|
301
|
+
|
|
302
|
+
/** JSON-RPC 2.0 reserved error: the payload was not a valid Request object. */
|
|
303
|
+
export declare const JSONRPC_INVALID_REQUEST = -32600;
|
|
304
|
+
|
|
305
|
+
/** JSON-RPC 2.0 reserved error: the requested method does not exist. */
|
|
306
|
+
export declare const JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
307
|
+
|
|
308
|
+
/** JSON-RPC 2.0 reserved error: invalid JSON was received (the message did not parse). */
|
|
309
|
+
export declare const JSONRPC_PARSE_ERROR = -32700;
|
|
310
|
+
|
|
311
|
+
/** JSON-RPC 2.0 implementation-defined server error (the `-32000` to `-32099` range). */
|
|
312
|
+
export declare const JSONRPC_SERVER_ERROR = -32000;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Build a JSON-RPC error {@link JSONRPCResponse} — the `id` echoed, the failure as
|
|
316
|
+
* an `error` object.
|
|
317
|
+
*
|
|
318
|
+
* @param id - The request's id (`null` for a parse / invalid-request error)
|
|
319
|
+
* @param code - One of the reserved JSON-RPC codes (see `./constants.js`)
|
|
320
|
+
* @param message - A short human description of the failure
|
|
321
|
+
* @param data - An OPTIONAL machine-readable payload (omitted from the envelope when absent)
|
|
322
|
+
* @returns The error response envelope
|
|
323
|
+
*/
|
|
324
|
+
export declare function jsonRPCError(id: string | number | null, code: number, message: string, data?: unknown): JSONRPCResponse;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* A JSON-RPC 2.0 error object — the `error` member of a failed
|
|
328
|
+
* {@link JSONRPCResponse}.
|
|
329
|
+
*
|
|
330
|
+
* @remarks
|
|
331
|
+
* `code` is one of the reserved JSON-RPC codes (see `./constants.js`); `message`
|
|
332
|
+
* is a short human description; `data` is an OPTIONAL machine-readable payload
|
|
333
|
+
* carrying extra detail.
|
|
334
|
+
*/
|
|
335
|
+
export declare interface JSONRPCErrorData {
|
|
336
|
+
readonly code: number;
|
|
337
|
+
readonly message: string;
|
|
338
|
+
readonly data?: unknown;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** A JSON-RPC 2.0 message on the wire — a {@link JSONRPCRequest} or a {@link JSONRPCResponse}. */
|
|
342
|
+
export declare type JSONRPCMessage = JSONRPCRequest | JSONRPCResponse;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* A JSON-RPC 2.0 request — a `method` call with optional `params`, correlated to
|
|
346
|
+
* its response by `id`.
|
|
347
|
+
*
|
|
348
|
+
* @remarks
|
|
349
|
+
* `jsonrpc` is the literal `'2.0'`. An ABSENT `id` marks a NOTIFICATION — a
|
|
350
|
+
* fire-and-forget call the server handles WITHOUT producing a response (e.g.
|
|
351
|
+
* `notifications/initialized`). `params` is an open record forwarded to the
|
|
352
|
+
* method handler (the handler narrows the fields it reads, §14).
|
|
353
|
+
*/
|
|
354
|
+
export declare interface JSONRPCRequest {
|
|
355
|
+
readonly jsonrpc: '2.0';
|
|
356
|
+
readonly method: string;
|
|
357
|
+
/** Correlates the request with its response; ABSENT ⇒ a notification (no response). */
|
|
358
|
+
readonly id?: string | number;
|
|
359
|
+
/** The method's open argument record (narrowed by the handler, §14). */
|
|
360
|
+
readonly params?: Readonly<Record<string, unknown>>;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* A JSON-RPC 2.0 response — the same `id` as its request, carrying EITHER a
|
|
365
|
+
* `result` (success) OR an `error` (failure), never both.
|
|
366
|
+
*
|
|
367
|
+
* @remarks
|
|
368
|
+
* `id` is `null` only when the request could not be parsed or its id read (a
|
|
369
|
+
* parse / invalid-request error), per the spec; otherwise it echoes the
|
|
370
|
+
* request's id. `result` is the method's return value (an open `unknown`);
|
|
371
|
+
* `error` is a {@link JSONRPCErrorData}.
|
|
372
|
+
*/
|
|
373
|
+
export declare interface JSONRPCResponse {
|
|
374
|
+
readonly jsonrpc: '2.0';
|
|
375
|
+
readonly id: string | number | null;
|
|
376
|
+
readonly result?: unknown;
|
|
377
|
+
readonly error?: JSONRPCErrorData;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Build a JSON-RPC success {@link JSONRPCResponse} — the `id` echoed, the method's
|
|
382
|
+
* value as `result`.
|
|
383
|
+
*
|
|
384
|
+
* @param id - The request's id (`null` only for a parse / invalid-request error)
|
|
385
|
+
* @param result - The method's return value
|
|
386
|
+
* @returns The success response envelope
|
|
387
|
+
*/
|
|
388
|
+
export declare function jsonRPCResult(id: string | number | null, result: unknown): JSONRPCResponse;
|
|
389
|
+
|
|
390
|
+
/** The MCP protocol revision this server implements (the default negotiated version). */
|
|
391
|
+
export declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* A transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE MCP server
|
|
395
|
+
* over an injected {@link ClientTransportInterface}, runs the `initialize` handshake,
|
|
396
|
+
* and exposes the server's tools as local {@link ToolInterface}s an agent can run.
|
|
397
|
+
*
|
|
398
|
+
* @remarks
|
|
399
|
+
* - **The mirror of `MCPServer`.** The server DISPATCHES requests over a tool registry;
|
|
400
|
+
* this client ISSUES them over a transport. `connect` runs `initialize` then sends
|
|
401
|
+
* `notifications/initialized`; `tools()` lists the remote tools and wraps each as a
|
|
402
|
+
* local {@link ToolInterface} whose `execute` calls back through `call`; `call` runs a
|
|
403
|
+
* remote `tools/call` and returns the tool's value (a remote `isError: true` throws
|
|
404
|
+
* locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}
|
|
405
|
+
* isolates it into a result `error` just like a local throw).
|
|
406
|
+
* - **Request↔response correlation.** Each request is tagged with a monotonic numeric
|
|
407
|
+
* `id` ({@link #nextId}); a single transport `message` subscription resolves / rejects
|
|
408
|
+
* the matching {@link #pending} entry by `id`. A message that is NOT a response to a
|
|
409
|
+
* pending request is a server NOTIFICATION — re-surfaced on the `notification` event.
|
|
410
|
+
* - **Per-request deadline.** `#request` races `AbortSignal.timeout(this.#timeout)` (the
|
|
411
|
+
* taverna idiom — never a raw `setTimeout`): a server that never replies REJECTS the
|
|
412
|
+
* pending request once the deadline fires, never hanging.
|
|
413
|
+
* - **Transport-agnostic.** Imports only core siblings (JSON-RPC + the tool vocabulary);
|
|
414
|
+
* the concrete transport is injected. Wire fields are narrowed via the contracts
|
|
415
|
+
* guards (no `as`).
|
|
416
|
+
* - **Observable (§13).** The owned `emitter` fires `connect` / `disconnect` /
|
|
417
|
+
* `notification` / `error`; the emitter isolates a listener throw and routes it to its
|
|
418
|
+
* `error` handler (the `error` option), so a listener throw can never escape.
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```ts
|
|
422
|
+
* const client = new MCPClient({ transport, name: 'agent', version: '1.0.0' })
|
|
423
|
+
* await client.connect()
|
|
424
|
+
* const tools = await client.tools()
|
|
425
|
+
* agent.context.tools.add(tools) // the remote tools are now the agent's
|
|
426
|
+
* const value = await client.call('search', { query: 'mcp' })
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
export declare class MCPClient implements MCPClientInterface {
|
|
430
|
+
#private;
|
|
431
|
+
constructor(options: MCPClientOptions);
|
|
432
|
+
get emitter(): EmitterInterface<MCPClientEventMap>;
|
|
433
|
+
get connected(): boolean;
|
|
434
|
+
get transport(): ClientTransportInterface;
|
|
435
|
+
on<K extends keyof MCPClientEventMap>(event: K, handler: (...args: MCPClientEventMap[K]) => void): void;
|
|
436
|
+
connect(): Promise<void>;
|
|
437
|
+
disconnect(): Promise<void>;
|
|
438
|
+
tools(): Promise<readonly ToolInterface[]>;
|
|
439
|
+
call(name: string, args: Readonly<Record<string, unknown>>): Promise<unknown>;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* The push observation surface (§13) of an {@link MCPClientInterface} — the moments a
|
|
444
|
+
* fire-and-forget observer (logging, tracing) subscribes to via `client.emitter.on`.
|
|
445
|
+
*
|
|
446
|
+
* @remarks
|
|
447
|
+
* - `connect` — the `initialize` handshake completed (the client is connected).
|
|
448
|
+
* - `disconnect` — the client disconnected (every pending request rejected, the
|
|
449
|
+
* transport closed).
|
|
450
|
+
* - `notification` — a server-initiated JSON-RPC NOTIFICATION arrived (a `message`
|
|
451
|
+
* that is not a response to a pending request) — forwarded for the consumer to
|
|
452
|
+
* react to (e.g. a `notifications/tools/list_changed`).
|
|
453
|
+
* - `error` — a client-level fault surfaced for observation (typed `unknown`, §13). This is
|
|
454
|
+
* a DOMAIN event, distinct from the emitter's own listener-error channel: a listener throw
|
|
455
|
+
* is routed to the emitter's `error` handler (the `error` option), never onto this map.
|
|
456
|
+
* Declared as a `type` alias (§4.5) so the literal satisfies `EventMap`.
|
|
457
|
+
*/
|
|
458
|
+
export declare type MCPClientEventMap = {
|
|
459
|
+
/** The `initialize` handshake completed — the client is connected. */
|
|
460
|
+
readonly connect: readonly [];
|
|
461
|
+
/** The client disconnected — pending requests rejected, the transport closed. */
|
|
462
|
+
readonly disconnect: readonly [];
|
|
463
|
+
/** A server-initiated notification arrived (not a response to a pending request). */
|
|
464
|
+
readonly notification: readonly [message: JSONRPCMessage];
|
|
465
|
+
/** A client-level fault surfaced for observation (typed `unknown`, §13). */
|
|
466
|
+
readonly error: readonly [error: unknown];
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* A transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE MCP
|
|
471
|
+
* server over an injected {@link ClientTransportInterface}, performs the
|
|
472
|
+
* `initialize` handshake, and exposes the server's tools as local
|
|
473
|
+
* {@link ToolInterface}s an agent can run.
|
|
474
|
+
*
|
|
475
|
+
* @remarks
|
|
476
|
+
* - **The mirror of {@link MCPServerInterface}.** Where the server DISPATCHES requests
|
|
477
|
+
* over a tool registry, the client ISSUES them over a transport: `connect` runs the
|
|
478
|
+
* `initialize` handshake (then sends `notifications/initialized`); `tools()` lists
|
|
479
|
+
* the remote tools and wraps each as a local {@link ToolInterface} whose `execute`
|
|
480
|
+
* calls back through `call`; `call(name, args)` runs a remote `tools/call` and
|
|
481
|
+
* returns the tool's value (a remote tool FAILURE — `isError: true` — throws locally,
|
|
482
|
+
* so the agent's {@link ToolManagerInterface} isolates it into a result `error` just
|
|
483
|
+
* like a local throw).
|
|
484
|
+
* - **Request↔response correlation.** Every request is tagged with a monotonic numeric
|
|
485
|
+
* `id`; the client subscribes to the transport's `message` event and resolves /
|
|
486
|
+
* rejects the matching pending request by that `id`. A message that is NOT a response
|
|
487
|
+
* to a pending request is a server NOTIFICATION — surfaced on `notification`.
|
|
488
|
+
* - **Per-request deadline.** Each request races an `AbortSignal.timeout(timeout)`
|
|
489
|
+
* deadline: a server that never replies REJECTS the pending request once the
|
|
490
|
+
* deadline fires, never hanging.
|
|
491
|
+
* - **Transport-agnostic.** Imports only core siblings — JSON-RPC + the tool vocabulary
|
|
492
|
+
* + the timeout primitive — with no HTTP and no model; the concrete transport is
|
|
493
|
+
* injected. Wire fields are narrowed via the contracts guards (no `as`).
|
|
494
|
+
* - **Observable (§13).** The owned `emitter` fires `connect` / `disconnect` /
|
|
495
|
+
* `notification` / `error`; the emitter isolates a listener throw and routes it to its
|
|
496
|
+
* `error` handler (the `error` option, §13), never the client.
|
|
497
|
+
*/
|
|
498
|
+
export declare interface MCPClientInterface {
|
|
499
|
+
readonly emitter: EmitterInterface<MCPClientEventMap>;
|
|
500
|
+
/** Whether the `initialize` handshake has completed and the client is connected. */
|
|
501
|
+
readonly connected: boolean;
|
|
502
|
+
/** The injected transport the client drives the remote server over. */
|
|
503
|
+
readonly transport: ClientTransportInterface;
|
|
504
|
+
/**
|
|
505
|
+
* Subscribe a listener to one of the client's {@link MCPClientEventMap} events —
|
|
506
|
+
* the convenience forward to `emitter.on` (§13).
|
|
507
|
+
*
|
|
508
|
+
* @param event - The event name to subscribe to
|
|
509
|
+
* @param handler - The listener for that event's argument tuple
|
|
510
|
+
*/
|
|
511
|
+
on<K extends keyof MCPClientEventMap>(event: K, handler: (...args: MCPClientEventMap[K]) => void): void;
|
|
512
|
+
/**
|
|
513
|
+
* Connect to the remote server — open the transport and run the `initialize`
|
|
514
|
+
* handshake (then send `notifications/initialized`).
|
|
515
|
+
*
|
|
516
|
+
* @remarks
|
|
517
|
+
* Idempotent — a second `connect` while already connected is a no-op. On success
|
|
518
|
+
* the `connect` event fires.
|
|
519
|
+
*
|
|
520
|
+
* @returns Resolves once the handshake completes and the client is connected
|
|
521
|
+
*/
|
|
522
|
+
connect(): Promise<void>;
|
|
523
|
+
/**
|
|
524
|
+
* Disconnect from the remote server — reject every pending request and close the
|
|
525
|
+
* transport.
|
|
526
|
+
*
|
|
527
|
+
* @remarks
|
|
528
|
+
* Idempotent — a second `disconnect` while already disconnected is a no-op. The
|
|
529
|
+
* `disconnect` event fires.
|
|
530
|
+
*
|
|
531
|
+
* @returns Resolves once the transport is closed
|
|
532
|
+
*/
|
|
533
|
+
disconnect(): Promise<void>;
|
|
534
|
+
/**
|
|
535
|
+
* List the remote server's tools, each wrapped as a local {@link ToolInterface}
|
|
536
|
+
* whose `execute` runs the remote `tools/call` via {@link call}.
|
|
537
|
+
*
|
|
538
|
+
* @remarks
|
|
539
|
+
* Runs `tools/list` and maps each descriptor: `name` (narrowed to a string),
|
|
540
|
+
* `description`, and `inputSchema` → `parameters` (the inverse of the server's
|
|
541
|
+
* `parameters` → `inputSchema` rename). Add the returned tools to an agent's
|
|
542
|
+
* {@link ToolManagerInterface} to give it the remote tools.
|
|
543
|
+
*
|
|
544
|
+
* @returns The remote tools as local {@link ToolInterface}s, in server order
|
|
545
|
+
*/
|
|
546
|
+
tools(): Promise<readonly ToolInterface[]>;
|
|
547
|
+
/**
|
|
548
|
+
* Call a remote tool by name and return its value — runs `tools/call`, concats the
|
|
549
|
+
* result's `text` content blocks, and either parses the JSON value or throws.
|
|
550
|
+
*
|
|
551
|
+
* @remarks
|
|
552
|
+
* The inverse of the server's `buildToolResult`: a SUCCESS parses the concatenated
|
|
553
|
+
* `text` as JSON (falling back to the raw string when it is not JSON); a remote tool
|
|
554
|
+
* FAILURE (`isError: true`) THROWS an `Error` carrying the error text — so an agent's
|
|
555
|
+
* {@link ToolManagerInterface} isolates the remote failure into a result `error`
|
|
556
|
+
* exactly as it would a local tool throw.
|
|
557
|
+
*
|
|
558
|
+
* @param name - The remote tool's name
|
|
559
|
+
* @param args - The arguments record forwarded as the call's `arguments`
|
|
560
|
+
* @returns The remote tool's value (parsed JSON, or the raw text)
|
|
561
|
+
*/
|
|
562
|
+
call(name: string, args: Readonly<Record<string, unknown>>): Promise<unknown>;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Options for `createMCPClient` — the {@link ClientTransportInterface} to drive, the
|
|
567
|
+
* client identity (`name` / `version`), the per-request `timeout`, and the reserved
|
|
568
|
+
* `on` hooks (§8).
|
|
569
|
+
*
|
|
570
|
+
* @remarks
|
|
571
|
+
* - `transport` — the carrier the client drives a remote MCP server over (REQUIRED;
|
|
572
|
+
* a concrete one from `src/server/mcp`, or an in-process loopback).
|
|
573
|
+
* - `name` / `version` — identify the client in the `initialize` handshake
|
|
574
|
+
* (`clientInfo`); default to {@link import('./constants.js').DEFAULT_MCP_CLIENT_NAME}
|
|
575
|
+
* / {@link import('./constants.js').DEFAULT_MCP_CLIENT_VERSION}.
|
|
576
|
+
* - `timeout` — the per-request deadline in milliseconds: a `tools/list` / `tools/call`
|
|
577
|
+
* / `initialize` that the server does not answer within it REJECTS (the pending
|
|
578
|
+
* request is settled by an `AbortSignal.timeout(timeout)` deadline — never a raw
|
|
579
|
+
* `setTimeout`). Defaults to {@link
|
|
580
|
+
* import('./constants.js').DEFAULT_MCP_REQUEST_TIMEOUT}.
|
|
581
|
+
* - `on` — the §8 reserved key: initial listeners for the client's
|
|
582
|
+
* {@link MCPClientEventMap}, wired at construction.
|
|
583
|
+
*/
|
|
584
|
+
export declare interface MCPClientOptions {
|
|
585
|
+
readonly on?: EmitterHooks<MCPClientEventMap>;
|
|
586
|
+
/** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
|
|
587
|
+
readonly error?: EmitterErrorHandler;
|
|
588
|
+
readonly transport: ClientTransportInterface;
|
|
589
|
+
readonly name?: string;
|
|
590
|
+
readonly version?: string;
|
|
591
|
+
/** The per-request deadline in milliseconds (default {@link import('./constants.js').DEFAULT_MCP_REQUEST_TIMEOUT}). */
|
|
592
|
+
readonly timeout?: number;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** One content item of an MCP {@link MCPToolResult} — a `text` block carrying the tool's output. */
|
|
596
|
+
export declare interface MCPContent {
|
|
597
|
+
readonly type: 'text';
|
|
598
|
+
readonly text: string;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0
|
|
603
|
+
* requests over a live {@link ToolManagerInterface}, with NO transport coupling.
|
|
604
|
+
*
|
|
605
|
+
* @remarks
|
|
606
|
+
* - **Two entry points.** `dispatch(request)` runs an already-parsed request and
|
|
607
|
+
* resolves a {@link JSONRPCResponse} — or `undefined` for a NOTIFICATION (a
|
|
608
|
+
* request with no `id`). `handle(message)` is the string boundary: it
|
|
609
|
+
* `JSON.parse`s the raw message (a failure → a `-32700` response), narrows it to
|
|
610
|
+
* a request (a non-request → a `-32600` response), dispatches, and serializes the
|
|
611
|
+
* response back to a string (`undefined` for a notification).
|
|
612
|
+
* - **The method switch.** `initialize` negotiates the protocol version + advertises
|
|
613
|
+
* the tools capability; `notifications/initialized` is a notification (no
|
|
614
|
+
* response); `ping` returns `{}`; `tools/list` lists the registry's tools (its
|
|
615
|
+
* `parameters` renamed to `inputSchema`); `tools/call` runs a tool by name (the
|
|
616
|
+
* {@link ToolManagerInterface} isolates a tool throw into the result `error`, which
|
|
617
|
+
* maps to an `isError: true` tool result — so the server adds NO try/catch). An
|
|
618
|
+
* unknown method → `-32601`; a `tools/call` with a missing / non-string `name` →
|
|
619
|
+
* `-32602`.
|
|
620
|
+
* - **Provider-agnostic.** Imports only core siblings — JSON-RPC + the tool registry,
|
|
621
|
+
* no HTTP, no model. Wire fields are narrowed via the contracts guards (no `as`).
|
|
622
|
+
* - **Observable (§13).** The owned `emitter` fires `request` at the top of every
|
|
623
|
+
* dispatch; the emitter isolates a listener throw and routes it to its `error` handler
|
|
624
|
+
* (the `error` option), so a listener throw can never escape the dispatch.
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```ts
|
|
628
|
+
* const tools = createToolManager()
|
|
629
|
+
* tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))
|
|
630
|
+
* const server = new MCPServer({ name: 'demo', version: '1.0.0', tools })
|
|
631
|
+
* await server.handle('{"jsonrpc":"2.0","method":"ping","id":1}') // '{"jsonrpc":"2.0","id":1,"result":{}}'
|
|
632
|
+
* ```
|
|
633
|
+
*/
|
|
634
|
+
export declare class MCPServer implements MCPServerInterface {
|
|
635
|
+
#private;
|
|
636
|
+
constructor(options: MCPServerOptions);
|
|
637
|
+
get emitter(): EmitterInterface<MCPServerEventMap>;
|
|
638
|
+
get name(): string;
|
|
639
|
+
get version(): string;
|
|
640
|
+
dispatch(request: JSONRPCRequest): Promise<JSONRPCResponse | undefined>;
|
|
641
|
+
handle(message: string): Promise<string | undefined>;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* The push observation surface (§13) of an {@link MCPServerInterface} — the
|
|
646
|
+
* dispatch moments a fire-and-forget observer (logging, tracing) subscribes to
|
|
647
|
+
* via `server.emitter.on`.
|
|
648
|
+
*
|
|
649
|
+
* @remarks
|
|
650
|
+
* `request` fires at the TOP of every `dispatch` with the method and the
|
|
651
|
+
* correlating id (`null` for a notification), BEFORE the method runs — so an
|
|
652
|
+
* observer sees every inbound call. Listener isolation is the emitter's (§13): a
|
|
653
|
+
* listener throw is routed to the emitter's `error` handler (the `error` option),
|
|
654
|
+
* never onto this map, so a buggy observer can never corrupt a dispatch. Declared as
|
|
655
|
+
* a `type` alias (§4.5) so the type-literal satisfies `EventMap` structurally.
|
|
656
|
+
*/
|
|
657
|
+
export declare type MCPServerEventMap = {
|
|
658
|
+
/** A request is being dispatched — its `method` and correlating `id` (`null` for a notification). */
|
|
659
|
+
readonly request: readonly [method: string, id: string | number | null];
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
/** The server identity echoed in the MCP `initialize` result's `serverInfo`. */
|
|
663
|
+
export declare interface MCPServerInfo {
|
|
664
|
+
readonly name: string;
|
|
665
|
+
readonly version: string;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0
|
|
670
|
+
* requests (`initialize` / `ping` / `tools/list` / `tools/call`) over a live
|
|
671
|
+
* {@link ToolManagerInterface}, with NO transport coupling (a transport layer
|
|
672
|
+
* pumps strings through `handle`).
|
|
673
|
+
*
|
|
674
|
+
* @remarks
|
|
675
|
+
* - **Two entry points.** `dispatch(request)` is the TYPED core: it takes an
|
|
676
|
+
* already-parsed {@link JSONRPCRequest}, runs the method, and resolves a
|
|
677
|
+
* {@link JSONRPCResponse} — or `undefined` for a NOTIFICATION (a request with no
|
|
678
|
+
* `id`). `handle(message)` is the STRING boundary: it `JSON.parse`s the raw
|
|
679
|
+
* message, narrows it to a request, dispatches, and serializes the response back
|
|
680
|
+
* to a string — turning a parse failure into a `-32700` response and a non-request
|
|
681
|
+
* into a `-32600` response, and returning `undefined` for a notification.
|
|
682
|
+
* - **Provider-agnostic.** Imports only core siblings; it speaks JSON-RPC + the
|
|
683
|
+
* tool registry, with no HTTP, no model, and no backend coupling.
|
|
684
|
+
* - **Observable (§13).** The owned `emitter` ({@link MCPServerEventMap}) fires
|
|
685
|
+
* `request` per dispatch; the emitter isolates a listener throw and routes it to its
|
|
686
|
+
* `error` handler (the `error` option, §13), never the dispatch.
|
|
687
|
+
*/
|
|
688
|
+
export declare interface MCPServerInterface {
|
|
689
|
+
readonly emitter: EmitterInterface<MCPServerEventMap>;
|
|
690
|
+
readonly name: string;
|
|
691
|
+
readonly version: string;
|
|
692
|
+
/**
|
|
693
|
+
* Dispatch an already-parsed request — run its method and resolve the response,
|
|
694
|
+
* or `undefined` for a notification (a request with no `id`).
|
|
695
|
+
*
|
|
696
|
+
* @param request - The parsed JSON-RPC request to dispatch
|
|
697
|
+
* @returns The response, or `undefined` when the request was a notification
|
|
698
|
+
*/
|
|
699
|
+
dispatch(request: JSONRPCRequest): Promise<JSONRPCResponse | undefined>;
|
|
700
|
+
/**
|
|
701
|
+
* Handle a raw message string — parse it, dispatch, and serialize the response.
|
|
702
|
+
*
|
|
703
|
+
* @remarks
|
|
704
|
+
* A `JSON.parse` failure resolves a serialized `-32700` (Parse error) response;
|
|
705
|
+
* a parsed value that is not a valid request resolves a serialized `-32600`
|
|
706
|
+
* (Invalid Request) response; a notification resolves `undefined` (no response).
|
|
707
|
+
*
|
|
708
|
+
* @param message - The raw JSON-RPC message string
|
|
709
|
+
* @returns The serialized response string, or `undefined` for a notification
|
|
710
|
+
*/
|
|
711
|
+
handle(message: string): Promise<string | undefined>;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Options for `createMCPServer` — the server identity (`name` / `version`), the
|
|
716
|
+
* live {@link ToolManagerInterface} it exposes, an optional `description`, and the
|
|
717
|
+
* reserved `on` hooks (§8).
|
|
718
|
+
*
|
|
719
|
+
* @remarks
|
|
720
|
+
* `name` / `version` identify the server in the `initialize` handshake
|
|
721
|
+
* (`serverInfo`). `tools` is the live registry the server dispatches `tools/list`
|
|
722
|
+
* / `tools/call` over — its `definitions()` advertise the tools and its
|
|
723
|
+
* `execute()` runs a call (the manager already isolates a tool throw into a
|
|
724
|
+
* result `error`, so the server adds none). `description` is a human label for
|
|
725
|
+
* the server (reserved for a future `instructions` capability — unused by the
|
|
726
|
+
* current dispatch). `on` is the §8 reserved key: initial listeners for the
|
|
727
|
+
* server's {@link MCPServerEventMap}, wired at construction.
|
|
728
|
+
*/
|
|
729
|
+
export declare interface MCPServerOptions {
|
|
730
|
+
readonly on?: EmitterHooks<MCPServerEventMap>;
|
|
731
|
+
/** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
|
|
732
|
+
readonly error?: EmitterErrorHandler;
|
|
733
|
+
readonly name: string;
|
|
734
|
+
readonly version: string;
|
|
735
|
+
/** The live tool registry the server exposes over `tools/list` / `tools/call`. */
|
|
736
|
+
readonly tools: ToolManagerInterface;
|
|
737
|
+
/** A human label for the server (reserved for a future capability; unused by dispatch). */
|
|
738
|
+
readonly description?: string;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* One entry of the MCP `tools/list` result — a tool's `name`, optional
|
|
743
|
+
* `description`, and its JSON-Schema `inputSchema`.
|
|
744
|
+
*
|
|
745
|
+
* @remarks
|
|
746
|
+
* The wire renaming of a `ToolDefinition`: `name` / `description` carry through,
|
|
747
|
+
* and `parameters` becomes `inputSchema` (the MCP field name), defaulting to an
|
|
748
|
+
* empty object schema (`{ type: 'object' }`) when a tool declares none.
|
|
749
|
+
*/
|
|
750
|
+
export declare interface MCPToolDescriptor {
|
|
751
|
+
readonly name: string;
|
|
752
|
+
readonly description?: string;
|
|
753
|
+
readonly inputSchema: Readonly<Record<string, unknown>>;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* The MCP `tools/call` result — the executed tool's output as `content` blocks,
|
|
758
|
+
* with `isError` flagging a tool failure.
|
|
759
|
+
*
|
|
760
|
+
* @remarks
|
|
761
|
+
* A success carries the tool's value serialized into one `text` content block; a
|
|
762
|
+
* tool FAILURE (the `ToolResult.error` the registry isolated) carries the error
|
|
763
|
+
* text in `content` AND sets `isError: true`, so the model sees the failure as a
|
|
764
|
+
* tool result it can react to rather than a protocol error.
|
|
765
|
+
*/
|
|
766
|
+
export declare interface MCPToolResult {
|
|
767
|
+
readonly content: readonly MCPContent[];
|
|
768
|
+
/** `true` when the tool failed — its error text is in `content`. */
|
|
769
|
+
readonly isError?: boolean;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Narrow an already-parsed value to a {@link JSONRPCMessage}, or `undefined` when
|
|
774
|
+
* it is not one.
|
|
775
|
+
*
|
|
776
|
+
* @remarks
|
|
777
|
+
* Total (§14) — a non-message returns `undefined`, never throws. The input must
|
|
778
|
+
* ALREADY be `JSON.parse`d: the raw-string parse (which can throw on malformed
|
|
779
|
+
* JSON) happens in `MCPServer.handle` inside a try/catch that maps a parse failure
|
|
780
|
+
* to a `-32700` response. Sound with {@link isJSONRPCMessage}: a guard-valid input
|
|
781
|
+
* is returned unchanged, and every non-`undefined` output satisfies the guard.
|
|
782
|
+
*
|
|
783
|
+
* @param value - The already-parsed value to narrow
|
|
784
|
+
* @returns The value as a {@link JSONRPCMessage}, or `undefined`
|
|
785
|
+
*
|
|
786
|
+
* @example
|
|
787
|
+
* ```ts
|
|
788
|
+
* parseJSONRPCMessage({ jsonrpc: '2.0', method: 'ping', id: 1 }) // the request
|
|
789
|
+
* parseJSONRPCMessage({ method: 'ping' }) // undefined — missing jsonrpc
|
|
790
|
+
* ```
|
|
791
|
+
*/
|
|
792
|
+
export declare function parseJSONRPCMessage(value: unknown): JSONRPCMessage | undefined;
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* The MCP protocol revisions this server can negotiate — the current
|
|
796
|
+
* {@link MCP_PROTOCOL_VERSION} plus a prior rev a client may still request.
|
|
797
|
+
*
|
|
798
|
+
* @remarks
|
|
799
|
+
* `initialize` echoes the client's requested `protocolVersion` when it appears in
|
|
800
|
+
* this list, else falls back to {@link MCP_PROTOCOL_VERSION}. Frozen so the list is
|
|
801
|
+
* an immutable contract.
|
|
802
|
+
*/
|
|
803
|
+
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
|
|
804
|
+
|
|
805
|
+
export { }
|