Skip to content

docs: Claude Desktop and other MCP client setup (closes #17) - #28

Merged
tylervick merged 2 commits into
tylervick/remote-access-docsfrom
tylervick/mcp-client-docs
Jul 30, 2026
Merged

tylervick merged 2 commits into
tylervick/remote-access-docsfrom
tylervick/mcp-client-docs

Conversation

@tylervick

Copy link
Copy Markdown
Owner

Summary

Extends the tunnel + bearer-token-by-reference pattern from #9 / PR #18 to Claude Desktop, Cursor, VS Code, and Windsurf.

Stacked on #26 (closes #16), because every client section points at the durable tunnel that PR documents. Base is tylervick/remote-access-docs; GitHub will retarget this to main once #26 merges. Review #26 first.

Claude Desktop needs a bridge

It can't reach this daemon directly, and both reasons are worth knowing before reaching for the config file:

  • Its config registers stdio servers only — there is no url/headers form.
  • The Connectors UI offers OAuth alone for custom remote servers, with no bearer-token or custom-header field (anthropics/claude-ai-mcp#112, closed as not planned).

So the documented setup wraps mcp-remote in /bin/sh, which keeps the token in ~/.nanokvm-token instead of writing it into the config JSON — mcp-remote's own README suggests an env block, which puts the secret in the file. The single quotes are load-bearing for the same reason as the Claude Code flow, with a different consumer: mcp-remote does its own ${VAR} substitution from its environment, so the reference has to survive the shell intact. Claude Desktop's well-known refusal to expand ${VAR} in args works in our favour here.

Two things I checked rather than copied from a guide:

  • --allow-http is omitted. mcp-remote already exempts localhost/127.0.0.1 from its HTTPS check (source), so the flag buys nothing and would relax that check for every other host.
  • Absolute npx path is called out. Claude Desktop launches servers from the GUI, not a login shell, so a bare npx is the most common way this config silently fails to start.

The other three speak HTTP natively

No bridge needed — but their schemas differ in ways that fail confusingly, so each gets its exact form:

Client Config Shape
Cursor ~/.cursor/mcp.json, .cursor/mcp.json url, no type needed, ${env:VAR}
VS Code .vscode/mcp.json, user profile key is servers, explicit "type": "http", ${input:id}
Windsurf ~/.codeium/windsurf/mcp_config.json serverUrl not url, ${env:VAR} or ${file:}

VS Code's promptString input is the best of the three for this project's purposes — it prompts once, stores the value in secret storage, and the token never reaches the file.

Also documents a cross-cutting gotcha: export NANOKVM_MCP_TOKEN in a shell profile works for Claude Code because it runs in your terminal, but a GUI-launched editor inherits launchd's environment, not your shell's, so ${env:...} can resolve empty. launchctl setenv "fixes" it by exporting the token to every process you own, which is the worse trade — VS Code's ${input:} and Windsurf's ${file:} sidestep it properly.

One honest caveat in the text: Windsurf's ${file:} reads the file verbatim, so the token file's trailing newline has to be stripped or auth fails in a way that reads like a bad token.

Verification

  • All five README JSON blocks parse (json.loads).
  • The Claude Desktop args string was extracted from that JSON and executed through /bin/sh -c with npx swapped for an argv dumper. mcp-remote receives Authorization: Bearer ${NANOKVM_MCP_TOKEN} as a literal reference — not empty, not pre-expanded — and the VAR=$(cat ...) prefix populates the child environment that mcp-remote substitutes from.
  • Client schemas taken from each vendor's own docs, not third-party guides.

Not tested against a running Claude Desktop or the device — no tunnel to the hardware from this workspace. The shell/JSON mechanics are verified; the round trip through each client UI is not.

Docs only; no code, no CHANGELOG.md (release PR in flight).

Closes #17.

🤖 Generated with Claude Code

Extends the tunnel + bearer-token-by-reference pattern from #9/PR #18 to
Claude Desktop, Cursor, VS Code, and Windsurf.

Claude Desktop needs a bridge: its config registers stdio servers only,
and the Connectors UI offers OAuth alone for custom remote servers with
no bearer or custom-header field (anthropics/claude-ai-mcp#112, closed
as not planned). mcp-remote wrapped in /bin/sh keeps the token in
~/.nanokvm-token rather than in the config JSON, which is what
mcp-remote's own README suggests. The single quotes are load-bearing for
the same reason as the Claude Code flow: mcp-remote does its own ${VAR}
substitution from its environment, so the reference has to survive the
shell. Claude Desktop not expanding ${VAR} in args works in our favour
here.

Cursor, VS Code, and Windsurf speak streamable HTTP natively. Their
schemas differ in ways that fail confusingly: VS Code keys on "servers"
and needs an explicit "type": "http", Windsurf uses "serverUrl" rather
than "url", and each has its own interpolation syntax. VS Code's
promptString input is the best of them — the token goes to secret
storage and never reaches the file.

Also notes the GUI-launch gotcha: an editor started from Finder inherits
launchd's environment, not the shell's, so ${env:...} may resolve empty
where it works fine for Claude Code in a terminal.

Verified: all five README JSON blocks parse; the Claude Desktop args
string was extracted from that JSON and run through /bin/sh with npx
stubbed, confirming mcp-remote receives the literal ${VAR} reference and
a populated environment. --allow-http is omitted because mcp-remote
already exempts 127.0.0.1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d4df6386-a7f8-4e1f-bf9f-561ecab8c05f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@tylervick

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Keeps the stacked branch current with the corrections made on PR #26
(ControlPath=none, restricted SSH key, plist XML validity).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tylervick
tylervick merged commit 7ef4831 into main Jul 30, 2026
3 checks passed
@tylervick
tylervick deleted the tylervick/mcp-client-docs branch July 30, 2026 18:36
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.

Document setup for Claude Desktop and other major MCP clients Durable remote access path for day-to-day use

1 participant