stdio.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.StdioServerTransport = void 0;
  7. const node_process_1 = __importDefault(require("node:process"));
  8. const stdio_js_1 = require("../shared/stdio.js");
  9. /**
  10. * Server transport for stdio: this communicates with an MCP client by reading from the current process' stdin and writing to stdout.
  11. *
  12. * This transport is only available in Node.js environments.
  13. */
  14. class StdioServerTransport {
  15. constructor(_stdin = node_process_1.default.stdin, _stdout = node_process_1.default.stdout) {
  16. this._stdin = _stdin;
  17. this._stdout = _stdout;
  18. this._readBuffer = new stdio_js_1.ReadBuffer();
  19. this._started = false;
  20. // Arrow functions to bind `this` properly, while maintaining function identity.
  21. this._ondata = (chunk) => {
  22. this._readBuffer.append(chunk);
  23. this.processReadBuffer();
  24. };
  25. this._onerror = (error) => {
  26. this.onerror?.(error);
  27. };
  28. }
  29. /**
  30. * Starts listening for messages on stdin.
  31. */
  32. async start() {
  33. if (this._started) {
  34. throw new Error('StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.');
  35. }
  36. this._started = true;
  37. this._stdin.on('data', this._ondata);
  38. this._stdin.on('error', this._onerror);
  39. }
  40. processReadBuffer() {
  41. while (true) {
  42. try {
  43. const message = this._readBuffer.readMessage();
  44. if (message === null) {
  45. break;
  46. }
  47. this.onmessage?.(message);
  48. }
  49. catch (error) {
  50. this.onerror?.(error);
  51. }
  52. }
  53. }
  54. async close() {
  55. // Remove our event listeners first
  56. this._stdin.off('data', this._ondata);
  57. this._stdin.off('error', this._onerror);
  58. // Check if we were the only data listener
  59. const remainingDataListeners = this._stdin.listenerCount('data');
  60. if (remainingDataListeners === 0) {
  61. // Only pause stdin if we were the only listener
  62. // This prevents interfering with other parts of the application that might be using stdin
  63. this._stdin.pause();
  64. }
  65. // Clear the buffer and notify closure
  66. this._readBuffer.clear();
  67. this.onclose?.();
  68. }
  69. send(message) {
  70. return new Promise(resolve => {
  71. const json = (0, stdio_js_1.serializeMessage)(message);
  72. if (this._stdout.write(json)) {
  73. resolve();
  74. }
  75. else {
  76. this._stdout.once('drain', resolve);
  77. }
  78. });
  79. }
  80. }
  81. exports.StdioServerTransport = StdioServerTransport;
  82. //# sourceMappingURL=stdio.js.map