Skip to content

feat(mcp): add mcp connect and disconnect commands#178

Open
sarthakNITT wants to merge 2 commits into
InsForge:mainfrom
sarthakNITT:feat/real_time_mcp_connection_status
Open

feat(mcp): add mcp connect and disconnect commands#178
sarthakNITT wants to merge 2 commits into
InsForge:mainfrom
sarthakNITT:feat/real_time_mcp_connection_status

Conversation

@sarthakNITT

@sarthakNITT sarthakNITT commented Jun 24, 2026

Copy link
Copy Markdown

Adds two new top-level CLI commands connect and disconnect for managing the InsForge MCP server entry in local AI coding agent config files.

reference - InsForge/InsForge#1581

Why:
Previously, users had to manually edit config files (e.g. .cursor/mcp.json) to wire up InsForge MCP. These commands automate that entirely after a project is linked with npx @insforge/cli link.

Changes

New files:

  • src/commands/mcp/connect.ts - connect [provider] command: writes the InsForge MCP server entry into the provider's config file and marks the backend status as connected
  • src/commands/mcp/disconnect.ts - disconnect [provider] command: removes the InsForge MCP entry from the provider's config file and marks backend status as disconnected. Without a provider arg, cleans up all known config files
  • src/lib/mcp-config.ts - core logic for reading/writing provider MCP config files, building the MCP server config from linked project credentials
  • src/lib/mcp-config.test.ts - unit tests for mcp-config helpers

Modified:

  • src/index.ts - registers the two new commands
  • src/lib/api/oss.ts - adds updateMcpConnectionStatus() to call POST /api/usage/mcp/status on the linked backend
    README.md - expands the MCP Connection section with full command reference, provider table, and config file paths

Supported providers - cursor, claude-code, windsurf, cline, roo, codex, antigravity.

Usage:

npx @insforge/cli connect cursor
npx @insforge/cli disconnect cursor
npx @insforge/cli disconnect # removes from all known configs


Summary by cubic

Adds connect and disconnect CLI commands to auto-configure the InsForge MCP server in local agent configs and keep backend connection status in sync. You can also run them without a linked project by passing an API key and base URL.

  • New Features

    • npx @insforge/cli connect [provider] and disconnect [provider] manage only the insforge MCP entry (default provider: cursor).
    • Works without a linked project via --api-key and --api-base-url; otherwise reads .insforge/project.json.
    • Reports status with updateMcpConnectionStatus('connected'|'disconnected'), using provided creds when passed.
    • Supports --json output; config files are written with 0600 perms.
    • Providers: cursor, claude-code (alias claude), windsurf, cline, roo, codex, antigravity; paths handled in src/lib/mcp-config.ts.
  • Migration

    • Link a project or pass creds: npx @insforge/cli link or use --api-key and --api-base-url.
    • Use: npx @insforge/cli connect cursor, npx @insforge/cli disconnect cursor, or npx @insforge/cli disconnect to remove from all supported configs.

Written for commit 254221d. Summary will update on new commits.

Review in cubic

Note

Add mcp connect and mcp disconnect CLI commands

  • Adds connect [provider] command that writes or updates an insforge MCP server entry (with Authorization and x-api-key headers) in the target provider's local config file, then marks backend MCP status as connected.
  • Adds disconnect [provider] command that removes the insforge entry from one or all supported provider config files and marks backend MCP status as disconnected.
  • Supports 7 providers (cursor, claude-code, windsurf, cline, roo, codex, antigravity) with alias resolution (e.g. claudeclaude-code); config paths are resolved per-provider relative to cwd.
  • Both commands accept optional --api-key and --api-base-url flags for use without a linked project, and emit JSON or human-readable output including the config path and whether the file was changed.
  • Adds updateMcpConnectionStatus in oss.ts to POST connection status updates to /api/usage/mcp/status.

Macroscope summarized 254221d.

Summary by CodeRabbit

  • New Features

    • Added MCP connect/disconnect commands to link or remove provider connections from the CLI.
    • Support now includes provider-specific MCP config handling and a new connection status update.
    • Added documentation with example commands and JSON output.
  • Bug Fixes

    • Preserves existing MCP configuration entries while adding or removing the InsForge connection.
    • Improves error handling and reporting for MCP command workflows.
  • Tests

    • Added coverage for MCP config updates and CLI connect/disconnect behavior.

Copilot AI review requested due to automatic review settings June 24, 2026 21:48
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds MCP connect and disconnect CLI commands, shared MCP config helpers, an OSS API for MCP status updates, tests for config and command flows, a README section for MCP Connection, and a default .antigravity/mcp.json file.

Changes

MCP CLI commands

Layer / File(s) Summary
Config helpers and persistence
.antigravity/mcp.json, src/lib/mcp-config.ts, src/lib/mcp-config.test.ts
Provider constants, path utilities, JSON load/write helpers, MCP config updates, and helper tests are added.
Connect command and status update
src/lib/api/oss.ts, src/commands/mcp/connect.ts, src/commands/mcp/mcp.test.ts
The connect command loads the linked project, parses the provider, writes the MCP server entry, posts connected status, and is covered by the CLI JSON-path test.
Disconnect command
src/commands/mcp/disconnect.ts, src/commands/mcp/mcp.test.ts
The disconnect command targets one or all configured providers, removes only the insforge entry, posts disconnected status, and is covered by the disconnect CLI tests.
Command wiring and docs
src/commands/mcp/index.ts, src/index.ts, README.md
The MCP subcommand group is registered in the CLI entrypoint, and the README adds connect/disconnect usage and provider config locations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

🐰 I hopped through MCP at dawn,
and found the connect and disconnect drawn.
One insforge key hops in, one hops away,
while status carrots brighten the day.
Crrunch! The CLI now knows the way.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding MCP connect and disconnect commands.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@agent-zhang-beihai

Copy link
Copy Markdown

Thanks for the PR, @sarthakNITT! A quick note on our workflow: we ask contributors to open an issue first, get it assigned, then submit a PR that links it (e.g. "Closes #123"). This PR isn't linked to any issue. It'll still be reviewed, but please open an issue and claim it (comment that you'd like it assigned to you) so the work is tracked.

@agent-zhang-beihai agent-zhang-beihai Bot added the needs-issue PR isn't linked to any issue — open and claim an issue first, then link it label Jun 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@agent-zhang-beihai agent-zhang-beihai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review — feat(mcp): add mcp connect and disconnect commands

The overall structure is clean and the happy-path logic is sound. Three issues need resolution before merge.


🔴 Critical

1. Stray .antigravity/mcp.json committed to the CLI repository

File: .antigravity/mcp.json

{
  "mcpServers": {}
}

This file is almost certainly a leftover from local testing — the author ran connect antigravity inside the CLI's own source directory. It should not be committed:

  • It will be bundled into the npm package and land in every consumer's node_modules/@insforge/cli/.antigravity/mcp.json, an unexpected side-effect.
  • If a developer ever runs disconnect (bare/all) from the CLI source directory, this committed file will be silently modified, producing a dirty working tree.
  • .antigravity/ should be added to .gitignore alongside the other provider config directories (.cursor/, .mcp.json, etc.).

Fix: delete .antigravity/mcp.json, add .antigravity/ to .gitignore.


🟠 Important

2. Bare disconnect (all providers) aborts on the first malformed config, leaving partial state

File: src/commands/mcp/disconnect.ts, line 22

const results = providers.map((provider) => disconnectMcpProvider(provider));
await updateMcpConnectionStatus('disconnected');

Array.prototype.map is synchronous and throws immediately when disconnectMcpProvider raises a CLIError (which it does when a config file exists but contains invalid JSON). If .cline/mcp.json is malformed, providers listed after cline (roo, codex, antigravity) are never touched and updateMcpConnectionStatus is never called. The command surfaces an error, leaving local and backend state in an inconsistent, partially-cleaned-up condition.

Fix: wrap each call in a per-provider try/catch (collect errors, continue), report them in aggregate, and only call updateMcpConnectionStatus after the full sweep. Or at minimum document and accept the behaviour.

3. connectMcpProvider always rewrites the file, even when changed === false

File: src/lib/mcp-config.ts, lines 68–71

const changed = JSON.stringify(existingServers[MCP_SERVER_NAME]) !== JSON.stringify(server);

config.mcpServers = { ...existingServers, [MCP_SERVER_NAME]: server };
writeMcpJson(path, config); // ← unconditional

writeMcpJson is called regardless of changed. A no-op connect still modifies the file's mtime, which can trigger IDE file-watchers (notably Claude Code, which watches .mcp.json). The changed flag is already computed — gating the write on it is a one-liner fix:

if (changed) {
  config.mcpServers = { ...existingServers, [MCP_SERVER_NAME]: server };
  writeMcpJson(path, config);
}

🟡 Minor

4. JSON.stringify change detection is key-order sensitive

File: src/lib/mcp-config.ts, line 64

const changed = JSON.stringify(existingServers[MCP_SERVER_NAME]) !== JSON.stringify(server);

If an existing insforge entry was written by an external tool with keys in a different order (e.g., x-api-key before Authorization), this evaluates to true and triggers a rewrite even though the values are identical. Use a field-by-field comparison or stable serialisation (sort keys) for reliability.


🔵 Cleanup

5. ProviderConfig interface wraps a single string field

File: src/lib/mcp-config.ts, lines 23–25

interface ProviderConfig {
  path: string;
}
const PROVIDER_CONFIGS: Record<McpProvider, ProviderConfig> = { ... };
// always accessed as PROVIDER_CONFIGS[provider].path

The interface adds an indirection layer with no current benefit. Record<McpProvider, string> is simpler and just as clear; the existing getMcpConfigPath helper already encapsulates all access.


Two items are required before merge: the committed stray file (1) and the partial-disconnect correctness issue (2). Issue (3) is a meaningful side-effect fix and should also be addressed. (4) and (5) can be taken in a follow-up if preferred.

@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown

Greptile Summary

Adds connect [provider] and disconnect [provider] top-level CLI commands that automate writing and removing the InsForge MCP server entry from supported provider config files (Cursor, Claude Code, Windsurf, Cline, Roo, Codex, Antigravity), replacing what previously required manual JSON edits. A new updateMcpConnectionStatus API call reports the change back to the linked backend.

  • src/lib/mcp-config.ts handles all file I/O: reads the existing config, merges/removes the insforge key while preserving other servers, and writes with mode: 0o600 — though that permission only applies to newly created files, leaving API keys in pre-existing configs with their original (potentially broader) permissions.
  • src/commands/mcp/connect.ts / disconnect.ts support both linked-project mode and explicit --api-key/--api-base-url credentials; bare disconnect (no provider arg) iterates all known providers.
  • .antigravity/mcp.json (empty mcpServers: {}) appears to be a test artifact committed to the repo during development.

Confidence Score: 4/5

Safe to merge after resolving the file-permissions gap in writeMcpJson; all other logic is sound.

The writeMcpJson function writes API keys to disk with mode: 0o600, but that mode is only applied when the file is newly created. On systems where a provider config file already existed with default permissions, the credentials written by connect will be readable by any local user. The fix is a one-line chmodSync after the write. Everything else — command structure, credential flow, disconnect logic, and test coverage — looks correct.

src/lib/mcp-config.ts — the writeMcpJson function needs a chmodSync call to enforce 0o600 on pre-existing files.

Important Files Changed

Filename Overview
src/lib/mcp-config.ts Core read/write helpers for provider MCP configs. writeMcpJson uses mode: 0o600 but that only applies to new files — existing files with broader permissions are not restricted after a write, leaving API keys readable.
src/commands/mcp/connect.ts Implements the connect [provider] command with project-linked and explicit-credentials modes; logic is clear and consistent with existing CLI patterns.
src/commands/mcp/disconnect.ts Implements disconnect [provider] with single- and all-provider modes; consistent with connect.ts; bare disconnect correctly iterates MCP_PROVIDERS.
src/lib/api/oss.ts Adds updateMcpConnectionStatus with both explicit-credentials and project-linked paths; the raw-fetch branch has its own error handling, while the ossFetch branch will produce a generic 404 on older backends.
.antigravity/mcp.json Empty provider config file committed to the repo — looks like a test artifact from running connect/disconnect in the working directory during development.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant CLI as connect/disconnect cmd
    participant Config as mcp-config.ts
    participant FS as File System
    participant API as Backend API

    User->>CLI: "npx @insforge/cli connect cursor"
    CLI->>CLI: parseMcpProvider("cursor")
    CLI->>CLI: getProjectConfig() or --api-key/--api-base-url
    CLI->>Config: connectMcpProvider(provider, credentials)
    Config->>FS: readMcpJson(.cursor/mcp.json)
    FS-->>Config: "existing config (or {})"
    Config->>Config: build insforge server entry
    Config->>FS: writeMcpJson (mode 0o600, new files only)
    Config-->>CLI: "{ changed, path, provider }"
    CLI->>API: updateMcpConnectionStatus("connected")
    API-->>CLI: 200 OK
    CLI->>User: Connected cursor to InsForge MCP

    User->>CLI: "npx @insforge/cli disconnect"
    CLI->>CLI: "providers = MCP_PROVIDERS (all)"
    loop each provider
        CLI->>Config: disconnectMcpProvider(provider)
        Config->>FS: readMcpJson(provider config)
        Config->>FS: "delete insforge key & writeMcpJson"
    end
    CLI->>API: updateMcpConnectionStatus("disconnected")
    API-->>CLI: 200 OK
    CLI->>User: Disconnected from all known configs
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant CLI as connect/disconnect cmd
    participant Config as mcp-config.ts
    participant FS as File System
    participant API as Backend API

    User->>CLI: "npx @insforge/cli connect cursor"
    CLI->>CLI: parseMcpProvider("cursor")
    CLI->>CLI: getProjectConfig() or --api-key/--api-base-url
    CLI->>Config: connectMcpProvider(provider, credentials)
    Config->>FS: readMcpJson(.cursor/mcp.json)
    FS-->>Config: "existing config (or {})"
    Config->>Config: build insforge server entry
    Config->>FS: writeMcpJson (mode 0o600, new files only)
    Config-->>CLI: "{ changed, path, provider }"
    CLI->>API: updateMcpConnectionStatus("connected")
    API-->>CLI: 200 OK
    CLI->>User: Connected cursor to InsForge MCP

    User->>CLI: "npx @insforge/cli disconnect"
    CLI->>CLI: "providers = MCP_PROVIDERS (all)"
    loop each provider
        CLI->>Config: disconnectMcpProvider(provider)
        Config->>FS: readMcpJson(provider config)
        Config->>FS: "delete insforge key & writeMcpJson"
    end
    CLI->>API: updateMcpConnectionStatus("disconnected")
    API-->>CLI: 200 OK
    CLI->>User: Disconnected from all known configs
Loading

Reviews (2): Last reviewed commit: "feat: allow mcp connect/disconnect using..." | Re-trigger Greptile

Comment thread src/commands/mcp/connect.ts Outdated
Comment on lines +22 to +23
const result = connectMcpProvider(provider, project);
await updateMcpConnectionStatus('connected');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Local file written but command reports failure on backend error

connectMcpProvider writes the config file on line 22 before updateMcpConnectionStatus is called on line 23. If ossFetch throws (network error, older self-hosted backend without the /api/usage/mcp/status endpoint, etc.), handleError reports an error to the user even though the local config file was already successfully modified. The user sees a failure, is left confused about whether the connect actually took effect, and may re-run the command unnecessarily.

The same race exists in disconnect.ts at the equivalent lines. Consider wrapping updateMcpConnectionStatus in a try/catch that logs a warning but doesn't fail the command, since the local-file mutation is the core user-visible outcome.

Comment thread src/lib/mcp-config.ts
Comment on lines +67 to +73
const changed = JSON.stringify(existingServers[MCP_SERVER_NAME]) !== JSON.stringify(server);

config.mcpServers = {
...existingServers,
[MCP_SERVER_NAME]: server,
};
writeMcpJson(path, config);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 File is always written even when the entry is unchanged

changed is computed on line 67 to detect whether the InsForge entry differs from the existing one, but writeMcpJson is called unconditionally on line 73 regardless of the result. When the entry is already up to date the file is still rewritten, changing its mtime and potentially triggering editor reloads or hot-reload loops in dev environments. The write should be guarded by if (changed).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread src/lib/api/oss.ts Outdated
Comment on lines +55 to +59
export async function updateMcpConnectionStatus(status: McpConnectionStatus): Promise<void> {
await ossFetch('/api/usage/mcp/status', {
method: 'POST',
body: JSON.stringify({ status }),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 No friendly 404 handler for the new MCP status endpoint

ossFetch has specific friendly messages for 404s on /api/compute, /api/payments, /api/database/migrations, /api/ai, and /api/memory paths (lines 153–172), but nothing for /api/usage/mcp/status. Self-hosted instances running an older backend that doesn't include this endpoint will get a generic OSS request failed: 404 error, which gives the user no actionable guidance. A path-specific 404 message (similar to the others) would significantly improve the experience for self-hosted users.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/commands/mcp/disconnect.ts`:
- Around line 21-23: Avoid clearing the shared MCP status during a
single-provider disconnect in disconnectMcpProvider handling. Update the logic
around the providers map and updateMcpConnectionStatus so it only sets
disconnected when all MCP providers have been removed, and keep the shared
status unchanged when disconnectMcpProvider is called for just one provider
while others still remain connected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: efb04659-2936-40be-83d9-a05b2756bafa

📥 Commits

Reviewing files that changed from the base of the PR and between 13a7935 and 6cde190.

📒 Files selected for processing (10)
  • .antigravity/mcp.json
  • README.md
  • src/commands/mcp/connect.ts
  • src/commands/mcp/disconnect.ts
  • src/commands/mcp/index.ts
  • src/commands/mcp/mcp.test.ts
  • src/index.ts
  • src/lib/api/oss.ts
  • src/lib/mcp-config.test.ts
  • src/lib/mcp-config.ts

Comment thread src/commands/mcp/disconnect.ts Outdated
Comment on lines +21 to +23
const providers = providerArg ? [parseMcpProvider(providerArg)] : MCP_PROVIDERS;
const results = providers.map((provider) => disconnectMcpProvider(provider));
await updateMcpConnectionStatus('disconnected');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map relevant files first
git ls-files 'src/commands/mcp/*' 'src/*mcp*' 'src/**/*mcp*' | sed -n '1,200p'

echo
echo '--- outline src/commands/mcp/disconnect.ts ---'
ast-grep outline src/commands/mcp/disconnect.ts --view expanded || true

echo
echo '--- search for updateMcpConnectionStatus and disconnectMcpProvider ---'
rg -n "updateMcpConnectionStatus|disconnectMcpProvider|MCP_PROVIDERS|parseMcpProvider" src

Repository: InsForge/CLI

Length of output: 3023


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the target file and related helpers with line numbers
for f in src/commands/mcp/disconnect.ts; do
  echo "=== $f ==="
  wc -l "$f"
  cat -n "$f"
  echo
done

echo "=== candidate files for connection status helpers ==="
rg -n "function updateMcpConnectionStatus|const updateMcpConnectionStatus|export .*updateMcpConnectionStatus|disconnectMcpProvider" src -A 4 -B 4

Repository: InsForge/CLI

Length of output: 7738


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether connection status is maintained per provider or as a single backend value
rg -n "connection status|connected|disconnected|MCP_PROVIDERS|insforge" src -A 3 -B 3

echo
echo '--- any aggregated status logic ---'
rg -n "some\\(|every\\(|filter\\(|length === 0|provider.*status|status.*provider" src/commands src -A 3 -B 3

Repository: InsForge/CLI

Length of output: 50369


Avoid clearing the shared MCP status on single-provider disconnect.
src/commands/mcp/disconnect.ts:21-23 still posts disconnected when only one provider is removed. If this status is meant to reflect whether any MCP provider remains connected, update it only after the last provider entry is cleared; otherwise it reports disconnected while other providers still have insforge configured.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/mcp/disconnect.ts` around lines 21 - 23, Avoid clearing the
shared MCP status during a single-provider disconnect in disconnectMcpProvider
handling. Update the logic around the providers map and
updateMcpConnectionStatus so it only sets disconnected when all MCP providers
have been removed, and keep the shared status unchanged when
disconnectMcpProvider is called for just one provider while others still remain
connected.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

8 issues found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/mcp-config.ts">

<violation number="1" location="src/lib/mcp-config.ts:73">
P2: The `writeMcpJson` call is unconditional even though `changed` is computed to detect whether the entry differs. When the InsForge entry is already up to date, this unnecessarily rewrites the file, changing its mtime and potentially triggering editor file-watcher reloads or hot-reload loops. Guard the write with `if (changed)` since the result already correctly reflects whether a modification occurred.</violation>

<violation number="2" location="src/lib/mcp-config.ts:135">
P1: Config files containing API keys may retain overly broad permissions when they already exist, because `writeFileSync` mode only applies on file creation.</violation>
</file>

<file name=".antigravity/mcp.json">

<violation number="1" location=".antigravity/mcp.json:1">
P1: Provider MCP config file `.antigravity/mcp.json` is committed in-repo and will be mutated by `connect` with sensitive API credentials, creating accidental commit risk.</violation>
</file>

<file name="src/commands/mcp/disconnect.ts">

<violation number="1" location="src/commands/mcp/disconnect.ts:22">
P2: Bulk disconnect is not fault-tolerant: a single malformed or unreadable provider config file aborts the entire cleanup and leaves remaining providers untouched. Each provider operation should be isolated in a try/catch so that one bad config doesn't prevent cleanup of the others.</violation>
</file>

<file name="src/lib/api/oss.ts">

<violation number="1" location="src/lib/api/oss.ts:55">
P2: Missing backward-compatibility / 404 handling for the new /api/usage/mcp/status endpoint in ossFetch. On older or self-hosted backends that do not yet implement this route, connect/disconnect flows will surface a generic 404 error instead of a clear feature-unavailable message (or graceful fallback), and the local config will have already been updated before the failure.</violation>
</file>

<file name="src/lib/mcp-config.test.ts">

<violation number="1" location="src/lib/mcp-config.test.ts:60">
P2: Missing test for disconnectMcpProvider edge case when no prior connection exists</violation>

<violation number="2" location="src/lib/mcp-config.test.ts:64">
P2: Disconnect test does not verify that non-insforge MCP entries survive disconnection</violation>
</file>

<file name="src/commands/mcp/connect.ts">

<violation number="1" location="src/commands/mcp/connect.ts:22">
P1: Non-atomic connect flow leaves local MCP config and backend status inconsistent when backend update fails</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .antigravity/mcp.json
@@ -0,0 +1,3 @@
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Provider MCP config file .antigravity/mcp.json is committed in-repo and will be mutated by connect with sensitive API credentials, creating accidental commit risk.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .antigravity/mcp.json:

<comment>Provider MCP config file `.antigravity/mcp.json` is committed in-repo and will be mutated by `connect` with sensitive API credentials, creating accidental commit risk.</comment>

<file context>
@@ -0,0 +1,3 @@
+{
+  "mcpServers": {}
+}
</file context>

Comment thread src/lib/mcp-config.ts

function writeMcpJson(path: string, config: JsonObject): void {
mkdirSync(dirname(path), { recursive: true });
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Config files containing API keys may retain overly broad permissions when they already exist, because writeFileSync mode only applies on file creation.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/mcp-config.ts, line 135:

<comment>Config files containing API keys may retain overly broad permissions when they already exist, because `writeFileSync` mode only applies on file creation.</comment>

<file context>
@@ -0,0 +1,140 @@
+
+function writeMcpJson(path: string, config: JsonObject): void {
+  mkdirSync(dirname(path), { recursive: true });
+  writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
+}
+
</file context>

Comment thread src/commands/mcp/connect.ts Outdated
if (!project) throw new ProjectNotLinkedError();

const provider = parseMcpProvider(providerArg ?? 'cursor');
const result = connectMcpProvider(provider, project);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Non-atomic connect flow leaves local MCP config and backend status inconsistent when backend update fails

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

<comment>Non-atomic connect flow leaves local MCP config and backend status inconsistent when backend update fails</comment>

<file context>
@@ -0,0 +1,55 @@
+        if (!project) throw new ProjectNotLinkedError();
+
+        const provider = parseMcpProvider(providerArg ?? 'cursor');
+        const result = connectMcpProvider(provider, project);
+        await updateMcpConnectionStatus('connected');
+        captureEvent(project.project_id, 'cli_mcp_connect', {
</file context>

Comment thread src/lib/mcp-config.ts
...existingServers,
[MCP_SERVER_NAME]: server,
};
writeMcpJson(path, config);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The writeMcpJson call is unconditional even though changed is computed to detect whether the entry differs. When the InsForge entry is already up to date, this unnecessarily rewrites the file, changing its mtime and potentially triggering editor file-watcher reloads or hot-reload loops. Guard the write with if (changed) since the result already correctly reflects whether a modification occurred.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/mcp-config.ts, line 73:

<comment>The `writeMcpJson` call is unconditional even though `changed` is computed to detect whether the entry differs. When the InsForge entry is already up to date, this unnecessarily rewrites the file, changing its mtime and potentially triggering editor file-watcher reloads or hot-reload loops. Guard the write with `if (changed)` since the result already correctly reflects whether a modification occurred.</comment>

<file context>
@@ -0,0 +1,140 @@
+    ...existingServers,
+    [MCP_SERVER_NAME]: server,
+  };
+  writeMcpJson(path, config);
+
+  return {
</file context>

if (!project) throw new ProjectNotLinkedError();

const providers = providerArg ? [parseMcpProvider(providerArg)] : MCP_PROVIDERS;
const results = providers.map((provider) => disconnectMcpProvider(provider));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Bulk disconnect is not fault-tolerant: a single malformed or unreadable provider config file aborts the entire cleanup and leaves remaining providers untouched. Each provider operation should be isolated in a try/catch so that one bad config doesn't prevent cleanup of the others.

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

<comment>Bulk disconnect is not fault-tolerant: a single malformed or unreadable provider config file aborts the entire cleanup and leaves remaining providers untouched. Each provider operation should be isolated in a try/catch so that one bad config doesn't prevent cleanup of the others.</comment>

<file context>
@@ -0,0 +1,69 @@
+        if (!project) throw new ProjectNotLinkedError();
+
+        const providers = providerArg ? [parseMcpProvider(providerArg)] : MCP_PROVIDERS;
+        const results = providers.map((provider) => disconnectMcpProvider(provider));
+        await updateMcpConnectionStatus('disconnected');
+        const changed = results.some((result) => result.changed);
</file context>

Comment thread src/lib/api/oss.ts Outdated

export type McpConnectionStatus = 'connected' | 'disconnected';

export async function updateMcpConnectionStatus(status: McpConnectionStatus): Promise<void> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Missing backward-compatibility / 404 handling for the new /api/usage/mcp/status endpoint in ossFetch. On older or self-hosted backends that do not yet implement this route, connect/disconnect flows will surface a generic 404 error instead of a clear feature-unavailable message (or graceful fallback), and the local config will have already been updated before the failure.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/api/oss.ts, line 55:

<comment>Missing backward-compatibility / 404 handling for the new /api/usage/mcp/status endpoint in ossFetch. On older or self-hosted backends that do not yet implement this route, connect/disconnect flows will surface a generic 404 error instead of a clear feature-unavailable message (or graceful fallback), and the local config will have already been updated before the failure.</comment>

<file context>
@@ -50,6 +50,15 @@ export async function getJwtSecret(): Promise<string | null> {
 
+export type McpConnectionStatus = 'connected' | 'disconnected';
+
+export async function updateMcpConnectionStatus(status: McpConnectionStatus): Promise<void> {
+  await ossFetch('/api/usage/mcp/status', {
+    method: 'POST',
</file context>

});
});

it('removes only the insforge MCP server', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Missing test for disconnectMcpProvider edge case when no prior connection exists

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/mcp-config.test.ts, line 60:

<comment>Missing test for disconnectMcpProvider edge case when no prior connection exists</comment>

<file context>
@@ -0,0 +1,74 @@
+    });
+  });
+
+  it('removes only the insforge MCP server', () => {
+    const cwd = tempDir();
+    connectMcpProvider('claude-code', project, cwd);
</file context>

const cwd = tempDir();
connectMcpProvider('claude-code', project, cwd);

const result = disconnectMcpProvider('claude-code', cwd);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Disconnect test does not verify that non-insforge MCP entries survive disconnection

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/mcp-config.test.ts, line 64:

<comment>Disconnect test does not verify that non-insforge MCP entries survive disconnection</comment>

<file context>
@@ -0,0 +1,74 @@
+    const cwd = tempDir();
+    connectMcpProvider('claude-code', project, cwd);
+
+    const result = disconnectMcpProvider('claude-code', cwd);
+    const config = JSON.parse(readFileSync(getMcpConfigPath('claude-code', cwd), 'utf-8'));
+
</file context>

@jwfing

jwfing commented Jun 24, 2026

Copy link
Copy Markdown
Member

@sarthakNITT Why do you think it's necessary to support mcp connection within CLI? In project's Install page, we've provided the different paths for CLI and MCP.

@sarthakNITT

Copy link
Copy Markdown
Author

@jwfing Currently @insforge/install only writes the MCP config file. The dashboard status updates to "Connected" only when the user makes their first agent call. meaning if a user disconnects InsForge by manually removing it from their MCP config, the dashboard still shows "Connected" because there's no way to notify the backend.

connect and disconnect fix this. connect writes the MCP config (same as install) and immediately updates the dashboard status. disconnect removes the InsForge entry from the MCP config and marks the dashboard as disconnected in real time. This way the dashboard always reflects the actual state.

The agent verification step (sending the prompt to confirm the agent is working) remains as a separate step, connect handles the config + status, verification confirms the agent is functioning correctly. These are two different things.

Also planning to make both commands accept --api-key and --api-base-url directly so any user, not just those using the CLI, can run them without any prior setup.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/api/oss.ts">

<violation number="1" location="src/lib/api/oss.ts:60">
P1: The opts path sends the Bearer API key to an arbitrary caller-provided apiBaseUrl without URL validation or domain checks. Callers (connect.ts and disconnect.ts) source apiBaseUrl from raw CLI options, so a malicious or mistyped URL can receive the secret API key, enabling credential exfiltration.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/lib/api/oss.ts
opts?: { apiKey: string; apiBaseUrl: string }
): Promise<void> {
if (opts) {
const res = await fetch(`${opts.apiBaseUrl.replace(/\/$/, '')}/api/usage/mcp/status`, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: The opts path sends the Bearer API key to an arbitrary caller-provided apiBaseUrl without URL validation or domain checks. Callers (connect.ts and disconnect.ts) source apiBaseUrl from raw CLI options, so a malicious or mistyped URL can receive the secret API key, enabling credential exfiltration.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/api/oss.ts, line 60:

<comment>The opts path sends the Bearer API key to an arbitrary caller-provided apiBaseUrl without URL validation or domain checks. Callers (connect.ts and disconnect.ts) source apiBaseUrl from raw CLI options, so a malicious or mistyped URL can receive the secret API key, enabling credential exfiltration.</comment>

<file context>
@@ -52,7 +52,25 @@ export async function getJwtSecret(): Promise<string | null> {
+  opts?: { apiKey: string; apiBaseUrl: string }
+): Promise<void> {
+  if (opts) {
+    const res = await fetch(`${opts.apiBaseUrl.replace(/\/$/, '')}/api/usage/mcp/status`, {
+      method: 'POST',
+      headers: {
</file context>

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@jwfing

jwfing commented Jun 25, 2026

Copy link
Copy Markdown
Member

@sarthakNITT could you please upload an screenshot or video for testing this feature?
somehow I ran the cli against the latest oss project, got error as below:

$ insforge connect claude-code
Error: OSS request failed: 404
$ insforge disconnect claude-code
Error: OSS request failed: 404
$ insforge functions list
┌─────────────────────┬─────────────────────┬────────┬───────────────────────┐
│ Slug                │ Name                │ Status │ Created At            │
├─────────────────────┼─────────────────────┼────────┼───────────────────────┤
│ search              │ search              │ active │ 5/6/2026, 7:53:01 PM  │
└─────────────────────┴─────────────────────┴────────┴───────────────────────┘

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

locally test failed.

@sarthakNITT

Copy link
Copy Markdown
Author

@jwfing
Current behaviour - After connecting successfully, theres no official disconnect instructions. After removing insforge manually from the mcp_config.json it got disconnected but on dashboard it shows connected (Incorrect state).

Here the screen recording of behaviour.

Screen.Recording.2026-06-27.at.12.04.31.AM.mov

This pr fix - Users can connect and disconnect by just one terminal command. After running disconnect command it removes the insforge mcp and also updates the dashboard in real time. Works for both cli and GUI users.

Screen.Recording.2026-06-27.at.12.14.25.AM.mov

Clarification for your error - The connect/disconnect commands call a new backend route (POST /api/usage/mcp/status) that I've added in InsForge/InsForge#1581

Since InsForge/InsForge#1581 PR isn't merged yet, running these commands against the original OSS codebase returns 404 because the route doesn't exist there. Once both PRs are merged, it will work end-to-end.

These CLI commands are also not yet published to npm, so they can't be run with the insforge prefix directly, they need to be run via the local build path (node dist/index.js connect claude-code).

@jwfing

jwfing commented Jun 27, 2026

Copy link
Copy Markdown
Member

@sarthakNITT Thanks for the explaination. If someone connected with multi agents(for example, claude-code on machine A, codex on machine B), then he disconnected with claude-code, what's the final status?

@jwfing

jwfing commented Jun 27, 2026

Copy link
Copy Markdown
Member

The connection status is designed to track onboarding progress, not the agent's actual runtime state. So even if it shows "connected" or "disconnected," it doesn't necessarily mean the agent itself is up or down. But I am open to discuss more.

@sarthakNITT

Copy link
Copy Markdown
Author

@jwfing I think this opens up an opportunity to redesign the dashboard a bit. Instead of only showing a binary “Connected” state, it could serve as a real-time overview of what’s happening in Insforge - active connections, number of connected agents, runtime status, recent activity, etc. That would give users a single place to verify what they’re doing and significantly improve the overall UX.

If this direction sounds good, I’d be happy to work on redesigning the dashboard and take up this issue.

@jwfing

jwfing commented Jun 29, 2026

Copy link
Copy Markdown
Member

@sarthakNITT Thank your for contributing this PR, we discussed internally and didn't think it's necessary to sync real-time status of multiple agents. I am wondering what is the painpoint you had that causes you to write this PR... if it sounds reasonable we can continue to this solution.

@sarthakNITT

sarthakNITT commented Jul 1, 2026

Copy link
Copy Markdown
Author

@jwfing Even if the status is currently used for onboarding, a dashboard that permanently shows "Connected" after a user has manually disconnected feels like a bug. It leaves users confused about whether InsForge is still active or has access to their local environment.

To answer your question on the multi-agent scenario: the backend status endpoint can easily track status per agent (e.g., claude-code: disconnected, codex: connected). The dashboard can then display exactly which agents are currently active.

This gives users clear visibility, avoids stale UI states, and ensures they know exactly when InsForge is active or inactive on their system.

Basically my pain point was having no instructions on how to disconnect, and even after doing it manually, the dashboard still showed 'Connected' leaving me confused if the disconnection actually succeeded.

Let me know if it sounds like an important behavior to support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-issue PR isn't linked to any issue — open and claim an issue first, then link it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants