Initial import

This commit is contained in:
David Soria Parra 2024-09-24 21:49:12 +01:00
commit 02e421c1f1
No known key found for this signature in database

73
src/server/stdio.ts Normal file
View file

@ -0,0 +1,73 @@
import process from "node:process";
import { Readable, Writable } from "node:stream";
import { ReadBuffer, serializeMessage } from "../shared/stdio.js";
import { JSONRPCMessage } from "../types/index.js";
import { Transport } from "../shared/transport.js";
/**
* Server transport for stdio: this communicates with a MCP client by reading from the current process' stdin and writing to stdout.
*
* This transport is only available in Node.js environments.
*/
export class StdioServerTransport implements Transport {
private _readBuffer: ReadBuffer = new ReadBuffer();
constructor(
private _stdin: Readable = process.stdin,
private _stdout: Writable = process.stdout,
) {}
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
// Arrow functions to bind `this` properly, while maintaining function identity.
_ondata = (chunk: Buffer) => {
this._readBuffer.append(chunk);
this.processReadBuffer();
};
_onerror = (error: Error) => {
this.onerror?.(error);
};
/**
* Starts listening for messages on stdin.
*/
async start(): Promise<void> {
this._stdin.on("data", this._ondata);
this._stdin.on("error", this._onerror);
}
private processReadBuffer() {
while (true) {
try {
const message = this._readBuffer.readMessage();
if (message === null) {
break;
}
this.onmessage?.(message);
} catch (error) {
this.onerror?.(error as Error);
}
}
}
async close(): Promise<void> {
this._stdin.off("data", this._ondata);
this._stdin.off("error", this._onerror);
this._readBuffer.clear();
this.onclose?.();
}
send(message: JSONRPCMessage): Promise<void> {
return new Promise((resolve) => {
const json = serializeMessage(message);
if (this._stdout.write(json)) {
resolve();
} else {
this._stdout.once("drain", resolve);
}
});
}
}