Skip to content

Commit 274be17

Browse files
committed
test(mcp): cover init-client's host and mode guards (#9526)
The five branch partials codecov/patch was holding the PR on, all in init-client's argument handling: no host at all, an unknown host, the --client spelling as well as --print, a host/mode pair the grid refuses, and the per-host remote caveat's absent side. Each asserts the message rather than merely the throw -- "unsupported client" without the list leaves a reader guessing at a five-value set they cannot see from outside the process.
1 parent 1f00f0c commit 274be17

1 file changed

Lines changed: 27 additions & 0 deletions

File tree

test/unit/mcp-cli-basics.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,33 @@ describe("loopover-mcp CLI — basics", () => {
125125
await expect(runInProcess(["init-client", "--print", "claude", "--mode", "carrier-pigeon"])).rejects.toThrow(/Unsupported mode.*stdio, remote, miner/);
126126
});
127127

128+
it("names the hosts it accepts when told nothing, or something it does not know (#9526)", async () => {
129+
// The error has to enumerate: "unsupported client" without the list leaves a reader guessing at a
130+
// five-value set they cannot see from the outside.
131+
await expect(runInProcess(["init-client"])).rejects.toThrow(/Pass --print with one of: codex, claude, cursor, mcp, vscode/);
132+
await expect(runInProcess(["init-client", "--print", "emacs"])).rejects.toThrow(/Unsupported client: emacs.*codex, claude, cursor, mcp, vscode/);
133+
});
134+
135+
it("accepts --client as well as --print, since both spellings reached this command (#9526)", async () => {
136+
const viaClient = JSON.parse(await runInProcess(["init-client", "--client", "cursor", "--json"])) as { client: string; snippet: string };
137+
expect(viaClient.client).toBe("cursor");
138+
expect(viaClient.snippet).toBe(clientConfigSnippet("cursor", "stdio"));
139+
});
140+
141+
it("refuses a host/mode pair it cannot vouch for, naming both (#9526)", async () => {
142+
// The generic `mcpServers` bucket is an unnamed host; guessing its remote dialect would print config
143+
// that fails on paste, and the stdio gateway already serves it the remote tools.
144+
await expect(runInProcess(["init-client", "--print", "mcp", "--mode", "remote"])).rejects.toThrow(/cannot connect over the Remote streamable-http mode/);
145+
});
146+
147+
it("carries the host's own remote caveat when it has one, and nothing when it does not (#9526)", async () => {
148+
const codex = JSON.parse(await runInProcess(["init-client", "--print", "codex", "--mode", "remote", "--json"])) as { notes: string[] };
149+
expect(codex.notes.join("\n")).toContain("experimental_use_rmcp_client");
150+
151+
const cursor = JSON.parse(await runInProcess(["init-client", "--print", "cursor", "--mode", "remote", "--json"])) as { notes: string[] };
152+
expect(cursor.notes.join("\n")).not.toContain("experimental_use_rmcp_client");
153+
});
154+
128155
it("prints human-approved agent profile instructions for supported MCP clients", async () => {
129156
const payload = JSON.parse(await runInProcess(["init-client", "--print", "codex", "--agent-profile", "miner-planner", "--json"])) as {
130157
agentProfile: {

0 commit comments

Comments
 (0)