git-subtree-dir: packages/mcp-typescript git-subtree-split: 2cc7dd104307d48bab8d27760f16c63c119d8a88
93 lines
3.6 KiB
JavaScript
Generated
93 lines
3.6 KiB
JavaScript
Generated
import { spawn } from "node:child_process";
|
|
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
|
|
/**
|
|
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
|
|
*
|
|
* This transport is only available in Node.js environments.
|
|
*/
|
|
export class StdioClientTransport {
|
|
constructor() {
|
|
this._abortController = new AbortController();
|
|
this._readBuffer = new ReadBuffer();
|
|
}
|
|
/**
|
|
* Spawns the server process and prepare to communicate with it.
|
|
*/
|
|
spawn(server) {
|
|
return new Promise((resolve, reject) => {
|
|
var _a, _b, _c, _d;
|
|
this._process = spawn(server.command, (_a = server.args) !== null && _a !== void 0 ? _a : [], {
|
|
// The parent process may have sensitive secrets in its env, so don't inherit it automatically.
|
|
env: server.env === undefined ? {} : { ...server.env },
|
|
stdio: ["pipe", "pipe", "inherit"],
|
|
signal: this._abortController.signal,
|
|
});
|
|
this._process.on("error", (error) => {
|
|
var _a, _b;
|
|
if (error.name === "AbortError") {
|
|
// Expected when close() is called.
|
|
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
return;
|
|
}
|
|
reject(error);
|
|
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
|
});
|
|
this._process.on("spawn", () => {
|
|
resolve();
|
|
});
|
|
this._process.on("close", (_code) => {
|
|
var _a;
|
|
this._process = undefined;
|
|
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
});
|
|
(_b = this._process.stdin) === null || _b === void 0 ? void 0 : _b.on("error", (error) => {
|
|
var _a;
|
|
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
});
|
|
(_c = this._process.stdout) === null || _c === void 0 ? void 0 : _c.on("data", (chunk) => {
|
|
this._readBuffer.append(chunk);
|
|
this.processReadBuffer();
|
|
});
|
|
(_d = this._process.stdout) === null || _d === void 0 ? void 0 : _d.on("error", (error) => {
|
|
var _a;
|
|
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
});
|
|
});
|
|
}
|
|
processReadBuffer() {
|
|
var _a, _b;
|
|
while (true) {
|
|
try {
|
|
const message = this._readBuffer.readMessage();
|
|
if (message === null) {
|
|
break;
|
|
}
|
|
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
|
|
}
|
|
catch (error) {
|
|
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
|
|
}
|
|
}
|
|
}
|
|
async close() {
|
|
this._abortController.abort();
|
|
this._process = undefined;
|
|
this._readBuffer.clear();
|
|
}
|
|
send(message) {
|
|
return new Promise((resolve) => {
|
|
var _a;
|
|
if (!((_a = this._process) === null || _a === void 0 ? void 0 : _a.stdin)) {
|
|
throw new Error("Not connected");
|
|
}
|
|
const json = serializeMessage(message);
|
|
if (this._process.stdin.write(json)) {
|
|
resolve();
|
|
}
|
|
else {
|
|
this._process.stdin.once("drain", resolve);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
//# sourceMappingURL=stdio.js.map
|