How to Deploy an MCP Server (Remote, Step by Step)
Taking a local server remote is three decisions — transport, auth, host — and most people over-think all three.

To deploy an MCP server remotely, you change three things about a local one: swap stdio for Streamable HTTP, add auth (OAuth or a bearer token, because the endpoint is now public), and put it somewhere with a stable URL. That's the whole job. Everything below is how to do each part without shipping something you'll regret.
First, be sure you actually need this. Roughly 90% of MCP servers run locally over stdio, and that's usually correct — a local server sees your files and CLIs, sends nothing outbound, and needs zero hosting. You deploy remotely for two reasons only: to share one setup across a team, or to run infrastructure (a browser farm, a hosted index) you don't want on every laptop. If neither applies, stop here and read local vs remote MCP first — remote costs you an auth layer and an ops surface you didn't have.
Step 1: Switch the transport from stdio to Streamable HTTP
A remote server speaks Streamable HTTP, not stdio. Local servers are launched as a child process and talk over stdin/stdout; a remote server listens on a URL and the client POSTs JSON-RPC to it. Same tools, same protocol — different pipe.
Use Streamable HTTP, not the old HTTP+SSE transport. SSE was deprecated in the March 2025 spec revision and split messages across two endpoints, which caused proxy and resumability pain. Streamable HTTP folds everything into one endpoint that returns either a plain JSON response or an SSE-formatted stream when it needs to push. If your framework offers both, pick Streamable HTTP and don't look back.
In practice this is a one-line change in most SDKs — you construct the same server object and start it with an HTTP transport instead of stdio. The tool definitions don't move. If your server writes anything to stdout in stdio mode, that's now irrelevant, but the reverse bites people: make sure logging goes to your host's log sink, not a stream the client is parsing.
Step 2: Add auth — the endpoint is public now
A remote MCP server needs auth from day one, because the moment it has a public URL, anyone who finds it can call your tools. This is the single biggest difference from local. A stdio server inherits your OS user and trusts the machine; a remote one trusts nobody by default.
Two real options, and the right one depends on who calls it:
- Bearer token — a static secret in the
Authorizationheader. Fine for a server you and a small team control, easy to rotate, easy to leak. Treat it like a password: per-user tokens, not one shared string. - OAuth 2.1 — the model gets scoped, revocable access on behalf of a real user. More work to stand up, but it's the only honest answer once the server acts on individual users' accounts. Only about 10% of servers use OAuth today, and that number has to grow as agents do more on our behalf.
Whatever you choose, the security rules for MCP don't change: grant the narrowest scope that works, guard any tool that runs SQL, shell, or arbitrary HTTP, and never pair a web-reading tool with broad write credentials in the same session. A public endpoint makes a prompt-injection bug reachable by strangers, not just you.
Step 3: Pick where to host it
Host a remote MCP server wherever you already run small stateless HTTP services — this is not special infrastructure. It's a process that holds an HTTP port and speaks JSON-RPC. Your options, from least to most operational overhead:
| Host type | Good for | Watch out for |
|---|---|---|
| Serverless / edge (Workers, Lambda) | Bursty, stateless tools; low idle cost | Cold starts; long-lived streams need care |
| Container platform (Fly, Render, Cloud Run) | Most servers; predictable ports | You manage TLS, scaling knobs |
| Your own VM / k8s | Full control, existing infra | You own patching and uptime |
TLS is non-negotiable — clients expect https:// and you're shipping tokens over the wire. Beyond that, keep the server stateless if you can: MCP sessions are per-connection, so avoid stashing state that assumes one instance. If a tool needs state, put it in a database, not process memory, so you can scale horizontally.
Note what you don't have to build: the GitHub MCP Server ships both a local Docker image over stdio and a hosted remote endpoint GitHub operates. Context7 is remote-first — a hosted docs server you point at, nothing to run. If an official hosted version of what you need already exists, deploying your own is usually the wrong move. Deploy when you're wrapping something no one hosts for you.
Step 4: Connect a client and verify
A remote server is added with a url instead of a command, and the fastest way to get it right is to not hand-write it. A remote entry looks like this:
{
"mcpServers": {
"my-server": {
"url": "https://mcp.example.com/mcp"
}
}
}
Auth goes in a header the client sends, and the exact shape is per-client, so don't fight the syntax by hand — copy the block from the tool you're wiring. One caveat worth knowing: Claude Desktop has no native remote transport, and bridges remote servers through the mcp-remote proxy — the steps are in how to add an MCP server.
After it connects, verify two things: the client lists your tools (discovery worked), and a real tool call returns. If it connects but shows no tools, that's a discovery or auth problem, not a hosting one — the troubleshooting checklist maps each symptom to its cause.
One thing hosting doesn't fix: the tool budget
Going remote changes where your server runs, not the constraint that actually degrades agents: the ~40-tool client budget. Clients feed every tool from every connected server into the model's context, and past roughly 40 the model picks badly. A remote 30-tool server costs the same context as a local one.
So don't treat "it's hosted now" as license to expose everything. Ship the tools the server is for, keep the surface tight, and if you're wiring several servers together, add up the tools you'll actually have active and trim anything near the ceiling. Fewer, sharper tools beat a big remote pile every time — and a server that does one thing well is the one teams actually keep connected.