diff --git a/src/cli.ts b/src/cli.ts index 67c072dc047..021fadf880a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -310,15 +310,15 @@ export const createCli = ( // Incur's `mcp add` silently skips a valued option with no value and // swallows the next flag as the value: the registration succeeds without // the requested agent or command. Reject a trailing --agent/--command/-c, - // a value position occupied by another flag, and an empty `--flag=` form - // up front. + // a value position occupied by another flag, an empty `--flag=` form, + // and a separate empty-string value up front. const valued = ["--agent", "--command", "-c"]; let missingValue: string | undefined; for (let index = 0; index < command.length; index += 1) { const next = command[index + 1]; if ( valued.includes(command[index]!) && - (next === undefined || next.startsWith("-")) + (next === undefined || next === "" || next.startsWith("-")) ) { missingValue = command[index]; break; diff --git a/tests/boundary/cli/mcpAddOptionValidation.test.ts b/tests/boundary/cli/mcpAddOptionValidation.test.ts index f9ef5555883..7e8bbe7d068 100644 --- a/tests/boundary/cli/mcpAddOptionValidation.test.ts +++ b/tests/boundary/cli/mcpAddOptionValidation.test.ts @@ -46,6 +46,30 @@ cliTest("mcp add rejects valued options without a value", async ({ cli }) => { }); } + // A separate empty string is not a value either; without this check Incur + // silently registers with defaults. REA rejects it before registration. + for (const [flag, field] of [ + ["--agent", "agent"], + ["--command", "command"], + ["-c", "command"], + ] as const) { + const result = await run(["mcp", "add", flag, ""]); + expect(result.exitCode, result.stderr).toBe(1); + expect(result.json).toMatchObject({ + code: "VALIDATION_ERROR", + fieldErrors: expect.arrayContaining([ + expect.objectContaining({ + code: "invalid_value", + missing: false, + path: field, + }), + ]), + }); + await expect(access(settingsPath(home))).rejects.toMatchObject({ + code: "ENOENT", + }); + } + // Incur would swallow the following flag as the option value; REA rejects it. const swallowed = await run(["mcp", "add", "--command", "--agent", "amp"]); expect(swallowed.exitCode, swallowed.stderr).toBe(1);