HomeLearn › Remote vs local MCP servers

Remote vs local MCP servers

Updated 2026-09-23

Every MCP server you install is one of two things. A local server is a process your client spawns on your machine and talks to over stdin and stdout. A remote server is an HTTP endpoint you send requests to. The protocol semantics are identical; the operational and security consequences are not.

What "local" means in practice

With the stdio transport the client launches the server as a subprocess and exchanges newline-delimited JSON-RPC over the standard streams. That is what a configuration line like npx -y some-mcp-server or uvx some-mcp-server does: it downloads a package and runs it as you.

Consequences:

A server that also listens on a local HTTP port is a hybrid: it runs on your machine but is reachable by other software. The Streamable HTTP spec says such servers should bind to 127.0.0.1, must validate the Origin header, and should authenticate connections, because otherwise a web page can reach a local MCP server through DNS rebinding.

What "remote" means in practice

A remote server exposes a single MCP endpoint over HTTPS, for example https://example.com/mcp. Each request is its own HTTP POST and the response is JSON or a request-scoped SSE stream. Nothing runs on your machine except the client.

Consequences:

How each client attaches credentials to a remote server

The three clients covered on mcpnav each let you send headers without writing the secret into a shared file.

Claude Code: claude mcp add --transport http <name> <url> --header "Authorization: Bearer your-token", or headers in .mcp.json with ${VAR} expansion. Claude Code reads certain credential variables (its own ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN, cloud-provider tokens, NPM_TOKEN) as empty in a remote server's url and headers, so a repository's config cannot forward your Claude credentials to a third party. OAuth sign-in runs through /mcp or claude mcp login <name>.

Cursor: a headers object on the url entry, with ${env:NAME} interpolation, for example "Authorization": "Bearer ${env:MY_SERVICE_TOKEN}". OAuth is supported, with an optional auth block for static client credentials.

Codex: bearer_token_env_var = "NAME" sends the named variable's value in Authorization; http_headers holds static headers, env_http_headers maps header names to variable names, and http_headers_helper runs a command that prints headers. OAuth is supported with CIMD and DCR.

In all three, the pattern is the same: the config names a variable, the shell holds the value.

Rules on the server side that affect you as a user

Two requirements from the MCP security document explain why a well-run remote server will refuse some things you might expect it to accept:

The same document recommends scope minimisation: request a minimal scope up front and elevate only when a privileged tool is first used. When a remote server asks for broad scopes at sign-in, that is a signal to look more closely.

Choosing

Pick a local server when the data is on your machine, when you need the server to see local files or processes, or when the data is sensitive enough that you do not want it leaving the host. Then treat the package as code you are executing: pin it, read it, and give it only the keys it needs.

Pick a remote server when the capability lives in a SaaS product, or when several people need the same integration. Then treat the endpoint as a third party you are sending data to: check who operates it, use OAuth or a scoped API key, and keep the key in an environment variable.

mcpnav lists both kinds. Server pages built from Registry data show a packages block for local installs and a remotes block for endpoints, and the Connect block prints the matching command with <YOUR_VALUE> placeholders for every secret header or variable.

Sources

All pages accessed 2026-09-23.

Sources