Skip to content

Add nansen mcp install/verify for local MCP clients (Cursor first) - #511

Closed
gulshngill wants to merge 1 commit into
mainfrom
feat/mcp-install-command
Closed

Add nansen mcp install/verify for local MCP clients (Cursor first)#511
gulshngill wants to merge 1 commit into
mainfrom
feat/mcp-install-command

Add nansen mcp install/verify for local MCP clients (Cursor first)

19b9ecb
Select commit
Loading
Failed to load commit list.
Nansen PR Reviewer / pr-reviewer succeeded Aug 21, 2026 in 2m 1s

Found 1 finding within acceptable thresholds

Review Status

Passed

Findings

Severity Count
🟡 Medium 1

Review effort: 3/5 (Moderate)

Details

This is a well-structured addition of nansen mcp install / nansen mcp verify commands. The credential-in-config concern is handled (parent-dir creation before write, chmod 0600, refusal to clobber invalid JSON). Error messages are actionable, the two-step verify design is correctly motivated in the PR description, and the 21-unit-test suite covers happy paths and the main failure modes. All AGENTS.md checklist items are satisfied: schema.json updated, changeset present with correct minor bump, no interactive prompts, no real network calls in tests.

Findings

src/commands/mcp.js — medium

Malformed JSON response from MCP server produces a misleading "endpoint unreachable" error

In verify, the call to parseMcpResponseBody (lines 179–183) lives inside the try block that wraps the fetch. When the server returns a well-formed HTTP 200 but with a body that isn't valid JSON (or isn't valid SSE), parseMcpResponseBody throws a SyntaxError. That SyntaxError is not a NansenError, so the instanceof NansenError guard on line 185 does not re-throw it — instead it falls through to:

const reason = error.name === 'AbortError'
  ? `timed out after ${timeoutMs}ms`
  : (error.cause?.code || error.message);
throw new NansenError(`MCP endpoint unreachable: ${url} (${reason})`, ErrorCode.NETWORK_ERROR);

The result is a message like MCP endpoint unreachable: https://mcp.nansen.ai/ra/mcp (Unexpected token '<', "<!DOCTYPE "... is not valid JSON). The endpoint was reachable — it just returned garbage. This will confuse users (and agents) into diagnosing a network problem when the real issue is a bad server response.

Fix: catch parseMcpResponseBody errors separately, or add a guard before the generic wrap:

} catch (error) {
  if (error instanceof NansenError) throw error;
  if (error instanceof SyntaxError) {
    throw new NansenError(
      `MCP handshake failed: ${url} returned an unparseable response (${error.message})`,
      ErrorCode.UNKNOWN
    );
  }
  const reason = error.name === 'AbortError'
    ? `timed out after ${timeoutMs}ms`
    : (error.cause?.code || error.message);
  throw new NansenError(`MCP endpoint unreachable: ${url} (${reason})`, ErrorCode.NETWORK_ERROR);
}

Note: Claude suggested: APPROVE_WITH_COMMENTS. Final status determined by severity thresholds.