@fusedashlabs/ui9000-workspace
Version:
UI9000 workspace MCP. One tool, show_workspace, draws a chart from your table. Set TYPESAFE_API_KEY to let Jev choose the chart.
53 lines (52 loc) • 1.85 kB
JavaScript
/**
* stdio transport: newline-delimited JSON-RPC in, newline-delimited JSON out.
* Nothing else may be written to stdout — a stray log breaks the frame stream.
*/
import { errorResponse, PARSE_ERROR } from './create-server.js';
const INTERNAL_ERROR = -32603;
export function connectStdio(server, streams = { input: process.stdin, output: process.stdout }) {
const { input, output } = streams;
let buffer = '';
// One promise chain keeps replies in request order even when a handler awaits.
let queue = Promise.resolve();
const onData = (chunk) => {
buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
let newline = buffer.indexOf('\n');
while (newline !== -1) {
const line = buffer.slice(0, newline);
buffer = buffer.slice(newline + 1);
queue = queue
.then(() => dispatch(server, line, output))
.catch((error) => {
const message = error instanceof Error ? error.message : 'Internal error';
write(output, errorResponse(0, INTERNAL_ERROR, message));
});
newline = buffer.indexOf('\n');
}
};
input.on('data', onData);
input.setEncoding?.('utf8');
return () => {
input.off?.('data', onData);
buffer = '';
};
}
async function dispatch(server, line, output) {
const text = line.trim();
if (text === '')
return;
let message;
try {
message = JSON.parse(text);
}
catch {
write(output, errorResponse(0, PARSE_ERROR, 'Request line is not valid JSON.'));
return;
}
const response = await server.handle(message);
if (response !== null)
write(output, response);
}
function write(output, response) {
output.write(`${JSON.stringify(response)}\n`);
}