修复 v1.0.1:MCP stdio 改用 JSON Lines 传输(修正握手超时);sync 支持 --allow-fail
This commit is contained in:
1 parent
4a02aee562
commit
48f9d9bd1f
3 files changed
+23
-27
No files matched your search
+10
-23
@@ -125,13 +125,11 @@ async function callTool(name, args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// JSON-RPC over stdio (MCP framing)
|
// JSON-RPC over stdio (MCP stdio transport = newline-delimited JSON)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function send(obj) {
|
function send(obj) {
|
||||||
const body = Buffer.from(JSON.stringify(obj), 'utf8');
|
process.stdout.write(`${JSON.stringify(obj)}\n`);
|
||||||
process.stdout.write(`Content-Length: ${body.length}\r\n\r\n`);
|
|
||||||
process.stdout.write(body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendError(id, code, message) {
|
function sendError(id, code, message) {
|
||||||
@@ -198,33 +196,22 @@ function handleMessage(msg) {
|
|||||||
// Notifications (e.g. notifications/initialized) are intentionally ignored.
|
// Notifications (e.g. notifications/initialized) are intentionally ignored.
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- framing parser ---------------------------------------------------------
|
// --- newline-delimited JSON parser -----------------------------------------
|
||||||
|
|
||||||
let buf = Buffer.alloc(0);
|
let buf = Buffer.alloc(0);
|
||||||
|
|
||||||
function tryParseFrame() {
|
|
||||||
const headerEnd = buf.indexOf('\r\n\r\n');
|
|
||||||
if (headerEnd === -1) return null;
|
|
||||||
const header = buf.subarray(0, headerEnd).toString('ascii');
|
|
||||||
const m = /Content-Length:\s*(\d+)/i.exec(header);
|
|
||||||
if (!m) return null;
|
|
||||||
const len = Number(m[1]);
|
|
||||||
const bodyStart = headerEnd + 4;
|
|
||||||
if (buf.length < bodyStart + len) return null;
|
|
||||||
const body = buf.subarray(bodyStart, bodyStart + len).toString('utf8');
|
|
||||||
buf = buf.subarray(bodyStart + len);
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pump() {
|
function pump() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const body = tryParseFrame();
|
const idx = buf.indexOf('\n');
|
||||||
if (body === null) break;
|
if (idx === -1) return;
|
||||||
|
const line = buf.subarray(0, idx).toString('utf8').replace(/\r$/, '');
|
||||||
|
buf = buf.subarray(idx + 1);
|
||||||
|
if (!line.trim()) continue;
|
||||||
let msg;
|
let msg;
|
||||||
try {
|
try {
|
||||||
msg = JSON.parse(body);
|
msg = JSON.parse(line);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[kimi-eyes] invalid JSON frame: ${err.message}`);
|
console.error(`[kimi-eyes] invalid JSON line: ${err.message}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
handleMessage(msg);
|
handleMessage(msg);
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kimi-eyes",
|
"name": "kimi-eyes",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Give non-multimodal models in Kimi Code the ability to analyze images and screenshots via a user-configured VLM (OpenAI-compatible or Anthropic protocol).",
|
"description": "Give non-multimodal models in Kimi Code the ability to analyze images and screenshots via a user-configured VLM (OpenAI-compatible or Anthropic protocol).",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"kimi",
|
"kimi",
|
||||||
@@ -35,6 +35,6 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"setup": "node setup.mjs",
|
"setup": "node setup.mjs",
|
||||||
"sync:models": "node scripts/sync-models.mjs",
|
"sync:models": "node scripts/sync-models.mjs",
|
||||||
"prepublishOnly": "node scripts/sync-models.mjs"
|
"prepublishOnly": "node scripts/sync-models.mjs --allow-fail"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+11
-2
@@ -33,11 +33,12 @@ const EXTRA_ENTRIES = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function parseArgs(argv) {
|
function parseArgs(argv) {
|
||||||
const args = { timeout: 180, out: DEFAULT_OUT, endpoint: DEFAULT_ENDPOINT };
|
const args = { timeout: 180, out: DEFAULT_OUT, endpoint: DEFAULT_ENDPOINT, allowFail: false };
|
||||||
for (let i = 0; i < argv.length; i++) {
|
for (let i = 0; i < argv.length; i++) {
|
||||||
if (argv[i] === '--timeout') args.timeout = Number(argv[++i]) || 180;
|
if (argv[i] === '--timeout') args.timeout = Number(argv[++i]) || 180;
|
||||||
else if (argv[i] === '--out') args.out = argv[++i];
|
else if (argv[i] === '--out') args.out = argv[++i];
|
||||||
else if (argv[i] === '--endpoint') args.endpoint = argv[++i];
|
else if (argv[i] === '--endpoint') args.endpoint = argv[++i];
|
||||||
|
else if (argv[i] === '--allow-fail') args.allowFail = true;
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
@@ -61,7 +62,15 @@ const args = parseArgs(process.argv.slice(2));
|
|||||||
const tmpFile = path.join(os.tmpdir(), `models-dev-${Date.now()}.json`);
|
const tmpFile = path.join(os.tmpdir(), `models-dev-${Date.now()}.json`);
|
||||||
|
|
||||||
console.log(`[sync-models] downloading ${args.endpoint} ...`);
|
console.log(`[sync-models] downloading ${args.endpoint} ...`);
|
||||||
download(args.endpoint, tmpFile, args.timeout);
|
try {
|
||||||
|
download(args.endpoint, tmpFile, args.timeout);
|
||||||
|
} catch (err) {
|
||||||
|
if (args.allowFail) {
|
||||||
|
console.error(`[sync-models] WARN: sync failed, keeping existing db: ${err.message.split('\n')[0]}`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
const raw = JSON.parse(fs.readFileSync(tmpFile, 'utf8'));
|
const raw = JSON.parse(fs.readFileSync(tmpFile, 'utf8'));
|
||||||
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
||||||
|
|||||||
Reference in new issue
Block a user