Files
playbook/antigravity-awesome-skills/tools/lib/aas-v1/mcp/stdio.js
T
2026-07-18 00:02:59 +00:00

99 lines
3.1 KiB
JavaScript

"use strict";
const { MAX_LINE_BYTES, StrictJsonError, parseStrictJsonLine } = require("./strict-json");
const MAX_PENDING_REQUESTS = 32;
function parseErrorResponse(code = "AAS_MCP_PARSE_FAILED") {
return {
jsonrpc: "2.0",
id: null,
error: { code: -32700, message: "Parse error", data: { code } },
};
}
function writeJsonLine(stream, value) {
stream.write(`${JSON.stringify(value)}\n`);
}
function runStdio(server, options = {}) {
const input = options.input || process.stdin;
const output = options.output || process.stdout;
const diagnostics = options.diagnostics || process.stderr;
let pending = Buffer.alloc(0);
let discardingOversizedLine = false;
let pendingRequests = 0;
let sequence = Promise.resolve();
function enqueue(line) {
if (pendingRequests >= MAX_PENDING_REQUESTS) {
writeJsonLine(output, {
jsonrpc: "2.0",
id: null,
error: { code: -32000, message: "Request queue full", data: { code: "AAS_MCP_QUEUE_FULL" } },
});
return;
}
pendingRequests += 1;
sequence = sequence.then(async () => {
let request;
try {
request = parseStrictJsonLine(line);
} catch (error) {
const code = error instanceof StrictJsonError ? error.code : "AAS_MCP_PARSE_FAILED";
writeJsonLine(output, parseErrorResponse(code));
return;
}
try {
const response = await server.handle(request);
if (response) writeJsonLine(output, response);
} catch {
writeJsonLine(output, {
jsonrpc: "2.0",
id: Object.hasOwn(request, "id") ? request.id : null,
error: { code: -32603, message: "Internal error" },
});
diagnostics.write("AAS MCP internal error (details redacted)\n");
}
}).finally(() => { pendingRequests -= 1; });
}
input.on("data", (chunk) => {
let buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
while (buffer.length) {
const newline = buffer.indexOf(0x0a);
const part = newline === -1 ? buffer : buffer.subarray(0, newline);
buffer = newline === -1 ? Buffer.alloc(0) : buffer.subarray(newline + 1);
if (discardingOversizedLine) {
if (newline !== -1) {
discardingOversizedLine = false;
enqueue(Buffer.alloc(MAX_LINE_BYTES + 1));
}
continue;
}
const framedBytes = pending.length + part.length + (newline === -1 ? 0 : 1);
if (framedBytes > MAX_LINE_BYTES) {
pending = Buffer.alloc(0);
if (newline === -1) discardingOversizedLine = true;
else enqueue(Buffer.alloc(MAX_LINE_BYTES + 1));
continue;
}
pending = Buffer.concat([pending, part]);
if (newline !== -1) {
if (pending[pending.length - 1] === 0x0d) pending = pending.subarray(0, -1);
enqueue(pending);
pending = Buffer.alloc(0);
}
}
});
input.on("end", () => {
if (discardingOversizedLine) enqueue(Buffer.alloc(MAX_LINE_BYTES + 1));
else if (pending.length) enqueue(pending);
});
return { completed: () => sequence };
}
module.exports = { MAX_PENDING_REQUESTS, parseErrorResponse, runStdio, writeJsonLine };