Skip to content

Scope a minimal local MCP binary (stdio, no OAuth, production II) - #77

Draft
aterga wants to merge 4 commits into
mainfrom
claude/secondary-mcp-local-deploy-jpof9i
Draft

Scope a minimal local MCP binary (stdio, no OAuth, production II)#77
aterga wants to merge 4 commits into
mainfrom
claude/secondary-mcp-local-deploy-jpof9i

Conversation

@aterga

@aterga aterga commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Scoping (docs-only) for a separate, minimal run-it-yourself binary for local deployment: it speaks MCP over stdio, talks to mainnet IC + production Internet Identity (not a local dfx replica), and drops the entire OAuth 2.1 authorization server while keeping Internet Identity. Adds/rewrites docs/scoping-local-deployment.md.

The insight: hosted-vs-local is a deployment axis, not a network one. Because the local server is single-user and reachable only through the stdio pipe of the client that spawned it, the OAuth 2.1 layer (which exists so remote clients can auth to a public endpoint) is unnecessary — the process boundary replaces the bearer gate. II is retained: the user logs in with their real anchor via a built-in browser handshake and acts as their real II accounts on real mainnet apps, from a bridge they run themselves.

Changes

  • Rewrite docs/scoping-local-deployment.md:
    • Crate layout that keeps the name imcp2: the existing crate stays imcp2 (the shared, embeddable core library) and its hosted binary stays named imcp2 — the OAuth 2.1 + streamable-HTTP server moves behind a default-on hosted feature (optional axum/tower-http), so the Dockerfile/systemd/deploy scripts are unchanged. The new imcp2-local binary is a separate crate depending on imcp2 with default-features = false. (A stricter 3-crate split is noted as an alternative.)
    • Verified dependency stripping: ed25519-dalek, p256, ic-signature-verification, ic-representation-independent-hash have zero references in src/ (grep-confirmed) and drop; top-level schemars 0.8 is vestigial; rmcp swaps transport-streamable-http-server→stdio (transport-io) and drops auth.
    • The auth.rs OAuth-drop / II-connect-keep partition; the tool/session seam (bearer→AuthedSession collapses to a singleton session id); the built-in browser II login (transient 127.0.0.1:0 callback listener); the security model and the production-II verification risks.
    • NEW — "Working with AI tool clients" (§7): how imcp2-local integrates with Claude, Codex, Cursor, Perplexity, and Antigravity, verified against each client's current MCP docs. A capability matrix (client × local-stdio × config × reachability), per-client registration snippets, the cross-client login invariants, and the cloud-client path.

Key finding — client reachability splits in two

A stdio server is reachable only by clients that spawn a local subprocess:

Runs imcp2-local directly (stdio) Cloud/remote-only → needs hosted imcp2
Claude Desktop, Claude Code claude.ai web / mobile / Cowork
Codex CLI / IDE ext / desktop Codex Cloud
Cursor Perplexity web / Windows / remote connectors
Antigravity (IDE / CLI / 2.0)
Perplexity macOS app (via its PerplexityXPC helper)

This is exactly why the OAuth layer stays in hosted imcp2 — it's the only way to serve the cloud clients. Across every subprocess-capable client the login design converges: host-driven OAuth never touches a stdio server, and stderr is invisible in chat everywhere, so the II login URL is surfaced in-band via an authenticate tool (lazy on first authenticated call, non-blocking to avoid the 60s/2min tool timeouts) plus a best-effort browser auto-open.

Testing

Docs-only change — no build/test impact.

  • No code changed (docs/ only)

Checklist

  • I have read the Contributing guidelines.
  • Docs updated (this PR is the doc).
  • No secrets, credentials, or internal-only information are included.

Open decisions (doc §9)

  1. Login loopback listener: hand-roll (drops axum/tower-http, recommended) vs reuse axum.
  2. Browser open: open/webbrowser crate vs std::process::Command.
  3. Session persistence: in-memory only (v1) vs keychain-backed session key.
  4. Crate layout: imcp2 + imcp2-local with a hosted feature (recommended) vs a stricter 3-crate split.

(Login timing is resolved by the client research — lazy + non-blocking.)


🤖 Generated with Claude Code

https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK

claude added 2 commits July 23, 2026 16:29
Analyze the current beta/prod composition and scope a secondary server
instance that bridges the MCP tools to a local dfx replica instead of
mainnet. Documents the mainnet assumptions that would break locally
(root-key fetch, hard-coded IC_URL, the discovery SSRF/https guard,
target_origin canonicalization, and the CMC/ledger management path), a
proposed local run-profile design, the security guardrails, a phased
work breakdown, and open decisions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK
Rewrite the scoping doc for the intended model: a separate, minimal
run-it-yourself binary that speaks MCP over stdio and talks to mainnet
IC + production Internet Identity — not a local dfx replica. It drops
the entire OAuth 2.1 authorization-server layer (the local client is
co-located, so the stdio process boundary replaces bearer-token auth)
while keeping Internet Identity: login runs as a built-in browser
handshake and per-app account delegations work as today.

Adds a verified dependency-stripping analysis (four unreferenced crates
plus a vestigial schemars drop; rmcp swaps to the stdio transport and
drops auth), the auth.rs OAuth-drop/II-connect-keep partition, the
tool/session singleton seam, a 3-crate workspace layout, the security
model, and the production-II verification risks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK
@aterga aterga changed the title Scope a secondary MCP server instance for local deployments Scope a minimal local MCP binary (stdio, no OAuth, production II) Jul 23, 2026
The shared library crate stays imcp2 (its existing embeddable identity)
and the hosted binary stays named imcp2, so the Dockerfile, systemd
unit, and deploy scripts that build/run an imcp2 binary are unchanged.
The hosted server + OAuth layer move behind a default-on `hosted`
feature (optional axum/tower-http); the new minimal stdio binary is a
separate imcp2-local crate depending on imcp2 with default-features
off, so it never compiles the OAuth/HTTP deps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK

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.

Pull request overview

This PR adds a scoping/design document for a separate “run-it-yourself” local MCP server binary that communicates over stdio, targets mainnet IC plus production Internet Identity, and removes the hosted OAuth 2.1 authorization-server layer while retaining an II browser-based delegation handshake.

Changes:

  • Add a draft scoping document defining the local-deployment model (stdio transport, no OAuth) and its security assumptions.
  • Propose a crate/binary layout (imcp2 core + imcp2-local) and a feature-gated hosted surface to keep the existing deployed imcp2 binary name unchanged.
  • Document verified dependency-stripping opportunities and a minimal tool/session seam for a singleton local session.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Cover how imcp2-local integrates with Claude (Desktop/Code + the
cloud surfaces), Codex, Cursor, Perplexity, and Antigravity, verified
against each client's current MCP docs.

Key findings: a stdio server is reachable only by clients that spawn a
local subprocess (Claude Desktop/Code, Codex CLI/IDE/desktop, Cursor,
Antigravity, and the Perplexity macOS app via its PerplexityXPC helper);
cloud/remote-only surfaces (claude.ai web/mobile, Perplexity web/Windows,
Codex Cloud) can't reach localhost and need the hosted imcp2 server — the
reason the OAuth layer stays in imcp2. Host-driven OAuth never applies to
stdio, and stderr is invisible in chat on every client, so the II login
URL is surfaced in-band via an authenticate tool (lazy, non-blocking)
plus a best-effort browser auto-open. Adds a capability matrix, per-client
registration snippets, the login invariants, and the Perplexity remote
OAuth/discovery caveats; updates the login section and open decisions to
match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK
@aterga aterga mentioned this pull request Jul 29, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants