Wiring into real hosts
A server nobody can connect to is a repository, not a capability. This lesson is the last mile: the config surfaces of the major hosts, the environment trap that causes most first-connection failures, and what changes when the server is remote.
The shape all hosts share
Every host's configuration answers the same three questions: what do I run (or where do I connect), what environment does it need, and what may it do once connected. Claude Desktop reads claude_desktop_config.json; a Paper Trail entry looks like:
{
"mcpServers": {
"paper-trail": {
"command": "uv",
"args": ["run", "--with", "fastmcp", "python",
"/Users/you/servers/paper_trail.py"],
"env": {"BOOKSTORE_DB_URL": "postgres://localhost/papertrail"}
}
}
}Claude Code takes the same information via claude mcp add (or .mcp.json checked into a project, so a whole team inherits the server with the repo). Cursor reads .mcp.json-style entries under its settings, per-project or global. The vocabulary transfers wholesale: a command/args/env block for stdio, or a url for remote. After any edit, the host must reconnect (most need a restart of the server connection) — a stale session against an old process is a classic ten-minute mystery.
The environment trap, once and properly
The single most common wiring failure, worth its own heading: the host spawns your server from the host's environment. Your shell's PATH, your virtualenv, your exported BOOKSTORE_DB_URL — none of it is there. Hence the two disciplines in the block above: absolute paths (to the script, and to the interpreter or runner if there is any doubt which one), and every required variable stated explicitly in env. The corollary for secrets: config files are where keys go to leak — prefer the host's env, reference a secret store where the host supports one, and never commit a config carrying a live credential. If PR review would flag it in code, it does not belong in mcp.json either.
Approval policy is configuration too
Connecting a server and trusting it are different decisions, and hosts keep them separate. Claude Desktop asks per tool call by default, with per-tool "always allow"; Claude Code lets you allowlist specific tools while everything else keeps prompting; hosts generally distinguish read-ish from write-ish operations in what they nag about. Resist the reflex to allow-all on day one. The gate is not friction to eliminate — it is the control you will wish existed when section 4's material stops being hypothetical. Allowlist the verbs you have read, one at a time, and leave the rest prompting.
Remote servers
For a streamable-HTTP server the block collapses to a URL plus auth — no command, no spawn, no environment trap. What replaces them: identity (OAuth flows, org allowlists — remote servers serve many users and must know which one you are), availability (a laptop stdio server fails only you; a remote one has an uptime story), and change without consent (the server you connected to yesterday may deploy different behaviour today — the "rug pull" problem, treated properly in lesson 13). Local means your blast radius and your maintenance; remote means someone else's maintenance and their blast radius. Choose per capability, not by fashion.
One server, three hosts, zero edits
The quiet payoff of everything above: the same hundred lines of Paper Trail — unchanged — can now serve Claude Desktop on your laptop, your team's Cursor via a committed .mcp.json, and the from-scratch client you wrote in lesson 10. Three hosts, three config blocks, one server. That is M+N, no longer as a diagram from lesson 1 but as your Tuesday.
Try this: wire your Paper Trail copy into one real host, with the deliberate mistake first — omit the env block, watch the failure, read the host's MCP log until you can see it is a spawn-environment error, then fix it. One rehearsed failure now converts hours of future mystery into a two-minute check.