@orkestrel/mcp 0.0.20 → 0.0.22
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/server/index.cjs +111 -41
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +158 -20
- package/dist/src/server/index.d.ts +158 -20
- package/dist/src/server/index.js +111 -42
- package/dist/src/server/index.js.map +1 -1
- package/package.json +16 -14
package/dist/src/server/index.js
CHANGED
|
@@ -84,6 +84,18 @@ var DEFAULT_MCP_SESSION_CAPACITY = 1024;
|
|
|
84
84
|
* this bounds the replay log paired with it.
|
|
85
85
|
*/
|
|
86
86
|
var DEFAULT_MCP_SESSION_TTL = 3e5;
|
|
87
|
+
/**
|
|
88
|
+
* The default bound in milliseconds on one unconfirmed write to a stdio client transport's
|
|
89
|
+
* child `stdin` — the `delivery` a `createStdioClientTransport` caller who supplies none gets.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* Ten seconds. The load-bearing property is the ordering, not the magnitude: this bound stays
|
|
93
|
+
* BELOW {@link import('@orkestrel/mcp').DEFAULT_MCP_REQUEST_TIMEOUT}, so a write the child never
|
|
94
|
+
* reads fails as an undeliverable message while the request that carried it is still open,
|
|
95
|
+
* rather than being masked by that request's own deadline expiring first. Override per
|
|
96
|
+
* transport with `delivery`; an explicit `0` there removes the bound.
|
|
97
|
+
*/
|
|
98
|
+
var DEFAULT_MCP_DELIVERY = 1e4;
|
|
87
99
|
//#endregion
|
|
88
100
|
//#region src/server/helpers.ts
|
|
89
101
|
/**
|
|
@@ -1362,7 +1374,7 @@ var WebSocketClientTransport = class {
|
|
|
1362
1374
|
//#region src/server/transports/StdioClientTransport.ts
|
|
1363
1375
|
/**
|
|
1364
1376
|
* The stdio CLIENT transport for the Model Context Protocol — a
|
|
1365
|
-
* {@link
|
|
1377
|
+
* {@link StdioClientTransportInterface} that drives a CHILD PROCESS MCP server over
|
|
1366
1378
|
* newline-delimited JSON-RPC on `stdin`/`stdout`, the stdio sibling of {@link
|
|
1367
1379
|
* import('./HTTPClientTransport.js').HTTPClientTransport} and {@link
|
|
1368
1380
|
* import('./WebSocketClientTransport.js').WebSocketClientTransport}.
|
|
@@ -1380,19 +1392,36 @@ var WebSocketClientTransport = class {
|
|
|
1380
1392
|
* - **Outbound (`send`).** `send(message)` writes one newline-terminated `JSON.stringify`d line
|
|
1381
1393
|
* through the supervisor's `send` and AWAITS its answer, so this promise settles only after the
|
|
1382
1394
|
* host reports the line handled rather than the moment the write is queued. The supervisor never
|
|
1383
|
-
* rejects — it answers `false` for a channel that was closed, destroyed, or ended,
|
|
1384
|
-
* that failed
|
|
1385
|
-
*
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1391
|
-
* the
|
|
1395
|
+
* rejects — it answers `false` for a channel that was closed, destroyed, or ended, for a write
|
|
1396
|
+
* that failed, or for one that remained unconfirmed through `delivery`. A call made without a
|
|
1397
|
+
* live child rejects as not connected; a `false` answer from a live child rejects as unable to
|
|
1398
|
+
* deliver. The supervisor does not disclose which cause produced that answer.
|
|
1399
|
+
* - **`close()`** runs the supervisor's bounded termination and teardown, then fires `close` once
|
|
1400
|
+
* (idempotent). That teardown reaches the child's TERMINAL MOMENT, where the supervisor freezes
|
|
1401
|
+
* `evidence`, ends `lines`, and settles `exit` together, so this transport needs no release of
|
|
1402
|
+
* its own to get its line pump back: the stream ends under the pump rather than throwing at it.
|
|
1403
|
+
* A line the supervisor had already framed behind the one being delivered is dropped rather than
|
|
1404
|
+
* emitted onto a transport whose teardown has begun. A `close()` issued while that teardown runs
|
|
1405
|
+
* joins it rather than opening a second one, so it resolves only after `close` has fired, and a
|
|
1406
|
+
* `start()` issued while it runs waits behind the same barrier, so lifetimes never overlap. A
|
|
1407
|
+
* descendant can retain an inherited stdout pipe after the child exits; the supervisor's `drain`
|
|
1408
|
+
* bound cuts that wait off, so this transport's `close()` settles within that bound rather than
|
|
1409
|
+
* on the descendant. The termination itself belongs to the host: a POSIX host signals the
|
|
1410
|
+
* child's own process group `SIGTERM`, waits the grace window, then `SIGKILL`s through the same
|
|
1411
|
+
* route, so the kill reaches grandchildren rather than orphaning them, while Windows ends the
|
|
1412
|
+
* tree with `taskkill /F /T`, which nothing in the child can intercept.
|
|
1413
|
+
* - **Evidence.** `evidence` reports that retained stderr tail off the HELD child — its live tail
|
|
1414
|
+
* while the child runs, and the value the supervisor froze at that child's terminal moment
|
|
1415
|
+
* afterwards. The reference is held past that moment and replaced only by the next `start()`,
|
|
1416
|
+
* which is what keeps a post-`close()` read stable without a private copy: the frozen value
|
|
1417
|
+
* never moves again, so a detached descendant writing to the inherited stderr after the cutoff
|
|
1418
|
+
* cannot grow it. See {@link StdioClientTransportInterface.evidence} for the readings and the
|
|
1419
|
+
* byte bound.
|
|
1392
1420
|
* - **Observable.** Owns the `emitter` ({@link MCPClientTransportEventMap}); the
|
|
1393
1421
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1394
|
-
* fault, including the child spawn cause the supervisor surfaces
|
|
1395
|
-
*
|
|
1422
|
+
* fault, including the child spawn cause the supervisor surfaces and the notice that this
|
|
1423
|
+
* lifetime's `evidence` was cut off at the `drain` bound), distinct from the emitter's own
|
|
1424
|
+
* listener-error channel.
|
|
1396
1425
|
*
|
|
1397
1426
|
* @example
|
|
1398
1427
|
* ```ts
|
|
@@ -1406,15 +1435,16 @@ var StdioClientTransport = class {
|
|
|
1406
1435
|
#command;
|
|
1407
1436
|
#args;
|
|
1408
1437
|
#env;
|
|
1438
|
+
#delivery;
|
|
1409
1439
|
#process = void 0;
|
|
1410
|
-
#
|
|
1411
|
-
#pumping = Promise.resolve();
|
|
1440
|
+
#closing = void 0;
|
|
1412
1441
|
#closed = false;
|
|
1413
1442
|
constructor(options) {
|
|
1414
1443
|
this.#emitter = new Emitter();
|
|
1415
1444
|
this.#command = options.command;
|
|
1416
1445
|
this.#args = options.args ?? [];
|
|
1417
1446
|
this.#env = options.env;
|
|
1447
|
+
this.#delivery = options.delivery ?? 1e4;
|
|
1418
1448
|
}
|
|
1419
1449
|
get emitter() {
|
|
1420
1450
|
return this.#emitter;
|
|
@@ -1423,10 +1453,21 @@ var StdioClientTransport = class {
|
|
|
1423
1453
|
get duplex() {
|
|
1424
1454
|
return true;
|
|
1425
1455
|
}
|
|
1456
|
+
get evidence() {
|
|
1457
|
+
return this.#process?.evidence;
|
|
1458
|
+
}
|
|
1426
1459
|
async start() {
|
|
1427
|
-
|
|
1460
|
+
let closing = this.#closing;
|
|
1461
|
+
while (closing !== void 0) {
|
|
1462
|
+
await closing;
|
|
1463
|
+
if (this.#closing === closing) {
|
|
1464
|
+
this.#closing = void 0;
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
closing = this.#closing;
|
|
1468
|
+
}
|
|
1469
|
+
if (this.#process !== void 0 && !this.#closed) return;
|
|
1428
1470
|
this.#closed = false;
|
|
1429
|
-
this.#release = Promise.withResolvers();
|
|
1430
1471
|
const child = new Process({
|
|
1431
1472
|
command: {
|
|
1432
1473
|
file: this.#command,
|
|
@@ -1435,43 +1476,65 @@ var StdioClientTransport = class {
|
|
|
1435
1476
|
},
|
|
1436
1477
|
workspace: process.cwd(),
|
|
1437
1478
|
grace: PROCESS_GRACE,
|
|
1479
|
+
delivery: this.#delivery,
|
|
1438
1480
|
writable: true
|
|
1439
1481
|
});
|
|
1440
1482
|
this.#process = child;
|
|
1441
1483
|
child.emitter.on("error", (cause) => this.#emitter.emit("error", cause));
|
|
1442
|
-
child.exit.then(() => this.#onExit(child));
|
|
1443
|
-
this.#
|
|
1484
|
+
child.exit.then((exit) => this.#onExit(child, exit));
|
|
1485
|
+
this.#pump(child);
|
|
1444
1486
|
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Sends one newline-delimited JSON-RPC message to the live child.
|
|
1489
|
+
*
|
|
1490
|
+
* @param message - The message to write to the child's `stdin`
|
|
1491
|
+
* @returns Resolves when the supervisor confirms the write
|
|
1492
|
+
* @throws Thrown with `stdio transport is not connected` when no live child is available before
|
|
1493
|
+
* the write
|
|
1494
|
+
* @throws Thrown with `stdio transport could not deliver the message` when a live child's write
|
|
1495
|
+
* resolves `false`
|
|
1496
|
+
*/
|
|
1445
1497
|
async send(message) {
|
|
1446
|
-
const child = this.#process;
|
|
1447
|
-
if (
|
|
1498
|
+
const child = this.#closed ? void 0 : this.#process;
|
|
1499
|
+
if (child === void 0) throw new Error("stdio transport is not connected");
|
|
1500
|
+
if (!await child.send(JSON.stringify(message))) throw new Error("stdio transport could not deliver the message");
|
|
1448
1501
|
}
|
|
1449
1502
|
async close() {
|
|
1503
|
+
if (this.#closed && this.#closing === void 0) return;
|
|
1504
|
+
this.#closing ??= this.#teardown();
|
|
1505
|
+
await this.#closing;
|
|
1506
|
+
}
|
|
1507
|
+
async #teardown() {
|
|
1450
1508
|
if (this.#closed) return;
|
|
1451
1509
|
this.#closed = true;
|
|
1452
1510
|
const child = this.#process;
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
await pumping;
|
|
1511
|
+
if (child !== void 0) {
|
|
1512
|
+
await child.destroy();
|
|
1513
|
+
this.#report(await child.exit);
|
|
1514
|
+
}
|
|
1458
1515
|
this.#emitter.emit("close");
|
|
1459
1516
|
}
|
|
1460
|
-
async #pump(child
|
|
1461
|
-
const
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
if (next === void 0 || next.done) return;
|
|
1465
|
-
if (this.#process !== child) return;
|
|
1466
|
-
dispatchLines(this.#emitter, [next.value]);
|
|
1517
|
+
async #pump(child) {
|
|
1518
|
+
for await (const line of child.lines) {
|
|
1519
|
+
if (this.#closed || this.#process !== child) return;
|
|
1520
|
+
dispatchLines(this.#emitter, [line]);
|
|
1467
1521
|
}
|
|
1468
1522
|
}
|
|
1469
|
-
#onExit(child) {
|
|
1470
|
-
if (this.#
|
|
1523
|
+
#onExit(child, exit) {
|
|
1524
|
+
if (this.#process !== child) return;
|
|
1525
|
+
if (this.#closed) return;
|
|
1471
1526
|
this.#closed = true;
|
|
1472
|
-
|
|
1527
|
+
const barrier = Promise.withResolvers();
|
|
1528
|
+
this.#closing ??= barrier.promise;
|
|
1529
|
+
this.#report(exit);
|
|
1530
|
+
barrier.resolve();
|
|
1531
|
+
if (this.#closing === barrier.promise) this.#closing = void 0;
|
|
1473
1532
|
this.#emitter.emit("close");
|
|
1474
1533
|
}
|
|
1534
|
+
#report(exit) {
|
|
1535
|
+
if (exit.drained) return;
|
|
1536
|
+
this.#emitter.emit("error", /* @__PURE__ */ new Error("stdio transport evidence may be incomplete: the child streams stayed open past the supervisor drain bound"));
|
|
1537
|
+
}
|
|
1475
1538
|
};
|
|
1476
1539
|
//#endregion
|
|
1477
1540
|
//#region src/server/transports/StdioServerTransport.ts
|
|
@@ -1816,22 +1879,28 @@ function createWebSocketClientTransport(options) {
|
|
|
1816
1879
|
}
|
|
1817
1880
|
/**
|
|
1818
1881
|
* Creates the stdio CLIENT transport for an {@link import('@orkestrel/mcp').MCPClientInterface}
|
|
1819
|
-
* — a {@link
|
|
1882
|
+
* — a {@link StdioClientTransportInterface} that spawns and drives a CHILD PROCESS MCP server
|
|
1820
1883
|
* over newline-delimited JSON-RPC on `stdin`/`stdout`, the stdio sibling of {@link
|
|
1821
1884
|
* createHTTPClientTransport} and {@link createWebSocketClientTransport}.
|
|
1822
1885
|
*
|
|
1823
1886
|
* @remarks
|
|
1824
1887
|
* Hand it to `createMCPClient({ transport })`: `start()` (run by `client.connect()`)
|
|
1825
1888
|
* spawns `options.command` with `options.args` and `options.env`, piping its
|
|
1826
|
-
* `stdin`/`stdout` for the JSON-RPC channel
|
|
1827
|
-
*
|
|
1889
|
+
* `stdin`/`stdout` for the JSON-RPC channel. The child's `stderr` is piped too, and
|
|
1890
|
+
* retained as a bounded tail this transport reports as `evidence` — the parent never
|
|
1891
|
+
* inherits it. Each JSON-RPC message the client `send`s is written as one
|
|
1828
1892
|
* newline-terminated line to the child's `stdin`; each decoded reply line from the
|
|
1829
1893
|
* child's `stdout` is surfaced on the transport's `message` event for the client's
|
|
1830
|
-
* id correlation.
|
|
1894
|
+
* id correlation. That write is bounded: a child that stays alive without ever reading
|
|
1895
|
+
* its `stdin` fills the pipe, and `options.delivery` is how long the unconfirmed write
|
|
1896
|
+
* waits before the `send` rejects. An omitted `delivery` selects {@link
|
|
1897
|
+
* import('./constants.js').DEFAULT_MCP_DELIVERY}; an explicit `0` removes the bound.
|
|
1831
1898
|
*
|
|
1832
1899
|
* @param options - `command` (the executable to spawn; REQUIRED), optional `args`,
|
|
1833
|
-
* and optional `
|
|
1834
|
-
*
|
|
1900
|
+
* optional `env`, and an optional `delivery` bound in milliseconds on an unconfirmed
|
|
1901
|
+
* `stdin` write; see {@link StdioClientTransportOptions}
|
|
1902
|
+
* @returns A working {@link StdioClientTransportInterface} over a child process's stdio,
|
|
1903
|
+
* whose `evidence` carries the supervised child's bounded stderr tail
|
|
1835
1904
|
*
|
|
1836
1905
|
* @example
|
|
1837
1906
|
* ```ts
|
|
@@ -2068,6 +2137,6 @@ function createMCPSession(options) {
|
|
|
2068
2137
|
};
|
|
2069
2138
|
}
|
|
2070
2139
|
//#endregion
|
|
2071
|
-
export { DEFAULT_MCP_KEEPALIVE_INTERVAL, DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, HTTPDisconnect, MCPSession, MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, SSE_BUFFERING_DISABLED, SSE_BUFFERING_HEADER, SSE_KEEPALIVE_COMMENT, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, allowsOrigin, bridgeMessageTransport, createHTTPClientTransport, createMCPContinuation, createMCPPostHandler, createMCPRoutes, createMCPSession, createReadableStream, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, inferHeaderIssue, inferLegacyVersion, inferStatus, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, sendEventStream, upgradeRequestPath };
|
|
2140
|
+
export { DEFAULT_MCP_DELIVERY, DEFAULT_MCP_KEEPALIVE_INTERVAL, DEFAULT_MCP_PATH, DEFAULT_MCP_SESSION_CAPACITY, DEFAULT_MCP_SESSION_TTL, HTTPClientTransport, HTTPDisconnect, MCPSession, MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER, MCP_SESSION_HEADER, MCP_WEBSOCKET_SUBPROTOCOL, SSE_BUFFERING_DISABLED, SSE_BUFFERING_HEADER, SSE_KEEPALIVE_COMMENT, StdioClientTransport, StdioServerTransport, WebSocketClientTransport, WebSocketServerTransport, acceptsEventStream, allowsOrigin, bridgeMessageTransport, createHTTPClientTransport, createMCPContinuation, createMCPPostHandler, createMCPRoutes, createMCPSession, createReadableStream, createStdioClientTransport, createStdioServer, createWebSocketClientTransport, createWebSocketServer, decodeEvent, dispatchLines, extractLines, inferHeaderIssue, inferLegacyVersion, inferStatus, readEventStream, readLastEventId, readSessionHeader, rejectUnknownSession, sendEventStream, upgradeRequestPath };
|
|
2072
2141
|
|
|
2073
2142
|
//# sourceMappingURL=index.js.map
|