Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions packages/cli/src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ export const add = new Command()

if (availableAgents.length === 0 && isNonInteractive && !agentArg) {
logger.break();
logger.success("All legacy agents are already installed.");
logger.log("Run without -y to add MCP.");
logger.success("All agents are already installed.");
logger.break();
process.exit(0);
}
Expand Down Expand Up @@ -111,6 +110,25 @@ export const add = new Command()

agentIntegration = validAgent;

// Handle MCP specially - it needs server configuration, not package installation
if (validAgent === "mcp") {
const mcpSpinner = spinner("Installing MCP server.").start();
const didInstall = await promptMcpInstall();
if (!didInstall) {
mcpSpinner.fail();
logger.break();
process.exit(1);
}
mcpSpinner.succeed();
logger.break();
logger.log(
`${highlighter.success("Success!")} MCP server has been configured.`,
);
logger.log("Restart your agents to activate.");
logger.break();
projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Adding 'mcp' via command-line argument triggers a false 'already installed' prompt because the code updates projectInfo.installedAgents with 'mcp' before checking if (installedAgents.length > 0). This causes the prompt to trigger even on fresh installation. If the user selects 'Replace', the just-installed MCP agent gets immediately uninstalled.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/add.ts, line 129:

<comment>Adding 'mcp' via command-line argument triggers a false 'already installed' prompt because the code updates `projectInfo.installedAgents` with 'mcp' before checking `if (installedAgents.length > 0)`. This causes the prompt to trigger even on fresh installation. If the user selects 'Replace', the just-installed MCP agent gets immediately uninstalled.</comment>

<file context>
@@ -111,6 +110,25 @@ export const add = new Command()
+          );
+          logger.log("Restart your agents to activate.");
+          logger.break();
+          projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
+        }
+
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Missing early exit after MCP installation. The success path within this if (validAgent === "mcp") block falls through to the generic agent installation flow below, which will attempt standard package installation for "mcp" and display duplicate success messages. The failure path correctly calls process.exit(1), so the success path should similarly exit.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/commands/add.ts, line 129:

<comment>Missing early exit after MCP installation. The success path within this `if (validAgent === "mcp")` block falls through to the generic agent installation flow below, which will attempt standard package installation for "mcp" and display duplicate success messages. The failure path correctly calls `process.exit(1)`, so the success path should similarly exit.</comment>

<file context>
@@ -111,6 +110,25 @@ export const add = new Command()
+          );
+          logger.log("Restart your agents to activate.");
+          logger.break();
+          projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
+        }
+
</file context>
Suggested change
projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
process.exit(0);
Fix with Cubic

}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing early exit after MCP installation causes unintended behavior

High Severity

After the MCP-specific installation block completes successfully at line 130, the code falls through to the generic agent installation flow instead of exiting. This causes getPackagesToInstall("mcp", false) at line 418 to return ["@react-grab/mcp"], which then gets installed as a local dev dependency via npm install -D @react-grab/mcp — this is unintended since MCP uses npx -y @react-grab/mcp --stdio on-demand. The user also sees duplicate success messages and a confusing "Adding MCP." spinner after configuration already completed.

Fix in Cursor Fix in Web


if (projectInfo.installedAgents.length > 0 && !isNonInteractive) {
const installedNames = formatInstalledAgentNames(
projectInfo.installedAgents,
Expand Down
17 changes: 9 additions & 8 deletions packages/cli/src/utils/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ export const AGENTS = [
"ami",
"droid",
"copilot",
"mcp",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MCP appears in interactive legacy agent selection list

Medium Severity

Adding "mcp" to AGENTS means it now appears in availableAgents used by the interactive agent selection prompt (the "legacy" flow in add.ts). If a user chooses "Legacy" connection mode and then selects "MCP" from the agent list, promptMcpInstall() is never called — the code instead tries a standard package installation flow, which is incorrect for MCP.

Fix in Cursor Fix in Web

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Adding "mcp" to the AGENTS array means it will appear in the interactive legacy agent selection prompt. If a user selects "MCP" through the interactive legacy flow, the code follows the standard package installation path instead of calling promptMcpInstall(). Consider filtering "mcp" out of the interactive agent choices (similar to how it's filtered from PROVIDERS), or adding MCP-specific handling in the interactive legacy flow.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/utils/templates.ts, line 11:

<comment>Adding `"mcp"` to the `AGENTS` array means it will appear in the interactive legacy agent selection prompt. If a user selects "MCP" through the interactive legacy flow, the code follows the standard package installation path instead of calling `promptMcpInstall()`. Consider filtering `"mcp"` out of the interactive agent choices (similar to how it's filtered from `PROVIDERS`), or adding MCP-specific handling in the interactive legacy flow.</comment>

<file context>
@@ -8,11 +8,12 @@ export const AGENTS = [
   "ami",
   "droid",
   "copilot",
+  "mcp",
 ] as const;
 
</file context>
Fix with Cubic

] as const;

export type Agent = (typeof AGENTS)[number];

export type AgentIntegration = Agent | "mcp" | "none";
export type AgentIntegration = Agent | "none";

export const AGENT_NAMES: Record<Agent, string> = {
"claude-code": "Claude Code",
Expand All @@ -24,17 +25,17 @@ export const AGENT_NAMES: Record<Agent, string> = {
ami: "Ami",
droid: "Droid",
copilot: "Copilot",
mcp: "MCP",
};

export const getAgentDisplayName = (agent: string): string => {
if (agent === "mcp") return "MCP";
if (agent in AGENT_NAMES) {
return AGENT_NAMES[agent as Agent];
}
return agent;
};

export const PROVIDERS = AGENTS.filter((agent) => agent !== "ami").map(
export const PROVIDERS = AGENTS.filter((agent) => agent !== "ami" && agent !== "mcp").map(
(agent) => `@react-grab/${agent}` as const,
);

Expand All @@ -49,7 +50,7 @@ export const NEXT_APP_ROUTER_SCRIPT = `{process.env.NODE_ENV === "development" &
export const NEXT_APP_ROUTER_SCRIPT_WITH_AGENT = (
agent: AgentIntegration,
): string => {
if (agent === "none") return NEXT_APP_ROUTER_SCRIPT;
if (agent === "none" || agent === "mcp") return NEXT_APP_ROUTER_SCRIPT;

return `{process.env.NODE_ENV === "development" && (
<Script
Expand Down Expand Up @@ -77,7 +78,7 @@ export const NEXT_PAGES_ROUTER_SCRIPT = `{process.env.NODE_ENV === "development"
export const NEXT_PAGES_ROUTER_SCRIPT_WITH_AGENT = (
agent: AgentIntegration,
): string => {
if (agent === "none") return NEXT_PAGES_ROUTER_SCRIPT;
if (agent === "none" || agent === "mcp") return NEXT_PAGES_ROUTER_SCRIPT;

return `{process.env.NODE_ENV === "development" && (
<Script
Expand All @@ -101,7 +102,7 @@ export const VITE_SCRIPT = `<script type="module">
</script>`;

export const VITE_SCRIPT_WITH_AGENT = (agent: AgentIntegration): string => {
if (agent === "none") return VITE_SCRIPT;
if (agent === "none" || agent === "mcp") return VITE_SCRIPT;

return `<script type="module">
if (import.meta.env.DEV) {
Expand All @@ -116,7 +117,7 @@ export const WEBPACK_IMPORT = `if (process.env.NODE_ENV === "development") {
}`;

export const WEBPACK_IMPORT_WITH_AGENT = (agent: AgentIntegration): string => {
if (agent === "none") return WEBPACK_IMPORT;
if (agent === "none" || agent === "mcp") return WEBPACK_IMPORT;

return `if (process.env.NODE_ENV === "development") {
import("react-grab");
Expand All @@ -131,7 +132,7 @@ export const TANSTACK_EFFECT = `useEffect(() => {
}, []);`;

export const TANSTACK_EFFECT_WITH_AGENT = (agent: AgentIntegration): string => {
if (agent === "none") return TANSTACK_EFFECT;
if (agent === "none" || agent === "mcp") return TANSTACK_EFFECT;

return `useEffect(() => {
if (import.meta.env.DEV) {
Expand Down