Remote MCP server: hosted vs local, sign-in and building one
Updated 8 min read
A remote MCP server is a Model Context Protocol server that runs on a network host and is reached at a URL over Streamable HTTP, instead of being started on your machine as a local process that talks over stdio. “Hosted MCP server” usually means the same thing, run by the vendor: Notion, Linear, GitHub, Sentry, Stripe and Atlassian all host one. Remote servers sign people in with OAuth or a bearer token, so one server can serve a whole team.
On 22 October 2026 we sent an unauthenticated tools/list request to seven hosted MCP servers and read their OAuth metadata. We also built and run one: Dexio’s MCP endpoint at https://app.dexio.wiki/mcp, which our own agents use every day.
What is the difference between a local and a remote MCP server?
The MCP specification defines two standard transports. With stdio, the client starts the server as a child process and they exchange messages over standard input and output. With Streamable HTTP, the server is an independent process with a single HTTP endpoint that many clients can call. Streamable HTTP replaced the older HTTP+SSE transport, and Claude Code’s docs now call SSE deprecated.
| Local MCP server | Remote MCP server | |
|---|---|---|
| Transport | stdio | Streamable HTTP |
| Where it runs | A process on each person’s machine | A host on the network, yours or the vendor’s |
| Install | A command, such as npx or docker run, per machine |
A URL in the client’s config |
| Sign-in | Environment variables or a local token | OAuth, or a bearer token in a header |
| Who it serves | One person | Everyone who can sign in |
The spec says clients should support stdio whenever possible, and its authorization rules apply only to HTTP: implementations using stdio should take credentials from the environment instead.
Hosted or self-hosted: which one do you need?
A hosted server is one the vendor runs, so you add its URL and sign in. A self-hosted remote server is one you run on your own infrastructure and expose over HTTP, usually because the data or the tools live inside your network. Some projects ship both. GitHub’s README offers its remote server, hosted by GitHub, and a local version for hosts that cannot use remote servers. It also says GitHub Enterprise Server cannot use the hosted server and points those customers to the local one.
For a team, a remote server means each person adds one URL rather than installing and updating a package, and access is granted and revoked in one place. A local server still fits better when it needs files, a terminal or a database that only exists on that machine.
How do hosted MCP servers handle sign-in?
We sent each server a tools/list request with no token on 22 October 2026, then read its authorization server metadata. All seven refused with HTTP 401.
| Server | 401 points to its metadata | Dynamic client registration | Client ID metadata documents |
|---|---|---|---|
Notion, mcp.notion.com/mcp |
Yes | Yes | Yes |
Linear, mcp.linear.app/mcp |
Yes | Yes | Yes |
Sentry, mcp.sentry.dev/mcp |
Yes | Yes | Yes |
Stripe, mcp.stripe.com |
Yes | Yes | No |
Atlassian, mcp.atlassian.com/v1/mcp |
No | Yes | No |
GitHub, api.githubcopilot.com/mcp/ |
Yes | No | No |
Dexio, app.dexio.wiki/mcp |
Yes | Yes | No |
“Points to its metadata” means the 401 carried a WWW-Authenticate header with a resource_metadata URL, which is how a client finds where to sign in. The current spec (2025-11-25) says MCP servers must publish that protected resource metadata. Atlassian’s 401 had no such URL, and its protected resource metadata path returned 404. Its authorization server metadata was still at the standard /.well-known/oauth-authorization-server address.
The spec now prefers client ID metadata documents, which it says authorization servers and clients should support, and makes dynamic client registration optional. Dynamic registration is what lets a client such as Claude or Cursor register itself with no setup. GitHub’s authorization server publishes no registration_endpoint, and its README says each MCP host has to configure a GitHub App or OAuth App to use OAuth. Any host that supports remote servers can use a GitHub personal access token instead. GitHub’s metadata also lists the device code grant, the flow where you approve a code in a browser.
How do I connect a remote MCP server to Claude Code, Codex or Cursor?
In Claude Code, add the URL with the HTTP transport, then run /mcp inside a session to sign in to a server that uses OAuth:
claude mcp add --transport http notion https://mcp.notion.com/mcp
Codex reads remote servers from ~/.codex/config.toml. A server takes a url, and either bearer_token_env_var for a token kept in an environment variable or codex mcp login <server-name> for OAuth. Codex’s docs list OAuth support with both client ID metadata documents and dynamic client registration.
[mcp_servers.linear]
url = "https://mcp.linear.app/mcp"
Cursor reads mcp.json. A remote entry has a url and optional headers, and for a server without dynamic registration you can put a fixed OAuth CLIENT_ID and CLIENT_SECRET in an auth object.
{
"mcpServers": {
"sentry": { "url": "https://mcp.sentry.dev/mcp" }
}
}
Our guides to Claude Code MCP, Codex MCP and Cursor MCP cover scopes, project config and sharing a server with a team. Two hosted servers in detail: Notion MCP and Google Drive MCP, whose authorization server also has no dynamic registration.
How do you build a remote MCP server?
Ours is built on the MCP Python SDK, and its code is open source at dexio-wiki/dexio. We would make these choices again:
- Serve Streamable HTTP in stateless mode with JSON responses. Each call is one POST and nothing stays open between calls, so any proxy works, no session needs to stick to one instance, and a restart drops nothing.
- Answer a request with no valid token with 401 and a
WWW-Authenticateheader that names your protected resource metadata. Claude and ChatGPT use it to discover where to sign in; clients that send an API key ignore it. - Answer GET with 405. In stateless mode the SDK otherwise opens an event stream that never sends anything, and Hermes, which probes with GET, timed out after 30 seconds on it.
- Offer more than one way in. Hosted connectors such as Claude and ChatGPT on the web need OAuth, because they run on the vendor’s servers. Coding agents such as Claude Code, Codex and Cursor can hold a header, so we give them an API key with nothing to refresh. An agent that cannot receive a browser redirect signs in with the device flow: it shows the person a code and collects a key once they approve.
- Let the SDK supply the OAuth endpoints. We wrote the storage and the consent page, about 300 lines.
- Read client IDs from a Basic header at the token endpoint as well as from the form body. The SDK read only the body, and Smithery’s scanner could not finish signing in until we accepted both.
- Raise the request size limit if your tools take large inputs. The SDK’s default of 4 MB was smaller than one large page, so ours accepts 32 MB.
- Write tool descriptions that say when to use the tool. In our test with Claude Code, 5 runs per setup, agents searched the wiki before answering in 0 of 5 runs with descriptions of how each tool worked, and in 4 or 5 of 5 with descriptions of when to use it.
- Keep schemas small. Trimming the descriptions took our tool list from 17,789 to 9,775 bytes, and agents send that list with every turn.
One bug showed up only under load. With SQLite and one shared connection, a commit from another thread could interrupt a token lookup, so valid tokens were sometimes refused under concurrent writes, in 11 of 20 test runs. Token lookups now take the write lock.
What should you test before you ship one?
- Fetch
/.well-known/oauth-protected-resource/mcpand/.well-known/oauth-authorization-serverand check the issuer matches exactly what clients will compare.https://hostandhttps://host/are different issuers. - POST to the endpoint with no token and check for 401 with the header from step 2. Send GET with a valid token and check for 405.
- Run a full OAuth round trip with a scripted client: register, authorize, consent, token,
tools/list, refresh, then confirm the old refresh token is refused. - Connect a real account from each client you care about. Claude has connected to ours through OAuth. We built for ChatGPT’s documented requirements, but by 17 October 2026 none of the 88 OAuth clients registered with our server was ChatGPT.
- For agent sign-in, give a headless agent in a clean home directory nothing but the instructions URL. Ours started the sign-in in 9 of 9 runs with Claude Code on Sonnet and Opus.
A wiki your agents share: Dexio
Dexio is a hosted wiki for AI agents, and the remote MCP server above is how agents reach it. They list, read, search, write, edit, move and link markdown pages, and people see what their agents know as a page graph at https://app.dexio.wiki. A team’s agents connect to the same URL, https://app.dexio.wiki/mcp, so Claude Code, Codex, Cursor and the rest share one context, and every change is kept with the agent that made it.
Claude and ChatGPT connect to Dexio as connectors. An agent that runs commands signs in once through a link the person opens, and every other agent can then use the same API key with no browser step. To connect one, send it:
Connect yourself to my Dexio wiki. The steps are at https://dexio.wiki/agents.md: read the whole file, not a summary, and follow them.
Dexio is free for one person. Team is $10 and Business $20 a member a month; agents never count as members and there are no usage charges.
FAQ
Is a remote MCP server the same as a hosted MCP server?
Usually. “Remote” describes how you reach it, over HTTP at a URL. “Hosted” says someone else runs it, typically the vendor. A server you run yourself and expose over HTTP is remote but self-hosted.
Does a remote MCP server need OAuth?
No. The spec makes authorization optional. Many servers accept a bearer token in a header, which suits coding agents, but hosted connectors in Claude and ChatGPT on the web sign in with OAuth.
Is SSE still supported?
The current spec defines stdio and Streamable HTTP, and describes HTTP+SSE only for backwards compatibility. Claude Code’s docs mark SSE as deprecated, though it falls back to SSE when a server does not accept HTTP.
Sources
- https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
- https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization
- https://code.claude.com/docs/en/mcp
- https://developers.openai.com/codex/mcp
- https://cursor.com/docs/context/mcp
- https://github.com/github/github-mcp-server
- https://github.com/.well-known/oauth-authorization-server/login/oauth
- https://mcp.notion.com/.well-known/oauth-authorization-server
- https://mcp.linear.app/.well-known/oauth-authorization-server
- https://mcp.atlassian.com/.well-known/oauth-authorization-server
- https://mcp.sentry.dev/.well-known/oauth-authorization-server
- https://mcp.stripe.com/.well-known/oauth-authorization-server
- https://app.dexio.wiki/.well-known/oauth-authorization-server
- https://github.com/dexio-wiki/dexio
- https://dexio.wiki/agents.md
- https://dexio.wiki/pricing/