@orkestrel/mcp 0.0.20 → 0.0.21
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 +73 -35
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +102 -15
- package/dist/src/server/index.d.ts +102 -15
- package/dist/src/server/index.js +73 -35
- package/dist/src/server/index.js.map +1 -1
- package/package.json +11 -9
|
@@ -1363,7 +1363,7 @@ var WebSocketClientTransport = class {
|
|
|
1363
1363
|
//#region src/server/transports/StdioClientTransport.ts
|
|
1364
1364
|
/**
|
|
1365
1365
|
* The stdio CLIENT transport for the Model Context Protocol — a
|
|
1366
|
-
* {@link
|
|
1366
|
+
* {@link StdioClientTransportInterface} that drives a CHILD PROCESS MCP server over
|
|
1367
1367
|
* newline-delimited JSON-RPC on `stdin`/`stdout`, the stdio sibling of {@link
|
|
1368
1368
|
* import('./HTTPClientTransport.js').HTTPClientTransport} and {@link
|
|
1369
1369
|
* import('./WebSocketClientTransport.js').WebSocketClientTransport}.
|
|
@@ -1384,16 +1384,32 @@ var WebSocketClientTransport = class {
|
|
|
1384
1384
|
* rejects — it answers `false` for a channel that was closed, destroyed, or ended, and for a write
|
|
1385
1385
|
* that failed — so a `false` answer REJECTS here with the same not-connected error a transport
|
|
1386
1386
|
* that was never started raises. A dead peer surfaces at the caller instead of vanishing.
|
|
1387
|
-
* - **`close()`**
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1391
|
-
*
|
|
1392
|
-
*
|
|
1387
|
+
* - **`close()`** runs the supervisor's bounded termination and teardown, then fires `close` once
|
|
1388
|
+
* (idempotent). That teardown reaches the child's TERMINAL MOMENT, where the supervisor freezes
|
|
1389
|
+
* `evidence`, ends `lines`, and settles `exit` together, so this transport needs no release of
|
|
1390
|
+
* its own to get its line pump back: the stream ends under the pump rather than throwing at it.
|
|
1391
|
+
* A line the supervisor had already framed behind the one being delivered is dropped rather than
|
|
1392
|
+
* emitted onto a transport whose teardown has begun. A `close()` issued while that teardown runs
|
|
1393
|
+
* joins it rather than opening a second one, so it resolves only after `close` has fired, and a
|
|
1394
|
+
* `start()` issued while it runs waits behind the same barrier, so lifetimes never overlap. A
|
|
1395
|
+
* descendant can retain an inherited stdout pipe after the child exits; the supervisor's `drain`
|
|
1396
|
+
* bound cuts that wait off, so this transport's `close()` settles within that bound rather than
|
|
1397
|
+
* on the descendant. The termination itself belongs to the host: a POSIX host signals the
|
|
1398
|
+
* child's own process group `SIGTERM`, waits the grace window, then `SIGKILL`s through the same
|
|
1399
|
+
* route, so the kill reaches grandchildren rather than orphaning them, while Windows ends the
|
|
1400
|
+
* tree with `taskkill /F /T`, which nothing in the child can intercept.
|
|
1401
|
+
* - **Evidence.** `evidence` reports that retained stderr tail off the HELD child — its live tail
|
|
1402
|
+
* while the child runs, and the value the supervisor froze at that child's terminal moment
|
|
1403
|
+
* afterwards. The reference is held past that moment and replaced only by the next `start()`,
|
|
1404
|
+
* which is what keeps a post-`close()` read stable without a private copy: the frozen value
|
|
1405
|
+
* never moves again, so a detached descendant writing to the inherited stderr after the cutoff
|
|
1406
|
+
* cannot grow it. See {@link StdioClientTransportInterface.evidence} for the readings and the
|
|
1407
|
+
* byte bound.
|
|
1393
1408
|
* - **Observable.** Owns the `emitter` ({@link MCPClientTransportEventMap}); the
|
|
1394
1409
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1395
|
-
* fault, including the child spawn cause the supervisor surfaces
|
|
1396
|
-
*
|
|
1410
|
+
* fault, including the child spawn cause the supervisor surfaces and the notice that this
|
|
1411
|
+
* lifetime's `evidence` was cut off at the `drain` bound), distinct from the emitter's own
|
|
1412
|
+
* listener-error channel.
|
|
1397
1413
|
*
|
|
1398
1414
|
* @example
|
|
1399
1415
|
* ```ts
|
|
@@ -1408,8 +1424,7 @@ var StdioClientTransport = class {
|
|
|
1408
1424
|
#args;
|
|
1409
1425
|
#env;
|
|
1410
1426
|
#process = void 0;
|
|
1411
|
-
#
|
|
1412
|
-
#pumping = Promise.resolve();
|
|
1427
|
+
#closing = void 0;
|
|
1413
1428
|
#closed = false;
|
|
1414
1429
|
constructor(options) {
|
|
1415
1430
|
this.#emitter = new _orkestrel_emitter.Emitter();
|
|
@@ -1424,10 +1439,21 @@ var StdioClientTransport = class {
|
|
|
1424
1439
|
get duplex() {
|
|
1425
1440
|
return true;
|
|
1426
1441
|
}
|
|
1442
|
+
get evidence() {
|
|
1443
|
+
return this.#process?.evidence;
|
|
1444
|
+
}
|
|
1427
1445
|
async start() {
|
|
1428
|
-
|
|
1446
|
+
let closing = this.#closing;
|
|
1447
|
+
while (closing !== void 0) {
|
|
1448
|
+
await closing;
|
|
1449
|
+
if (this.#closing === closing) {
|
|
1450
|
+
this.#closing = void 0;
|
|
1451
|
+
break;
|
|
1452
|
+
}
|
|
1453
|
+
closing = this.#closing;
|
|
1454
|
+
}
|
|
1455
|
+
if (this.#process !== void 0 && !this.#closed) return;
|
|
1429
1456
|
this.#closed = false;
|
|
1430
|
-
this.#release = Promise.withResolvers();
|
|
1431
1457
|
const child = new _orkestrel_process_server.Process({
|
|
1432
1458
|
command: {
|
|
1433
1459
|
file: this.#command,
|
|
@@ -1440,39 +1466,49 @@ var StdioClientTransport = class {
|
|
|
1440
1466
|
});
|
|
1441
1467
|
this.#process = child;
|
|
1442
1468
|
child.emitter.on("error", (cause) => this.#emitter.emit("error", cause));
|
|
1443
|
-
child.exit.then(() => this.#onExit(child));
|
|
1444
|
-
this.#
|
|
1469
|
+
child.exit.then((exit) => this.#onExit(child, exit));
|
|
1470
|
+
this.#pump(child);
|
|
1445
1471
|
}
|
|
1446
1472
|
async send(message) {
|
|
1447
|
-
const child = this.#process;
|
|
1473
|
+
const child = this.#closed ? void 0 : this.#process;
|
|
1448
1474
|
if (!(child === void 0 ? false : await child.send(JSON.stringify(message)))) throw new Error("stdio transport is not connected");
|
|
1449
1475
|
}
|
|
1450
1476
|
async close() {
|
|
1477
|
+
if (this.#closed && this.#closing === void 0) return;
|
|
1478
|
+
this.#closing ??= this.#teardown();
|
|
1479
|
+
await this.#closing;
|
|
1480
|
+
}
|
|
1481
|
+
async #teardown() {
|
|
1451
1482
|
if (this.#closed) return;
|
|
1452
1483
|
this.#closed = true;
|
|
1453
1484
|
const child = this.#process;
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
await pumping;
|
|
1485
|
+
if (child !== void 0) {
|
|
1486
|
+
await child.destroy();
|
|
1487
|
+
this.#report(await child.exit);
|
|
1488
|
+
}
|
|
1459
1489
|
this.#emitter.emit("close");
|
|
1460
1490
|
}
|
|
1461
|
-
async #pump(child
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
if (next === void 0 || next.done) return;
|
|
1466
|
-
if (this.#process !== child) return;
|
|
1467
|
-
dispatchLines(this.#emitter, [next.value]);
|
|
1491
|
+
async #pump(child) {
|
|
1492
|
+
for await (const line of child.lines) {
|
|
1493
|
+
if (this.#closed || this.#process !== child) return;
|
|
1494
|
+
dispatchLines(this.#emitter, [line]);
|
|
1468
1495
|
}
|
|
1469
1496
|
}
|
|
1470
|
-
#onExit(child) {
|
|
1471
|
-
if (this.#
|
|
1497
|
+
#onExit(child, exit) {
|
|
1498
|
+
if (this.#process !== child) return;
|
|
1499
|
+
if (this.#closed) return;
|
|
1472
1500
|
this.#closed = true;
|
|
1473
|
-
|
|
1501
|
+
const barrier = Promise.withResolvers();
|
|
1502
|
+
this.#closing ??= barrier.promise;
|
|
1503
|
+
this.#report(exit);
|
|
1504
|
+
barrier.resolve();
|
|
1505
|
+
if (this.#closing === barrier.promise) this.#closing = void 0;
|
|
1474
1506
|
this.#emitter.emit("close");
|
|
1475
1507
|
}
|
|
1508
|
+
#report(exit) {
|
|
1509
|
+
if (exit.drained) return;
|
|
1510
|
+
this.#emitter.emit("error", /* @__PURE__ */ new Error("stdio transport evidence may be incomplete: the child streams stayed open past the supervisor drain bound"));
|
|
1511
|
+
}
|
|
1476
1512
|
};
|
|
1477
1513
|
//#endregion
|
|
1478
1514
|
//#region src/server/transports/StdioServerTransport.ts
|
|
@@ -1817,22 +1853,24 @@ function createWebSocketClientTransport(options) {
|
|
|
1817
1853
|
}
|
|
1818
1854
|
/**
|
|
1819
1855
|
* Creates the stdio CLIENT transport for an {@link import('@orkestrel/mcp').MCPClientInterface}
|
|
1820
|
-
* — a {@link
|
|
1856
|
+
* — a {@link StdioClientTransportInterface} that spawns and drives a CHILD PROCESS MCP server
|
|
1821
1857
|
* over newline-delimited JSON-RPC on `stdin`/`stdout`, the stdio sibling of {@link
|
|
1822
1858
|
* createHTTPClientTransport} and {@link createWebSocketClientTransport}.
|
|
1823
1859
|
*
|
|
1824
1860
|
* @remarks
|
|
1825
1861
|
* Hand it to `createMCPClient({ transport })`: `start()` (run by `client.connect()`)
|
|
1826
1862
|
* spawns `options.command` with `options.args` and `options.env`, piping its
|
|
1827
|
-
* `stdin`/`stdout` for the JSON-RPC channel
|
|
1828
|
-
*
|
|
1863
|
+
* `stdin`/`stdout` for the JSON-RPC channel. The child's `stderr` is piped too, and
|
|
1864
|
+
* retained as a bounded tail this transport reports as `evidence` — the parent never
|
|
1865
|
+
* inherits it. Each JSON-RPC message the client `send`s is written as one
|
|
1829
1866
|
* newline-terminated line to the child's `stdin`; each decoded reply line from the
|
|
1830
1867
|
* child's `stdout` is surfaced on the transport's `message` event for the client's
|
|
1831
1868
|
* id correlation.
|
|
1832
1869
|
*
|
|
1833
1870
|
* @param options - `command` (the executable to spawn; REQUIRED), optional `args`,
|
|
1834
1871
|
* and optional `env`; see {@link StdioClientTransportOptions}
|
|
1835
|
-
* @returns A working {@link
|
|
1872
|
+
* @returns A working {@link StdioClientTransportInterface} over a child process's stdio,
|
|
1873
|
+
* whose `evidence` carries the supervised child's bounded stderr tail
|
|
1836
1874
|
*
|
|
1837
1875
|
* @example
|
|
1838
1876
|
* ```ts
|