Remote MCP Server vs Local (stdio): The 2026 Decision Guide
A remote MCP server is an MCP server your client reaches over HTTP instead of launching as a subprocess — and almost every guide explaining that sentence is one spec revision out of date. The current Model Context Protocol revision is 2025-11-25, and it rewrote the remote-server authorization story: Dynamic Client Registration was downgraded from SHOULD to MAY and kept only "for backwards compatibility with earlier versions of the MCP authorization spec," with OAuth Client ID Metadata Documents taking its place as the preferred path. Meanwhile the thing nobody writes down: Claude's remote connectors dial your server from Anthropic's cloud infrastructure, not from your laptop — which turns "your data leaves your machine" from a hand-wave into three testable networking requirements. This guide gives you a revision-dated comparison table, a decision rule, and a pre-launch checklist written against the spec as it stands in July 2026.
What changed in the 2025-11-25 revision
If your mental model of remote MCP is "OAuth 2.1 plus Dynamic Client Registration," it is dated 2025-06-18 and it is stale. MCP revisions are date strings — YYYY-MM-DD marking the last backwards-incompatible change, each tagged Draft, Current or Final. The current revision is 2025-11-25. Two things in it matter more than anything else for people standing up a remote server.
First, registration inverted. In 2025-06-18, clients and authorization servers SHOULD support Dynamic Client Registration (RFC 7591), and Client ID Metadata Documents did not exist. In 2025-11-25, the authorization spec says clients and authorization servers SHOULD support OAuth Client ID Metadata Documents (CIMD, draft-ietf-oauth-client-id-metadata-document-00), and DCR drops to MAY — explicitly "included for backwards compatibility with earlier versions of the MCP authorization spec." Same protocol, opposite polarity, five months apart. Every copy-paste tutorial in circulation predates the flip.
Second, stewardship moved. Anthropic created and open-sourced MCP on 25 November 2024 (initial revision 2024-11-05, shipping with pre-built servers for Google Drive, Slack, GitHub, Git, Postgres and Puppeteer), then donated it to the Agentic AI Foundation — a directed fund under the Linux Foundation, co-founded with Block and OpenAI, with support from Google, Microsoft, AWS, Cloudflare and Bloomberg — on 9 December 2025. The governance model was stated as unchanged, but the framing is: MCP is not "Anthropic's protocol" any more. That donation post also put adoption at "more than 10,000 active public MCP servers" — a December 2025 figure, roughly seven months old now, so treat it as a floor, not a count.
One more piece of tense discipline, because it is the easiest error to make in this topic: Roots, Sampling, Logging and Dynamic Client Registration are marked Deprecated in the draft, which targets revision 2026-07-28 and has not been released. Earliest removal for all four is the first revision released on or after 2027-07-28; deprecated features must stay in the spec at least twelve months (or 90 days under expedited removal). Signposted, not gone.
Local vs remote, side by side
The protocol is identical either way — what changes is the transport, the auth posture, and who owns the risk. The spec defines exactly two standard transports, stdio and Streamable HTTP, and says "Clients SHOULD support stdio whenever possible." Custom transports are permitted but MUST preserve the JSON-RPC message format and lifecycle. Server primitives are the same three in both worlds, and their control hierarchy is worth memorising: Prompts are user-controlled (slash commands, menu options), Resources are application-controlled (file contents, git history), Tools are model-controlled (API calls, file writes).
The table below dates the auth rows on purpose. If a guide you are reading matches the 2025-06-18 row, you now know exactly how old it is.
| Dimension | Local server (stdio) | Remote server (Streamable HTTP) |
|---|---|---|
| Standard transport | stdio — clients SHOULD support it whenever possible | Streamable HTTP — one endpoint path serving both POST and GET (e.g. https://example.com/mcp) |
| Spec position on authorization | SHOULD NOT follow the authorization spec; "retrieve credentials from the environment" | SHOULD conform: OAuth 2.1 (draft-ietf-oauth-v2-1-13), server acts as a resource server |
| Client registration — spec 2025-06-18 | n/a | DCR (RFC 7591): SHOULD support. CIMD did not exist. |
| Client registration — spec 2025-11-25 | n/a | CIMD: SHOULD support. DCR: MAY, "for backwards compatibility." |
| Who initiates the connection | the MCP client process on your device | Anthropic's cloud infrastructure — even from Claude Desktop |
| Public reachability | not required | required — a remote server MUST be publicly accessible at its URL |
| Distribution and updates | user runs a binary; clients supporting one-click config MUST show the exact untruncated command and require explicit approval | you update server-side; declare it in server.json under remotes |
| Primary risk you own | arbitrary code execution on the user's machine with the client's privileges; data exfiltration with no visibility into commands | token audience binding, session security, Origin validation — plus SSRF if your client is itself hosted |
| Anthropic MCP connector (Messages API) | not supported — local stdio servers cannot be connected directly | supported over public HTTPS; tool calls only; not eligible for Zero Data Retention |
Two rows deserve a footnote. The Origin-validation and localhost-binding rules — servers MUST validate the Origin header to prevent DNS rebinding, and new in 2025-11-25 MUST respond 403 Forbidden if an Origin is present and invalid; when running locally they SHOULD bind to 127.0.0.1 rather than 0.0.0.0 — are Streamable HTTP rules that mostly bite local HTTP servers, the awkward middle case. And HTTP+SSE is Deprecated, not removed: deprecated in revision 2025-03-26 with Streamable HTTP as the migration path, earliest removal "three months after SEP-2596 reaches Final," and the spec's Removed table still reads "No features have been removed under this policy yet." Build new on Streamable HTTP; don't tell your users SSE stops working tomorrow.
Who actually dials your server
This is the fact that turns "remote means your data leaves your machine" into something you can actually test. Per Anthropic's custom connector documentation, connections to remote MCP servers originate from Anthropic's cloud infrastructure, not from the user's local device — and that holds across every Claude client, including claude.ai, Claude Desktop, Cowork and the mobile apps. The arrow does not go from the laptop to your server. It goes laptop → Anthropic → your server.
Three requirements fall straight out of that arrow, and none of them are hand-waves:
- The server must be publicly reachable. A remote server MUST be publicly accessible at its URL. A localhost or VPN-only endpoint is not a custom connector.
- Private networks must allowlist Anthropic's IP ranges. That is a firewall ticket, not a checkbox. "Remote means no install" is only true for the end user — you inherited the ops work.
- It is not Zero Data Retention eligible. Anthropic's MCP connector on the Messages API is explicitly not ZDR-eligible. If ZDR is a contractual requirement for you, that path is closed and you need to know now, not at procurement.
The API-side connector has its own edges, all date-stamped as of July 2026: it requires the beta header mcp-client-2025-11-20 (the previous mcp-client-2025-04-04 is deprecated — this header rotates, so check the docs); of the whole MCP feature set it supports tool calls only; the server must be publicly exposed over HTTPS and both Streamable HTTP and SSE transports are accepted; and it is available on the Claude API, Claude Platform on AWS and Microsoft Foundry, but not currently on Amazon Bedrock or Google Cloud. Config splits across mcp_servers (url, name, authorization_token) and an mcp_toolset in tools with allowlist, denylist and deferred loading. The authorization_token takes an OAuth access token, and the docs are blunt about whose job that is: API consumers are expected to run the OAuth flow, obtain the token before the call, and refresh it as needed. If you are wiring tools into an agent loop, our MCP vs plain API comparison covers when the protocol earns its overhead at all, and best LLM for AI agents covers the model behind it.
The decision rule
The spec hands you the cleanest split there is: stdio SHOULD NOT follow the authorization spec and instead "retrieve credentials from the environment"; HTTP-based transports SHOULD conform to it. Authorization is OPTIONAL in MCP — but the moment you go remote, you have opted into OAuth 2.1, discovery, PKCE, resource indicators and scope negotiation. That is the real cost of the URL. So:
- Go local (stdio) when the server needs the user's filesystem, local binaries or dev environment; when one user maps to one process; and when the credential is already sitting in that user's environment. You get no OAuth, no public surface, no discovery — and you accept that you are shipping a binary that runs with the client's privileges.
- Go remote (Streamable HTTP) when the server fronts a multi-tenant service with per-user identity; when you need to ship a fix without asking 5,000 people to update; or when the client is hosted and physically cannot spawn your subprocess — which is exactly the case for Anthropic's API connector.
- Ship both when you can. In
server.json,remotesandpackagescoexist specifically so hosts can choose local install or hosted URL.
On latency: reason about it, don't quote it. A stdio call is a write to a subprocess pipe. A remote call is a network round trip plus TLS plus token validation, on every tool invocation, inside a loop the model may run dozens of times per task. Nobody publishes credible MCP local-vs-remote latency numbers, and you should be suspicious of anyone who does — but the shape of the difference is not in doubt, and it compounds with tool-call count.
And the security trade is not one-directional. The counterweight to every "remote sends your data away" argument is the spec's own warning about local servers: they are binaries executed on the user's machine with the client's privileges, with the risk of arbitrary code execution, no visibility into what commands run, and data exfiltration. That is why clients offering one-click local install MUST display the exact, untruncated command and require explicit approval. Local is not automatically safer; it is differently unsafe. We unpack both threat models in MCP security.
One key behind every agent that calls your MCP server
An MCP server is only half the loop — something has to decide which tool to call. DataLLM Lab is an OpenAI-compatible gateway to 300+ models at https://www.datallmlab.com/v1, so you can swap the model behind your agent without touching your MCP wiring or your auth.
Authorizing a remote server
Build to 2025-11-25, and the registration story is a priority order, not a single mechanism. A protected MCP server acts as an OAuth 2.1 resource server; the MCP client acts as an OAuth 2.1 client; the authorization server may be co-hosted or entirely separate. Clients SHOULD work down this list: (1) pre-registered client information, (2) CIMD, if the AS advertises "client_id_metadata_document_supported": true, (3) DCR, if the AS exposes a registration_endpoint, (4) prompt the user to enter client information by hand.
CIMD is the interesting new one, and its mechanics are simple enough to hold in your head. The client_id is an HTTPS URL with a path component — say https://example.com/client.json — that resolves to a JSON document containing at minimum client_id, client_name and redirect_uris, where the client_id inside the document MUST match the URL exactly. That is the whole trick: it solves the "client and server have never met" problem without the AS having to mint records for every client that shows up.
The rest of the flow, with the parts people skip flagged:
- Discovery. Servers MUST implement RFC 9728 Protected Resource Metadata; clients MUST use it to find the AS. Servers MUST implement at least one of: a
WWW-Authenticateheader carryingresource_metadataon a 401, or the well-known URI/.well-known/oauth-protected-resource. Clients MUST support both and prefer the header when present. New in 2025-11-25: the AS MUST provide at least one of RFC 8414 metadata or OpenID Connect Discovery 1.0, and clients MUST support both discovery mechanisms, probing well-known endpoints in a defined order (path-insertion variants first for issuers with path components). 2025-06-18 required RFC 8414 only. - PKCE, with teeth. Clients MUST implement PKCE and MUST use
S256when technically capable. Strengthened in 2025-11-25: clients MUST verify PKCE support via authorization server metadata — ifcode_challenge_methods_supportedis absent, the client MUST refuse to proceed. Not warn. Refuse. This is the single most commonly ignored MUST in the spec. - Resource indicators. Clients MUST include the RFC 8707
resourceparameter in both the authorization and the token request, set to the MCP server's canonical URI, and MUST send it whether or not the AS supports it. Servers MUST validate that tokens were issued specifically for them and MUST NOT accept or transit tokens meant for anyone else. Token passthrough is explicitly forbidden. Access tokens MUST NOT appear in URI query strings —Authorization: Beareron every request. - Scope negotiation (new). Servers SHOULD include a
scopeparameter in theWWW-Authenticatechallenge, and runtime insufficient-scope failures SHOULD return403witherror="insufficient_scope", the requiredscope, andresource_metadata— which drives a defined step-up authorization flow. Clients SHOULD implement retry limits. The error contract:401unauthorized or invalid token,403invalid scope or insufficient permission,400malformed. - Sessions are not authentication. The spec is unambiguous: servers that implement authorization MUST verify all inbound requests, and "MCP Servers MUST NOT use sessions for authentication." Session IDs MUST be secure and non-deterministic, and SHOULD be bound to user-specific information using a key format like
<user_id>:<session_id>, so a guessed session ID cannot impersonate someone else.
Two structural traps worth naming. SSRF is a named risk for hosted MCP clients, not servers: during OAuth discovery a malicious server controls the resource_metadata, authorization_servers and token_endpoint URLs you are about to fetch. If your client runs on a server, you SHOULD enforce HTTPS, block private and reserved ranges (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16 including cloud metadata, fc00::/7, fe80::/10), validate redirect targets, and consider an egress proxy — the spec names Stripe's Smokescreen — while warning you not to hand-roll IP validation. And the confused deputy problem bites when an MCP proxy uses a static upstream client ID and lets clients register dynamically and the third-party AS sets a consent cookie and nobody enforces per-client consent; the mitigation is a per-client consent registry checked before forwarding upstream, exact-match redirect URI validation, __Host- prefixed Secure/HttpOnly/SameSite=Lax signed consent cookies bound to client_id, and single-use short-lived state set only after consent is approved.
If the OAuth authorization-code dance doesn't fit your case — background services, CI/CD, server-to-server with no human in the loop — two official extensions live in the modelcontextprotocol/ext-auth repo: Client Credentials (Draft) and Enterprise-Managed Authorization (Stable; centralized IdP policy enforcement). Both are optional, additive and composable, and require explicit client support — never on by default. If you are already managing per-customer provider keys, the pattern will feel familiar from implementing BYOK.
Shipping and declaring it
Streamable HTTP is a small surface with a lot of MUSTs. The server MUST provide a single MCP endpoint path supporting both POST and GET. On POST, the client MUST send an Accept header listing both application/json and text/event-stream; the server may answer with either a single JSON object or an SSE stream, and the client MUST handle both. The server MAY assign a session via the MCP-Session-Id response header on InitializeResult; the client MUST then echo it on every subsequent request, MUST re-initialize without one if it gets a 404, and SHOULD send an HTTP DELETE to terminate. (2025-06-18 spelled the header Mcp-Session-Id; HTTP headers are case-insensitive, so this is cosmetic — just use the current spelling.) After initialization the client MUST send MCP-Protocol-Version on all HTTP requests, e.g. MCP-Protocol-Version: 2025-11-25; if it is absent and the server has no other way to identify the version, the server SHOULD assume 2025-03-26, and an invalid or unsupported version MUST get a 400.
New in 2025-11-25 and easy to miss: on opening an SSE stream the server SHOULD immediately send a priming event (an event ID with empty data) so the client has something to reconnect from; the server MAY close a connection without terminating the stream to avoid long-lived connections, SHOULD send a retry field first, and the client MUST respect it. Resumption is always via HTTP GET with Last-Event-ID, regardless of whether the stream started on a POST or a GET.
Then declare it. The official MCP Registry — backed by Anthropic, GitHub, PulseMCP and Microsoft — is in preview, with its own warning that breaking changes or data resets may occur before general availability, so do not architect around it as if it were GA. It hosts metadata only (server.json), never artifacts; names are reverse-DNS (io.github.user/server) with DNS or GitHub namespace verification; you publish with the mcp-publisher CLI. Remote servers go in a remotes array typed either "streamable-http" or "sse" — you may offer both at different URLs — and support {curly_brace} URL template variables for multi-tenant or regional deployments, plus a headers array for things like X-API-Key, with isRequired, default, choices and isSecret flags. Worth being precise about why you pick one: the registry schema treats the two transport types as equals and states no preference between them, so the case for "streamable-http" comes from the spec, not the registry — HTTP+SSE is Deprecated there, with Streamable HTTP named as its migration path. One catch for the "share it with my team" use case: the registry explicitly does not support private servers. Internal servers need a self-hosted registry.
SDKs are tiered and all of them speak both local and remote transports: Tier 1 is TypeScript, Python, C# and Go; Tier 2 is Java and Rust; Tier 3 is Swift, Ruby, PHP and Kotlin — all under the modelcontextprotocol GitHub org. If your remote server also fronts model calls, the same argument that makes one MCP endpoint attractive makes one LLM gateway attractive: a single OpenAI-compatible endpoint in front of many providers, so the tool layer and the model layer each have exactly one seam.
Pre-launch checklist
Every line here is a spec MUST or a documented product constraint — not a style preference. Run it before you hand anyone a URL.
- Single endpoint path answers both POST and GET; POST responses can be
application/jsonortext/event-stream. MCP-Protocol-Versionenforced after init; invalid version returns400; absent version falls back to assuming2025-03-26.Originvalidated; invalid Origin returns403. Local HTTP builds bind127.0.0.1, not0.0.0.0.- RFC 9728 Protected Resource Metadata served, via the
WWW-Authenticateheader on 401 and the well-known URI. - Registration path documented in priority order — pre-registered → CIMD → DCR → user prompt — and your CIMD document's
client_idmatches its URL exactly. - Client refuses to proceed when
code_challenge_methods_supportedis missing. Test that path deliberately. - Token audience validated against your canonical URI; no passthrough of foreign tokens; no tokens in query strings.
- Insufficient scope returns
403withinsufficient_scope, the neededscope, andresource_metadata; clients cap retries. - Every inbound request authenticated independently. Sessions are never the auth check. Session IDs non-deterministic and bound as
<user_id>:<session_id>. - If your MCP client is hosted: HTTPS enforced, private ranges blocked, redirect targets validated, egress proxy considered.
- Publicly reachable at the declared URL; Anthropic IP ranges allowlisted if you sit behind a private network.
- ZDR requirement checked against reality — the Anthropic MCP connector is not ZDR-eligible, and supports tool calls only.
server.jsonuses the exact string"streamable-http"; private/internal servers routed to a self-hosted registry, not the public preview one.
One last thing worth passing to your users verbatim, because it is Anthropic's own guidance and it is good: connect only to servers built or hosted by organizations you trust; malicious servers can embed hidden instructions (prompt injection); read the requested OAuth scopes before approving them; server developers can change tool behavior without warning; and disable write-capable tools when using Claude Research. Custom connectors are in beta, supported on the Free, Pro, Max, Team and Enterprise plans, with Free limited to a single custom connector.
FAQ
What is a remote MCP server?
A remote MCP server is an MCP server the client reaches over HTTP at a URL rather than launching as a local subprocess. It speaks the same protocol and exposes the same three server primitives — Tools, Resources and Prompts — but uses the Streamable HTTP transport instead of stdio. Because it is HTTP-based, the spec says it SHOULD conform to the MCP authorization spec, which is built on OAuth 2.1. Local stdio servers explicitly SHOULD NOT do OAuth; they "retrieve credentials from the environment" instead.
Do remote MCP servers still use Dynamic Client Registration?
They may, but it is no longer the recommended path. In revision 2025-06-18, clients and authorization servers SHOULD support Dynamic Client Registration (RFC 7591). In the current revision, 2025-11-25, that inverted: OAuth Client ID Metadata Documents are the SHOULD-support path and DCR is downgraded to MAY, "included for backwards compatibility with earlier versions of the MCP authorization spec." The unreleased draft goes further and marks DCR as Deprecated with CIMD as the named migration path. If a tutorial tells you DCR is how remote MCP auth works, it is describing 2025-06-18.
Is the HTTP+SSE transport dead?
No. HTTP+SSE (from revision 2024-11-05) is Deprecated — deprecated in revision 2025-03-26 with Streamable HTTP as the migration path — but it has not been removed. The spec's Removed table is explicitly empty: "No features have been removed under this policy yet," and the earliest removal for HTTP+SSE is conditional: three months after SEP-2596 reaches Final. Anthropic's MCP connector still accepts SSE, and the registry still defines an "sse" remote type. Build new servers on Streamable HTTP; don't assume SSE stops working tomorrow.
Does Claude connect to my remote MCP server from my laptop?
No. Per Anthropic's support documentation for custom connectors, connections to remote MCP servers originate from Anthropic's cloud infrastructure rather than from the user's local device — and that holds across every Claude client, including claude.ai, Claude Desktop, Cowork and the mobile apps. Three consequences: your server must be publicly reachable at its URL, organizations with private networks must allowlist Anthropic's IP ranges, and localhost or VPN-only endpoints will not work as custom connectors. Custom connectors are in beta.
Can I publish an internal MCP server to the official registry?
No. The official MCP Registry explicitly does not support private servers — the documented guidance is to self-host a private registry for those. The official registry is also in preview, warning that breaking changes or data resets may occur before general availability. It stores metadata only (a server.json), not artifacts, and uses reverse-DNS names with DNS or GitHub namespace verification. For an internal team server you can use the same server.json shape but distribute it yourself.
Which transport should I ship if I want both local and remote?
Ship both and let the host choose. The spec defines exactly two standard transports — stdio and Streamable HTTP — and says "Clients SHOULD support stdio whenever possible." In server.json, the remotes array and the packages array can coexist, so one published entry can offer a local install and a hosted URL. For the remote entry use the exact type string "streamable-http" rather than "sse". The registry schema accepts both and states no preference between them; the reason to pick "streamable-http" comes from the spec, where HTTP+SSE is Deprecated with Streamable HTTP named as its migration path.
DataLLM Lab