From 48f9d9bd1f432eb1aaf87e4f05a605deb1ef5fa0 Mon Sep 17 00:00:00 2001 From: billowliu2 Date: Sun, 2 Aug 2026 02:21:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20v1.0.1=EF=BC=9AMCP=20stdio?= =?UTF-8?q?=20=E6=94=B9=E7=94=A8=20JSON=20Lines=20=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=EF=BC=88=E4=BF=AE=E6=AD=A3=E6=8F=A1=E6=89=8B=E8=B6=85=E6=97=B6?= =?UTF-8?q?=EF=BC=89=EF=BC=9Bsync=20=E6=94=AF=E6=8C=81=20--allow-fail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mcp/server.mjs | 33 ++++++++++----------------------- package.json | 4 ++-- scripts/sync-models.mjs | 13 +++++++++++-- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/mcp/server.mjs b/mcp/server.mjs index 48406c4..8b4c6d5 100644 --- a/mcp/server.mjs +++ b/mcp/server.mjs @@ -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) { - const body = Buffer.from(JSON.stringify(obj), 'utf8'); - process.stdout.write(`Content-Length: ${body.length}\r\n\r\n`); - process.stdout.write(body); + process.stdout.write(`${JSON.stringify(obj)}\n`); } function sendError(id, code, message) { @@ -198,33 +196,22 @@ function handleMessage(msg) { // Notifications (e.g. notifications/initialized) are intentionally ignored. } -// --- framing parser --------------------------------------------------------- +// --- newline-delimited JSON parser ----------------------------------------- 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() { for (;;) { - const body = tryParseFrame(); - if (body === null) break; + const idx = buf.indexOf('\n'); + 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; try { - msg = JSON.parse(body); + msg = JSON.parse(line); } catch (err) { - console.error(`[kimi-eyes] invalid JSON frame: ${err.message}`); + console.error(`[kimi-eyes] invalid JSON line: ${err.message}`); continue; } handleMessage(msg); diff --git a/package.json b/package.json index 8d6cf21..aa99562 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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).", "keywords": [ "kimi", @@ -35,6 +35,6 @@ "scripts": { "setup": "node setup.mjs", "sync:models": "node scripts/sync-models.mjs", - "prepublishOnly": "node scripts/sync-models.mjs" + "prepublishOnly": "node scripts/sync-models.mjs --allow-fail" } } diff --git a/scripts/sync-models.mjs b/scripts/sync-models.mjs index 579ce7a..b8005b7 100644 --- a/scripts/sync-models.mjs +++ b/scripts/sync-models.mjs @@ -33,11 +33,12 @@ const EXTRA_ENTRIES = { }; 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++) { if (argv[i] === '--timeout') args.timeout = Number(argv[++i]) || 180; else if (argv[i] === '--out') args.out = argv[++i]; else if (argv[i] === '--endpoint') args.endpoint = argv[++i]; + else if (argv[i] === '--allow-fail') args.allowFail = true; } return args; } @@ -61,7 +62,15 @@ const args = parseArgs(process.argv.slice(2)); const tmpFile = path.join(os.tmpdir(), `models-dev-${Date.now()}.json`); 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')); if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {