API-285: One-step MCP install (nansen mcp install <client>) - #487
API-285: One-step MCP install (nansen mcp install <client>)#487gulshngill wants to merge 3 commits into
Conversation
pr-reviewer Summary for #2bdce77📝 2 findings Review completed. Please address the findings below. Findings by Severity
Review effort: 4/5 (Complex) SummaryThis is a well-engineered new command. The security decisions are sound and explicitly documented: merge-only writes, atomic rename, backup before write, key never printed, closed client-name validation, hardcoded HTTPS server URL, and Findings
|
Add `nansen mcp install/uninstall <client>` to write the hosted Nansen MCP server (https://mcp.nansen.ai/ra/mcp) into Claude Code, Claude Desktop, or Cursor configs. Merge-only atomic writes with backup, key never printed, --dry-run supported. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
a49f962 to
e2bc3b3
Compare
|
🤖 Automated Branch Sync (claude-code) — 2026-08-13T17:02:07Z Action: Rebased Conflict resolved (1 file): Auto-merged cleanly, both intents verified intact:
Verified: full suite 1985 passed / 2 skipped / 0 failed,
Left for a human (not changed during sync): |
|
🤖 Automated Branch Sync (claude-code) — 2026-08-13T18:56:53Z Action: No rebase needed — Merge state is |
|
🤖 Automated Branch Sync (claude-code) — 2026-08-14T00:58:01Z Action: No rebase needed —
|
|
🤖 Automated Branch Sync (claude-code) — 2026-08-14T02:56:49Z Action: No rebase needed — Merge is gated only by |
|
🤖 Automated Branch Sync (claude-code) — 2026-08-14T04:57:08Z Action: No rebase needed — |
|
🤖 Automated Branch Sync (claude-code) — 2026-08-14T14:57:24Z Action: No rebase needed — |
|
🤖 Automated Branch Sync (claude-code) — 2026-08-17T05:50:35Z Action: No rebase needed — Merge is still gated on |
|
🤖 Automated PR Review (codex) — 2026-08-17T06:04:44Z Reviewed: MCP install/uninstall behavior, client config formats, merge/backup/atomic-write paths, error handling, key exposure, CLI/schema/docs integration, and test coverage |
|
🤖 Automated Branch Sync (claude-code) — 2026-08-17T08:57:58Z Action: No rebase needed — ℹ️ Merge state is |
|
🤖 Automated PR Review (codex) — 2026-08-17T09:02:56Z Reviewed: MCP client config formats, install/uninstall behavior, atomic writes, backups, error handling, API-key exposure, CLI/schema/docs integration, and test coverage |
| const writeConfig = (configPath, config) => { | ||
| const dir = path.dirname(configPath); | ||
| if (!fsx.existsSync(dir)) fsx.mkdirSync(dir, { recursive: true, mode: 0o700 }); | ||
| const tmp = path.join(dir, `.${path.basename(configPath)}.tmp-${process.pid}`); |
There was a problem hiding this comment.
Potential file inclusion attack via reading file - medium severity
If an attacker can control the input leading into the ReadFile function, they might be able to read sensitive files and launch further attacks with that information.
Show fix
Remediation: Ignore this issue only after you've verified or sanitized the input going into this function. This issue is only relevant in the backend, not in the frontend!
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
|
🤖 Automated Branch Sync (claude-code) — 2026-08-17T12:59:06Z Action: Checked Merge is currently gated on |
Summary
Implements API-285 — one-step install of the hosted Nansen MCP server into local MCP clients:
The command writes a
nansenentry into the client's own config file using the API key fromnansen login/NANSEN_API_KEY. No network calls, no shelling out — pure fs operations.Provider research (public sources)
Surveyed one-step-install mechanisms from Nansen's own MCP docs, Claude Code (
claude mcp add,.mcp.json), Claude Desktop, Cursor (~/.cursor/mcp.json+ deeplinks), VS Code (serverskey,code --add-mcp), Codex, Gemini CLI, and vendor installers (Sentry wizard, Smithery CLI, Stripe, GitHub MCP badges). Key facts driving the design:https://mcp.nansen.ai/ra/mcp, auth viaNANSEN-API-KEYheader (docs) — so entries are remote-URL, no local server process.~/.claude.jsonentries require"type": "http"next tourl; Cursor infers fromurl; Claude Desktop's config is stdio-only, so it bridges vianpx mcp-remote(pinnedmcp-remote@0.1.38, header arg written without a space after the colon to dodge Claude Desktop's arg-splitting bug).--dry-run, uninstall support.Security decisions (threat-modeled independently)
mcpServers.nansenis ever assigned; all sibling servers and unrelated keys pass through. Unparseable JSON → refuse with the file path, never repair/overwrite..bakcopy before every install write. Atomic temp-file + rename so a crash can't truncate the config. Type guard onmcpServers.--dry-run(redacted), or errors. New dirs 0700, files 0600, backup 0600, existing target chmod'd 0600 post-write (best-effort). Explicit plaintext + settings-sync warnings on install. Telemetry already sends flag names only, so no key material can leak there.claude mcp addetc. deliberately not exec'd); client name validated against a closed set before any path math; no user-supplied paths.--url/env override — a redirectable URL would exfiltrate the key);mcp-remotepinned exact; the docs'--allow-httpflag deliberately dropped (URL is HTTPS).realpathSyncso the rename edits the real file instead of replacing the link. TOCTOU judged not realistic (same-user home dir).Tests
New
src/__tests__/mcp.test.js(27 tests): per-platform path resolution incl. claude-desktop-on-Linux error, per-client entry shapes (pinned version, no--allow-http, no-space header), merge/remove purity + non-objectmcpServersguards, and handler tests against real temp dirs — file/dir modes, backup content + mode, idempotent re-install, corrupt-JSON refusal (file untouched), not-logged-in (no writes),--dry-run(no writes, key never printed), key-never-in-output, uninstall (incl. no-key and no-entry paths), symlink follow, schema.json registration, andrunCLIrouting /--dry-runboolean-flag parsing.npm test: 52 files, 1913 passed / 2 skipped ✅npm run lint: clean ✅$HOME, help paths,nansen schema mcp.Limitations / follow-up
~/.claude.jsonis also rewritten by live Claude Code sessions — a session saving state after our write can drop the entry (last-writer-wins, not corruption). Output tells the user to restart; if it bites, fallback isexecFile('claude', ['mcp','add',...]).mcp-remotepin (0.1.38) trades missed upstream security fixes for protection against compromised future releases; bumping is a one-constant change.scripts/postinstall.jsalready distributes agent skills — MCP install is a second, parallel distribution channel; worth a docs pass later on when to use which.🤖 Generated with Claude Code