@orkestrel/mcp 0.0.22 → 0.0.24

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.
@@ -1484,8 +1484,10 @@ export declare interface StdioServerOptions {
1484
1484
  * emits `error` (never throws). `input`'s `close` bridges to this
1485
1485
  * transport's `close`.
1486
1486
  * - **Outbound (`send`).** `send(message)` writes one newline-terminated
1487
- * `JSON.stringify`d line to `output`.
1488
- * - **`close()`** removes this transport's input subscriptions and fires its `close`
1487
+ * `JSON.stringify`d line to `output` and awaits the writable completion callback. The
1488
+ * callback is the backpressure boundary and its error rejects the send.
1489
+ * - **`close()`** removes this transport's input and output subscriptions, rejects every
1490
+ * pending send, and fires its `close`
1489
1491
  * event (idempotent). It pauses the input only when the caller was not already reading
1490
1492
  * it at `start` (`readableFlowing !== true`) AND no `data` listener remains once this
1491
1493
  * transport's own is removed — so a process holding `process.stdin` can exit, and a
@@ -1508,6 +1510,19 @@ export declare class StdioServerTransport implements MCPClientTransportInterface
1508
1510
  get session(): string | undefined;
1509
1511
  get duplex(): boolean;
1510
1512
  start(): Promise<void>;
1513
+ /**
1514
+ * Sends one newline-delimited JSON-RPC message through the caller-owned output stream.
1515
+ *
1516
+ * @remarks
1517
+ * The writable completion callback is the backpressure boundary. This method awaits that
1518
+ * callback rather than adding a `drain` listener. Closing the transport rejects every send
1519
+ * whose callback has not settled.
1520
+ *
1521
+ * @param message - The message to serialize and write
1522
+ * @returns Resolves when the output confirms the write
1523
+ * @throws Thrown with `stdio transport is not connected` after the transport closes
1524
+ * @throws Thrown with the output callback error or synchronous write failure
1525
+ */
1511
1526
  send(message: JSONRPCMessage_2): Promise<void>;
1512
1527
  close(): Promise<void>;
1513
1528
  }
@@ -1556,7 +1571,11 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
1556
1571
  * event (the reply the {@link import('@orkestrel/mcp').MCPClientInterface} correlates by `id`); a
1557
1572
  * non-JSON / non-message frame surfaces on `error` and is dropped. The socket's `close`
1558
1573
  * / `error` bridge to this transport's events.
1559
- * - **Outbound (`send`).** `send(message)` writes one masked text frame.
1574
+ * - **Outbound (`send`).** `send(message)` writes one masked text frame. A socket write is not
1575
+ * confirmed, so this transport answers a closed channel from its OWN state: a `send` with no
1576
+ * bound socket — before `start()`, after `close()`, or after the peer ended the socket —
1577
+ * REJECTS with `WebSocket transport is not connected`. It neither drops the message (the
1578
+ * browser face's posture) nor queues it for a connection this transport is not holding.
1560
1579
  * - **`close()`** unsubscribes from the socket, closes it, and fires `close` (idempotent). An
1561
1580
  * upgrade still on the wire is DESTROYED, so a `close()` during the handshake ends the
1562
1581
  * transport at once instead of waiting for a peer that may never answer — the suspended
@@ -1684,4 +1703,30 @@ export declare class WebSocketServerTransport implements MCPClientTransportInter
1684
1703
  close(): Promise<void>;
1685
1704
  }
1686
1705
 
1706
+ /**
1707
+ * Writes one line to a Node writable stream and waits for its completion callback.
1708
+ *
1709
+ * @remarks
1710
+ * The completion callback is the writable channel's backpressure boundary. A callback error and
1711
+ * a synchronous `write` throw reject the returned promise with the original value.
1712
+ *
1713
+ * That callback is the ONLY thing that settles the promise: this helper holds no timer and no
1714
+ * abort, so an output that neither confirms nor fails the write parks the promise for as long as
1715
+ * the caller-owned stream holds the callback. A caller wanting a bound races this promise against
1716
+ * one it owns — {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
1717
+ * registers such a bound per send and rejects it on `close()`, so closing the transport settles
1718
+ * the CALLER's `send` while the abandoned write stays with the stream that still holds its
1719
+ * callback, reachable from nothing the transport retains.
1720
+ *
1721
+ * @param output - The writable stream that receives the line
1722
+ * @param line - The complete line to write
1723
+ * @returns Resolves when the stream confirms the write; rejects when the write fails
1724
+ *
1725
+ * @example
1726
+ * ```ts
1727
+ * await writeLine(process.stdout, '{"jsonrpc":"2.0","method":"ping"}\n')
1728
+ * ```
1729
+ */
1730
+ export declare function writeLine(output: NodeJS.WritableStream, line: string): Promise<void>;
1731
+
1687
1732
  export { }
@@ -1484,8 +1484,10 @@ export declare interface StdioServerOptions {
1484
1484
  * emits `error` (never throws). `input`'s `close` bridges to this
1485
1485
  * transport's `close`.
1486
1486
  * - **Outbound (`send`).** `send(message)` writes one newline-terminated
1487
- * `JSON.stringify`d line to `output`.
1488
- * - **`close()`** removes this transport's input subscriptions and fires its `close`
1487
+ * `JSON.stringify`d line to `output` and awaits the writable completion callback. The
1488
+ * callback is the backpressure boundary and its error rejects the send.
1489
+ * - **`close()`** removes this transport's input and output subscriptions, rejects every
1490
+ * pending send, and fires its `close`
1489
1491
  * event (idempotent). It pauses the input only when the caller was not already reading
1490
1492
  * it at `start` (`readableFlowing !== true`) AND no `data` listener remains once this
1491
1493
  * transport's own is removed — so a process holding `process.stdin` can exit, and a
@@ -1508,6 +1510,19 @@ export declare class StdioServerTransport implements MCPClientTransportInterface
1508
1510
  get session(): string | undefined;
1509
1511
  get duplex(): boolean;
1510
1512
  start(): Promise<void>;
1513
+ /**
1514
+ * Sends one newline-delimited JSON-RPC message through the caller-owned output stream.
1515
+ *
1516
+ * @remarks
1517
+ * The writable completion callback is the backpressure boundary. This method awaits that
1518
+ * callback rather than adding a `drain` listener. Closing the transport rejects every send
1519
+ * whose callback has not settled.
1520
+ *
1521
+ * @param message - The message to serialize and write
1522
+ * @returns Resolves when the output confirms the write
1523
+ * @throws Thrown with `stdio transport is not connected` after the transport closes
1524
+ * @throws Thrown with the output callback error or synchronous write failure
1525
+ */
1511
1526
  send(message: JSONRPCMessage_2): Promise<void>;
1512
1527
  close(): Promise<void>;
1513
1528
  }
@@ -1556,7 +1571,11 @@ export declare function upgradeRequestPath(request: IncomingMessage): string;
1556
1571
  * event (the reply the {@link import('@orkestrel/mcp').MCPClientInterface} correlates by `id`); a
1557
1572
  * non-JSON / non-message frame surfaces on `error` and is dropped. The socket's `close`
1558
1573
  * / `error` bridge to this transport's events.
1559
- * - **Outbound (`send`).** `send(message)` writes one masked text frame.
1574
+ * - **Outbound (`send`).** `send(message)` writes one masked text frame. A socket write is not
1575
+ * confirmed, so this transport answers a closed channel from its OWN state: a `send` with no
1576
+ * bound socket — before `start()`, after `close()`, or after the peer ended the socket —
1577
+ * REJECTS with `WebSocket transport is not connected`. It neither drops the message (the
1578
+ * browser face's posture) nor queues it for a connection this transport is not holding.
1560
1579
  * - **`close()`** unsubscribes from the socket, closes it, and fires `close` (idempotent). An
1561
1580
  * upgrade still on the wire is DESTROYED, so a `close()` during the handshake ends the
1562
1581
  * transport at once instead of waiting for a peer that may never answer — the suspended
@@ -1684,4 +1703,30 @@ export declare class WebSocketServerTransport implements MCPClientTransportInter
1684
1703
  close(): Promise<void>;
1685
1704
  }
1686
1705
 
1706
+ /**
1707
+ * Writes one line to a Node writable stream and waits for its completion callback.
1708
+ *
1709
+ * @remarks
1710
+ * The completion callback is the writable channel's backpressure boundary. A callback error and
1711
+ * a synchronous `write` throw reject the returned promise with the original value.
1712
+ *
1713
+ * That callback is the ONLY thing that settles the promise: this helper holds no timer and no
1714
+ * abort, so an output that neither confirms nor fails the write parks the promise for as long as
1715
+ * the caller-owned stream holds the callback. A caller wanting a bound races this promise against
1716
+ * one it owns — {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
1717
+ * registers such a bound per send and rejects it on `close()`, so closing the transport settles
1718
+ * the CALLER's `send` while the abandoned write stays with the stream that still holds its
1719
+ * callback, reachable from nothing the transport retains.
1720
+ *
1721
+ * @param output - The writable stream that receives the line
1722
+ * @param line - The complete line to write
1723
+ * @returns Resolves when the stream confirms the write; rejects when the write fails
1724
+ *
1725
+ * @example
1726
+ * ```ts
1727
+ * await writeLine(process.stdout, '{"jsonrpc":"2.0","method":"ping"}\n')
1728
+ * ```
1729
+ */
1730
+ export declare function writeLine(output: NodeJS.WritableStream, line: string): Promise<void>;
1731
+
1687
1732
  export { }
@@ -364,6 +364,42 @@ function extractLines(buffer, chunk) {
364
364
  };
365
365
  }
366
366
  /**
367
+ * Writes one line to a Node writable stream and waits for its completion callback.
368
+ *
369
+ * @remarks
370
+ * The completion callback is the writable channel's backpressure boundary. A callback error and
371
+ * a synchronous `write` throw reject the returned promise with the original value.
372
+ *
373
+ * That callback is the ONLY thing that settles the promise: this helper holds no timer and no
374
+ * abort, so an output that neither confirms nor fails the write parks the promise for as long as
375
+ * the caller-owned stream holds the callback. A caller wanting a bound races this promise against
376
+ * one it owns — {@link import('./transports/StdioServerTransport.js').StdioServerTransport}
377
+ * registers such a bound per send and rejects it on `close()`, so closing the transport settles
378
+ * the CALLER's `send` while the abandoned write stays with the stream that still holds its
379
+ * callback, reachable from nothing the transport retains.
380
+ *
381
+ * @param output - The writable stream that receives the line
382
+ * @param line - The complete line to write
383
+ * @returns Resolves when the stream confirms the write; rejects when the write fails
384
+ *
385
+ * @example
386
+ * ```ts
387
+ * await writeLine(process.stdout, '{"jsonrpc":"2.0","method":"ping"}\n')
388
+ * ```
389
+ */
390
+ function writeLine(output, line) {
391
+ return new Promise((resolve, reject) => {
392
+ try {
393
+ output.write(line, (error) => {
394
+ if (error === void 0 || error === null) resolve();
395
+ else reject(error);
396
+ });
397
+ } catch (error) {
398
+ reject(error);
399
+ }
400
+ });
401
+ }
402
+ /**
367
403
  * Decodes and delivers each complete newline-framed line onto a {@link
368
404
  * MCPClientTransportEventMap} emitter — the shared per-chunk dispatch step both stdio
369
405
  * transports run their framed lines through: the server transport frames with {@link
@@ -1211,7 +1247,11 @@ var WebSocketServerTransport = class {
1211
1247
  * event (the reply the {@link import('@orkestrel/mcp').MCPClientInterface} correlates by `id`); a
1212
1248
  * non-JSON / non-message frame surfaces on `error` and is dropped. The socket's `close`
1213
1249
  * / `error` bridge to this transport's events.
1214
- * - **Outbound (`send`).** `send(message)` writes one masked text frame.
1250
+ * - **Outbound (`send`).** `send(message)` writes one masked text frame. A socket write is not
1251
+ * confirmed, so this transport answers a closed channel from its OWN state: a `send` with no
1252
+ * bound socket — before `start()`, after `close()`, or after the peer ended the socket —
1253
+ * REJECTS with `WebSocket transport is not connected`. It neither drops the message (the
1254
+ * browser face's posture) nor queues it for a connection this transport is not holding.
1215
1255
  * - **`close()`** unsubscribes from the socket, closes it, and fires `close` (idempotent). An
1216
1256
  * upgrade still on the wire is DESTROYED, so a `close()` during the handshake ends the
1217
1257
  * transport at once instead of waiting for a peer that may never answer — the suspended
@@ -1558,8 +1598,10 @@ var StdioClientTransport = class {
1558
1598
  * emits `error` (never throws). `input`'s `close` bridges to this
1559
1599
  * transport's `close`.
1560
1600
  * - **Outbound (`send`).** `send(message)` writes one newline-terminated
1561
- * `JSON.stringify`d line to `output`.
1562
- * - **`close()`** removes this transport's input subscriptions and fires its `close`
1601
+ * `JSON.stringify`d line to `output` and awaits the writable completion callback. The
1602
+ * callback is the backpressure boundary and its error rejects the send.
1603
+ * - **`close()`** removes this transport's input and output subscriptions, rejects every
1604
+ * pending send, and fires its `close`
1563
1605
  * event (idempotent). It pauses the input only when the caller was not already reading
1564
1606
  * it at `start` (`readableFlowing !== true`) AND no `data` listener remains once this
1565
1607
  * transport's own is removed — so a process holding `process.stdin` can exit, and a
@@ -1582,6 +1624,7 @@ var StdioServerTransport = class {
1582
1624
  #data = (chunk) => this.#receive(chunk.toString());
1583
1625
  #ending = () => this.#onClose();
1584
1626
  #failure = (error) => this.#emitter.emit("error", error);
1627
+ #pending = /* @__PURE__ */ new Set();
1585
1628
  #buffer = "";
1586
1629
  #started = false;
1587
1630
  #closed = false;
@@ -1605,9 +1648,30 @@ var StdioServerTransport = class {
1605
1648
  this.#input.on("data", this.#data);
1606
1649
  this.#input.on("close", this.#ending);
1607
1650
  this.#input.on("error", this.#failure);
1651
+ this.#output.on("error", this.#failure);
1608
1652
  }
1653
+ /**
1654
+ * Sends one newline-delimited JSON-RPC message through the caller-owned output stream.
1655
+ *
1656
+ * @remarks
1657
+ * The writable completion callback is the backpressure boundary. This method awaits that
1658
+ * callback rather than adding a `drain` listener. Closing the transport rejects every send
1659
+ * whose callback has not settled.
1660
+ *
1661
+ * @param message - The message to serialize and write
1662
+ * @returns Resolves when the output confirms the write
1663
+ * @throws Thrown with `stdio transport is not connected` after the transport closes
1664
+ * @throws Thrown with the output callback error or synchronous write failure
1665
+ */
1609
1666
  async send(message) {
1610
- this.#output.write(`${JSON.stringify(message)}\n`);
1667
+ if (this.#closed) throw new Error("stdio transport is not connected");
1668
+ const pending = Promise.withResolvers();
1669
+ this.#pending.add(pending);
1670
+ try {
1671
+ await Promise.race([writeLine(this.#output, `${JSON.stringify(message)}\n`), pending.promise]);
1672
+ } finally {
1673
+ this.#pending.delete(pending);
1674
+ }
1611
1675
  }
1612
1676
  async close() {
1613
1677
  if (this.#closed) return;
@@ -1630,6 +1694,9 @@ var StdioServerTransport = class {
1630
1694
  this.#input.removeListener("data", this.#data);
1631
1695
  this.#input.removeListener("close", this.#ending);
1632
1696
  this.#input.removeListener("error", this.#failure);
1697
+ this.#output.removeListener("error", this.#failure);
1698
+ for (const pending of this.#pending) pending.reject(/* @__PURE__ */ new Error("stdio transport is not connected"));
1699
+ this.#pending.clear();
1633
1700
  if (!this.#flowing && this.#input.listenerCount("data") === 0) this.#input.pause();
1634
1701
  }
1635
1702
  };
@@ -2137,6 +2204,6 @@ function createMCPSession(options) {
2137
2204
  };
2138
2205
  }
2139
2206
  //#endregion
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 };
2207
+ 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, writeLine };
2141
2208
 
2142
2209
  //# sourceMappingURL=index.js.map