From 0941e596767cc20d7869bb654e10b7c533d89b0b Mon Sep 17 00:00:00 2001 From: aiirvizionz Date: Sat, 18 Jul 2026 16:52:42 -0600 Subject: [PATCH] fix(mcp): reject missing flag values --- src/integrations.mjs | 30 ++++++++++++++++++++++++++---- test/mcp.test.mjs | 7 +++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/integrations.mjs b/src/integrations.mjs index f50e7e0..cf56069 100644 --- a/src/integrations.mjs +++ b/src/integrations.mjs @@ -20,6 +20,12 @@ function headerName(header) { return i === -1 ? null : String(header).slice(0, i).trim(); } +function flagValue(rest, index, flag) { + const value = rest[index + 1]; + if (value === undefined || value === "--") return { error: `${flag} requires a value` }; + return { value }; +} + /** Parse `/mcp` tokens (after the `mcp` word) into { list } | { spec } | { error }. */ export function parseMcp(tokens) { const verb = tokens[0]; @@ -32,10 +38,26 @@ export function parseMcp(tokens) { for (let i = 0; i < rest.length; i++) { const t = rest[i]; if (t === "--") { cmdParts = rest.slice(i + 1); break; } - else if (t === "--name") name = rest[++i]; - else if (t === "-t" || t === "--transport") transport = rest[++i]; - else if (t === "-e" || t === "--env") env.push(splitKV(rest[++i])); - else if (t === "-H" || t === "--header") headers.push(rest[++i]); + else if (t === "--name") { + const next = flagValue(rest, i, t); + if (next.error) return next; + name = next.value; i++; + } + else if (t === "-t" || t === "--transport") { + const next = flagValue(rest, i, t); + if (next.error) return next; + transport = next.value; i++; + } + else if (t === "-e" || t === "--env") { + const next = flagValue(rest, i, t); + if (next.error) return next; + env.push(splitKV(next.value)); i++; + } + else if (t === "-H" || t === "--header") { + const next = flagValue(rest, i, t); + if (next.error) return next; + headers.push(next.value); i++; + } else positional.push(t); } diff --git a/test/mcp.test.mjs b/test/mcp.test.mjs index bd0a6eb..bdd12d0 100644 --- a/test/mcp.test.mjs +++ b/test/mcp.test.mjs @@ -84,6 +84,13 @@ test("parseMcp: env and header flags reject empty names", () => { assert.deepEqual(parseMcp(["install", "https://x.dev/mcp", "--env", "EMPTY="]).spec.env, [["EMPTY", ""]]); }); +test("parseMcp: flags that need values reject missing values", () => { + assert.match(parseMcp(["install", "https://x.dev/mcp", "--name"]).error, /--name requires a value/); + assert.match(parseMcp(["install", "https://x.dev/mcp", "--transport", "--"]).error, /--transport requires a value/); + assert.match(parseMcp(["install", "https://x.dev/mcp", "--env"]).error, /--env requires a value/); + assert.match(parseMcp(["install", "https://x.dev/mcp", "--header"]).error, /--header requires a value/); +}); + test("runMcpAdd summarizes added / skipped / not-installed", async () => { const spec = { name: "s", target: "https://x.dev/mcp", env: [], headers: ["A: b"] }; const plan = planMcpAdd(spec, { installedSet: new Set(["claude", "opencode"]) }); // gemini/codex not installed; codex also skips