@orkestrel/mcp 0.0.18 → 0.0.19
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.
|
@@ -1231,22 +1231,29 @@ export declare const SSE_KEEPALIVE_COMMENT = "keepalive";
|
|
|
1231
1231
|
* import('./WebSocketClientTransport.js').WebSocketClientTransport}.
|
|
1232
1232
|
*
|
|
1233
1233
|
* @remarks
|
|
1234
|
-
* - **
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
* - **Inbound (`message`).**
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
* {@link dispatchLines} helper — a well-formed
|
|
1242
|
-
* `message`, a malformed line emits `error` (§14, never throws).
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1234
|
+
* - **Composes `@orkestrel/process`.** `start()` builds one supervised
|
|
1235
|
+
* {@link import('@orkestrel/process/server').Process} with `writable: true`, so the child's
|
|
1236
|
+
* `stdin`/`stdout` are the JSON-RPC channel and its `stderr` is retained as bounded evidence
|
|
1237
|
+
* rather than parsed as protocol. The supervisor owns spawn, framing, and termination.
|
|
1238
|
+
* - **Inbound (`message`).** Standard output is drained eagerly through the supervisor's
|
|
1239
|
+
* `readline`-framed `lines` iterable, so a multi-byte UTF-8 sequence split across two reads is
|
|
1240
|
+
* decoded whole and a final line written without a trailing newline still arrives. Each framed
|
|
1241
|
+
* line is decoded and delivered via the shared {@link dispatchLines} helper — a well-formed
|
|
1242
|
+
* {@link JSONRPCMessage} emits `message`, a malformed line emits `error` (§14, never throws).
|
|
1243
|
+
* - **Outbound (`send`).** `send(message)` writes one newline-terminated `JSON.stringify`d line
|
|
1244
|
+
* through the supervisor's `send` and AWAITS its answer, so this promise settles only after the
|
|
1245
|
+
* host reports the line handled rather than the moment the write is queued. The supervisor never
|
|
1246
|
+
* rejects — it answers `false` for a channel that was closed, destroyed, or ended, and for a write
|
|
1247
|
+
* that failed — so a `false` answer REJECTS here with the same not-connected error a transport
|
|
1248
|
+
* that was never started raises. A dead peer surfaces at the caller instead of vanishing.
|
|
1249
|
+
* - **`close()`** terminates the child through the supervisor's bounded `SIGTERM` → grace →
|
|
1250
|
+
* `SIGKILL` group-kill, awaits its observed exit, tears down the supervisor, and fires `close`
|
|
1251
|
+
* once (idempotent). On a POSIX host the child leads its own process group, so the group-kill
|
|
1252
|
+
* reaches its grandchildren rather than orphaning them.
|
|
1247
1253
|
* - **Observable (§13).** Owns the `emitter` ({@link MCPClientTransportEventMap}); the
|
|
1248
1254
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1249
|
-
* fault), distinct from the emitter's
|
|
1255
|
+
* fault, including the child spawn cause the supervisor surfaces), distinct from the emitter's
|
|
1256
|
+
* own listener-error channel.
|
|
1250
1257
|
*
|
|
1251
1258
|
* @example
|
|
1252
1259
|
* ```ts
|
|
@@ -1273,11 +1280,11 @@ export declare class StdioClientTransport implements MCPClientTransportInterface
|
|
|
1273
1280
|
* @remarks
|
|
1274
1281
|
* - `command` — the executable to spawn (e.g. `'node'`, `'./my-mcp-server'`). REQUIRED.
|
|
1275
1282
|
* - `args` — the command-line arguments passed to `command`; defaults to none.
|
|
1276
|
-
* - `env` —
|
|
1277
|
-
*
|
|
1278
|
-
* `process.env
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
1283
|
+
* - `env` — environment variable overrides MERGED over the parent `process.env` for the
|
|
1284
|
+
* spawned child (the composed `@orkestrel/process` supervisor's merge semantics): when
|
|
1285
|
+
* OMITTED the child inherits the full `process.env`, when PROVIDED each named key overrides
|
|
1286
|
+
* the inherited value while every unlisted key is still inherited. This transport cannot
|
|
1287
|
+
* REPLACE the inherited environment entirely — the supervisor always merges over the parent.
|
|
1281
1288
|
*/
|
|
1282
1289
|
export declare interface StdioClientTransportOptions {
|
|
1283
1290
|
readonly command: string;
|
|
@@ -1231,22 +1231,29 @@ export declare const SSE_KEEPALIVE_COMMENT = "keepalive";
|
|
|
1231
1231
|
* import('./WebSocketClientTransport.js').WebSocketClientTransport}.
|
|
1232
1232
|
*
|
|
1233
1233
|
* @remarks
|
|
1234
|
-
* - **
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
* - **Inbound (`message`).**
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
* {@link dispatchLines} helper — a well-formed
|
|
1242
|
-
* `message`, a malformed line emits `error` (§14, never throws).
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1234
|
+
* - **Composes `@orkestrel/process`.** `start()` builds one supervised
|
|
1235
|
+
* {@link import('@orkestrel/process/server').Process} with `writable: true`, so the child's
|
|
1236
|
+
* `stdin`/`stdout` are the JSON-RPC channel and its `stderr` is retained as bounded evidence
|
|
1237
|
+
* rather than parsed as protocol. The supervisor owns spawn, framing, and termination.
|
|
1238
|
+
* - **Inbound (`message`).** Standard output is drained eagerly through the supervisor's
|
|
1239
|
+
* `readline`-framed `lines` iterable, so a multi-byte UTF-8 sequence split across two reads is
|
|
1240
|
+
* decoded whole and a final line written without a trailing newline still arrives. Each framed
|
|
1241
|
+
* line is decoded and delivered via the shared {@link dispatchLines} helper — a well-formed
|
|
1242
|
+
* {@link JSONRPCMessage} emits `message`, a malformed line emits `error` (§14, never throws).
|
|
1243
|
+
* - **Outbound (`send`).** `send(message)` writes one newline-terminated `JSON.stringify`d line
|
|
1244
|
+
* through the supervisor's `send` and AWAITS its answer, so this promise settles only after the
|
|
1245
|
+
* host reports the line handled rather than the moment the write is queued. The supervisor never
|
|
1246
|
+
* rejects — it answers `false` for a channel that was closed, destroyed, or ended, and for a write
|
|
1247
|
+
* that failed — so a `false` answer REJECTS here with the same not-connected error a transport
|
|
1248
|
+
* that was never started raises. A dead peer surfaces at the caller instead of vanishing.
|
|
1249
|
+
* - **`close()`** terminates the child through the supervisor's bounded `SIGTERM` → grace →
|
|
1250
|
+
* `SIGKILL` group-kill, awaits its observed exit, tears down the supervisor, and fires `close`
|
|
1251
|
+
* once (idempotent). On a POSIX host the child leads its own process group, so the group-kill
|
|
1252
|
+
* reaches its grandchildren rather than orphaning them.
|
|
1247
1253
|
* - **Observable (§13).** Owns the `emitter` ({@link MCPClientTransportEventMap}); the
|
|
1248
1254
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1249
|
-
* fault), distinct from the emitter's
|
|
1255
|
+
* fault, including the child spawn cause the supervisor surfaces), distinct from the emitter's
|
|
1256
|
+
* own listener-error channel.
|
|
1250
1257
|
*
|
|
1251
1258
|
* @example
|
|
1252
1259
|
* ```ts
|
|
@@ -1273,11 +1280,11 @@ export declare class StdioClientTransport implements MCPClientTransportInterface
|
|
|
1273
1280
|
* @remarks
|
|
1274
1281
|
* - `command` — the executable to spawn (e.g. `'node'`, `'./my-mcp-server'`). REQUIRED.
|
|
1275
1282
|
* - `args` — the command-line arguments passed to `command`; defaults to none.
|
|
1276
|
-
* - `env` —
|
|
1277
|
-
*
|
|
1278
|
-
* `process.env
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
1283
|
+
* - `env` — environment variable overrides MERGED over the parent `process.env` for the
|
|
1284
|
+
* spawned child (the composed `@orkestrel/process` supervisor's merge semantics): when
|
|
1285
|
+
* OMITTED the child inherits the full `process.env`, when PROVIDED each named key overrides
|
|
1286
|
+
* the inherited value while every unlisted key is still inherited. This transport cannot
|
|
1287
|
+
* REPLACE the inherited environment entirely — the supervisor always merges over the parent.
|
|
1281
1288
|
*/
|
|
1282
1289
|
export declare interface StdioClientTransportOptions {
|
|
1283
1290
|
readonly command: string;
|
package/dist/src/server/index.js
CHANGED
|
@@ -7,7 +7,8 @@ import { randomBytes } from "node:crypto";
|
|
|
7
7
|
import { request } from "node:http";
|
|
8
8
|
import { request as request$1 } from "node:https";
|
|
9
9
|
import { WEBSOCKET_VERSION, computeWebSocketAccept, createNodeWebSocket } from "@orkestrel/websocket";
|
|
10
|
-
import {
|
|
10
|
+
import { Process } from "@orkestrel/process/server";
|
|
11
|
+
import { PROCESS_GRACE } from "@orkestrel/process";
|
|
11
12
|
//#region src/server/constants.ts
|
|
12
13
|
/**
|
|
13
14
|
* The Streamable-HTTP transport header that carries the MCP session id. When a {@link
|
|
@@ -1296,22 +1297,29 @@ var WebSocketClientTransport = class {
|
|
|
1296
1297
|
* import('./WebSocketClientTransport.js').WebSocketClientTransport}.
|
|
1297
1298
|
*
|
|
1298
1299
|
* @remarks
|
|
1299
|
-
* - **
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
* - **Inbound (`message`).**
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1306
|
-
* {@link dispatchLines} helper — a well-formed
|
|
1307
|
-
* `message`, a malformed line emits `error` (§14, never throws).
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1300
|
+
* - **Composes `@orkestrel/process`.** `start()` builds one supervised
|
|
1301
|
+
* {@link import('@orkestrel/process/server').Process} with `writable: true`, so the child's
|
|
1302
|
+
* `stdin`/`stdout` are the JSON-RPC channel and its `stderr` is retained as bounded evidence
|
|
1303
|
+
* rather than parsed as protocol. The supervisor owns spawn, framing, and termination.
|
|
1304
|
+
* - **Inbound (`message`).** Standard output is drained eagerly through the supervisor's
|
|
1305
|
+
* `readline`-framed `lines` iterable, so a multi-byte UTF-8 sequence split across two reads is
|
|
1306
|
+
* decoded whole and a final line written without a trailing newline still arrives. Each framed
|
|
1307
|
+
* line is decoded and delivered via the shared {@link dispatchLines} helper — a well-formed
|
|
1308
|
+
* {@link JSONRPCMessage} emits `message`, a malformed line emits `error` (§14, never throws).
|
|
1309
|
+
* - **Outbound (`send`).** `send(message)` writes one newline-terminated `JSON.stringify`d line
|
|
1310
|
+
* through the supervisor's `send` and AWAITS its answer, so this promise settles only after the
|
|
1311
|
+
* host reports the line handled rather than the moment the write is queued. The supervisor never
|
|
1312
|
+
* rejects — it answers `false` for a channel that was closed, destroyed, or ended, and for a write
|
|
1313
|
+
* that failed — so a `false` answer REJECTS here with the same not-connected error a transport
|
|
1314
|
+
* that was never started raises. A dead peer surfaces at the caller instead of vanishing.
|
|
1315
|
+
* - **`close()`** terminates the child through the supervisor's bounded `SIGTERM` → grace →
|
|
1316
|
+
* `SIGKILL` group-kill, awaits its observed exit, tears down the supervisor, and fires `close`
|
|
1317
|
+
* once (idempotent). On a POSIX host the child leads its own process group, so the group-kill
|
|
1318
|
+
* reaches its grandchildren rather than orphaning them.
|
|
1312
1319
|
* - **Observable (§13).** Owns the `emitter` ({@link MCPClientTransportEventMap}); the
|
|
1313
1320
|
* emitter isolates a listener throw; `error` is a DOMAIN event (a transport-level
|
|
1314
|
-
* fault), distinct from the emitter's
|
|
1321
|
+
* fault, including the child spawn cause the supervisor surfaces), distinct from the emitter's
|
|
1322
|
+
* own listener-error channel.
|
|
1315
1323
|
*
|
|
1316
1324
|
* @example
|
|
1317
1325
|
* ```ts
|
|
@@ -1325,8 +1333,7 @@ var StdioClientTransport = class {
|
|
|
1325
1333
|
#command;
|
|
1326
1334
|
#args;
|
|
1327
1335
|
#env;
|
|
1328
|
-
#
|
|
1329
|
-
#buffer = "";
|
|
1336
|
+
#process = void 0;
|
|
1330
1337
|
#closed = false;
|
|
1331
1338
|
constructor(options) {
|
|
1332
1339
|
this.#emitter = new Emitter();
|
|
@@ -1342,44 +1349,45 @@ var StdioClientTransport = class {
|
|
|
1342
1349
|
return true;
|
|
1343
1350
|
}
|
|
1344
1351
|
async start() {
|
|
1345
|
-
if (this.#
|
|
1352
|
+
if (this.#process !== void 0) return;
|
|
1346
1353
|
this.#closed = false;
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1354
|
+
const child = new Process({
|
|
1355
|
+
command: {
|
|
1356
|
+
file: this.#command,
|
|
1357
|
+
arguments: [...this.#args],
|
|
1358
|
+
...this.#env === void 0 ? {} : { environment: this.#env }
|
|
1359
|
+
},
|
|
1360
|
+
workspace: process.cwd(),
|
|
1361
|
+
grace: PROCESS_GRACE,
|
|
1362
|
+
writable: true
|
|
1355
1363
|
});
|
|
1356
|
-
this.#
|
|
1357
|
-
child.
|
|
1358
|
-
child.
|
|
1359
|
-
|
|
1364
|
+
this.#process = child;
|
|
1365
|
+
child.emitter.on("error", (cause) => this.#emitter.emit("error", cause));
|
|
1366
|
+
child.exit.then(() => this.#onExit(child));
|
|
1367
|
+
this.#pump(child);
|
|
1360
1368
|
}
|
|
1361
1369
|
async send(message) {
|
|
1362
|
-
const child = this.#
|
|
1363
|
-
if (child === void 0) throw new Error("stdio transport is not connected");
|
|
1364
|
-
child.stdin.write(`${JSON.stringify(message)}\n`);
|
|
1370
|
+
const child = this.#process;
|
|
1371
|
+
if (!(child === void 0 ? false : await child.send(JSON.stringify(message)))) throw new Error("stdio transport is not connected");
|
|
1365
1372
|
}
|
|
1366
1373
|
async close() {
|
|
1367
1374
|
if (this.#closed) return;
|
|
1368
1375
|
this.#closed = true;
|
|
1369
|
-
const child = this.#
|
|
1370
|
-
this.#
|
|
1371
|
-
if (child !== void 0) child.
|
|
1376
|
+
const child = this.#process;
|
|
1377
|
+
this.#process = void 0;
|
|
1378
|
+
if (child !== void 0) await child.destroy();
|
|
1372
1379
|
this.#emitter.emit("close");
|
|
1373
1380
|
}
|
|
1374
|
-
#
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1381
|
+
async #pump(child) {
|
|
1382
|
+
for await (const line of child.lines) {
|
|
1383
|
+
if (this.#process !== child) return;
|
|
1384
|
+
dispatchLines(this.#emitter, [line]);
|
|
1385
|
+
}
|
|
1378
1386
|
}
|
|
1379
|
-
#
|
|
1380
|
-
if (this.#closed || this.#
|
|
1387
|
+
#onExit(child) {
|
|
1388
|
+
if (this.#closed || this.#process !== child) return;
|
|
1381
1389
|
this.#closed = true;
|
|
1382
|
-
this.#
|
|
1390
|
+
this.#process = void 0;
|
|
1383
1391
|
this.#emitter.emit("close");
|
|
1384
1392
|
}
|
|
1385
1393
|
};
|