Your MCP server works locally. It passes tests, the tools respond, and your agent calls them without errors. Now you need to put it somewhere other people — or other agents — can reach it.
The three most common deployment targets for MCP servers are Railway, Cloudflare Workers, and a plain VPS (DigitalOcean, Hetzner, Linode, or any machine you can SSH into). Each one handles MCP differently, and the right choice depends on your transport protocol, your latency requirements, and how much infrastructure you want to manage.
What makes MCP deployment different
MCP servers are not standard web applications. A REST API receives a request, returns a response, and forgets the connection. MCP servers using SSE or WebSocket transport maintain persistent connections. The server keeps a session alive, streams tool results back, and holds state between calls.
This means your hosting environment needs to support long-lived connections. Platforms that aggressively terminate idle HTTP requests or enforce short timeouts will break SSE-based MCP servers. Serverless platforms that spin down between invocations will lose session state entirely.
Stdio transport sidesteps this problem — the MCP client spawns the server as a local subprocess and communicates over stdin/stdout. But stdio only works when the client and server run on the same machine. For remote MCP servers, you need HTTP-based transport, and that is where hosting choices matter.
Railway
Railway is a managed platform that deploys containers from a Git repo or Dockerfile. You push code, Railway builds it, assigns a URL, and keeps it running.
What works well:
Railway supports long-running processes out of the box. Your MCP server can maintain SSE connections without getting killed by idle timeouts. Deployment is straightforward — connect your repo, set environment variables in the dashboard, and Railway handles the rest. It supports both Node.js and Python servers without custom configuration.
You get a public HTTPS endpoint automatically, which means any MCP client that supports HTTP transport can connect. Railway also handles TLS termination, so your server code does not need to manage certificates.
Where it gets tricky:
Railway charges by resource usage (CPU, memory, network). An MCP server with many concurrent SSE connections will use more memory than a typical web app because each connection holds state. If your server handles dozens of simultaneous agent sessions, costs can climb faster than expected.
Cold starts are minimal but not zero. If Railway scales your service to zero (configurable), the first connection after a period of inactivity will take a few seconds.
Best for: MCP servers that need persistent connections, moderate traffic, and minimal ops work. Good default choice for SSE-based servers.
Deploy pattern:
# Dockerfile at your repo root
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Set PORT=3000 in Railway’s environment variables. Your MCP server should listen on the port from the PORT env var.
Cloudflare Workers
Workers run JavaScript at the edge — Cloudflare’s network of data centers worldwide. They execute close to the user (or agent) making the request, which means low latency for the initial connection.
What works well:
Latency is the standout advantage. A Worker responding to an MCP tool call runs in the data center closest to the caller. For agents making rapid sequential tool calls, shaving 50-100ms off each round trip adds up. Workers also scale automatically with no capacity planning.
The free tier is generous for low-traffic MCP servers. You get 100,000 requests per day at no cost, which covers most development and early production use.
Where it gets tricky:
Workers have a hard constraint that affects MCP: they are designed for request-response patterns, not persistent connections. SSE transport requires the server to hold a connection open and push data over time. Workers can stream responses using the Streams API, but they do not support true server-initiated pushes after the initial response completes.
This means Workers work best with MCP’s newer HTTP Streamable transport, where each tool call is an independent HTTP request rather than a persistent connection. If your MCP server relies on SSE for session continuity, Workers will fight you.
CPU time limits also matter. Workers get 10ms of CPU time on the free plan and 30ms on paid. MCP tool calls that do heavy computation — parsing large documents, running transformations, aggregating data — can hit this ceiling. Offload heavy work to external services or Durable Objects.
Best for: Stateless MCP servers using HTTP transport, where low latency and automatic scaling matter more than persistent connections. Good for MCP servers that wrap external APIs.
Deploy pattern:
// wrangler.toml
name = "my-mcp-server"
main = "src/index.js"
compatibility_date = "2026-07-01"
// src/index.js
export default {
async fetch(request, env) {
const body = await request.json();
// Handle MCP JSON-RPC request
const result = await handleToolCall(body);
return new Response(JSON.stringify(result), {
headers: { "Content-Type": "application/json" }
});
}
};
Deploy with wrangler deploy. Add secrets with wrangler secret put API_KEY.
VPS (DigitalOcean, Hetzner, Linode)
A VPS is a virtual machine you control. You install your runtime, run your server process, and manage everything yourself — or use a process manager like PM2 or systemd.
What works well:
Full control. Any transport protocol works: stdio (for local use), SSE, WebSocket, HTTP Streamable. No timeout restrictions, no CPU limits, no cold starts. Your MCP server runs as a long-lived process that stays in memory.
Cost is predictable. A $5-10/month VPS from Hetzner or DigitalOcean handles most MCP server workloads. You pay the same whether you serve ten requests or ten thousand. For MCP servers with consistent traffic, this is usually cheaper than usage-based platforms.
You can run multiple MCP servers on one machine. A small VPS can host several servers behind a reverse proxy (Caddy or nginx), each on a different path or subdomain.
Where it gets tricky:
You own the ops. TLS certificates, process restarts, security updates, monitoring — all yours. If the server crashes at 3 AM, nobody restarts it unless you set up a process manager and health checks.
Scaling is manual. If your MCP server suddenly needs to handle ten times the traffic, you need to provision more capacity yourself. There is no auto-scaling button.
Deployment requires more steps: SSH in, pull code, restart the process. You can automate this with a deploy script or CI/CD pipeline, but the setup is on you.
Best for: MCP servers that need full transport flexibility, predictable costs, and persistent state. The right choice when you want to run the server exactly the way you want.
Deploy pattern:
# On your VPS, using PM2
npm install -g pm2
git clone your-mcp-server /opt/mcp-server
cd /opt/mcp-server && npm ci --production
pm2 start server.js --name mcp-server
pm2 save
pm2 startup
# Reverse proxy with Caddy (auto-TLS)
# Caddyfile
mcp.yourdomain.com {
reverse_proxy localhost:3000
}
Decision framework
Pick based on what matters most for your server:
| Factor | Railway | Cloudflare Workers | VPS |
|---|---|---|---|
| SSE support | Yes | Limited | Yes |
| WebSocket support | Yes | Via Durable Objects | Yes |
| HTTP Streamable | Yes | Yes | Yes |
| Cold starts | Minimal | None | None |
| Auto-scaling | Yes | Yes | No |
| Ops burden | Low | Low | High |
| Cost model | Usage-based | Usage-based (generous free tier) | Fixed monthly |
| Best latency | Regional | Edge (global) | Single region |
Start with Railway if you want the easiest path to a working remote MCP server with SSE support.
Start with Cloudflare Workers if your MCP server is stateless, wraps external APIs, and you want edge latency.
Start with a VPS if you need full control, run multiple servers, or want predictable monthly costs.
Most MCP servers in production today run on Railway or a VPS. Workers are gaining ground as HTTP Streamable transport becomes more common, but persistent-connection servers still need a platform that keeps processes alive.
FAQ
Q: Can I deploy an MCP server on Vercel or Netlify? A: Serverless platforms like Vercel and Netlify are designed for short-lived functions. They work for HTTP Streamable transport where each tool call is an independent request, but they will not support SSE or WebSocket connections. If your server needs persistent connections, use Railway or a VPS instead.
Q: Do I need a custom domain for my MCP server? A: No. Railway and Cloudflare Workers both provide generated URLs that work for MCP connections. A custom domain helps if you want a stable, memorable endpoint or need to set up CORS policies for browser-based MCP clients.
Q: How do I handle authentication on a remote MCP server? A: MCP supports several auth patterns. The simplest is an API key passed as a header or query parameter. For multi-tenant servers, OAuth or x402 payment-gated access are options. See our guide on how MCP auth works for a full breakdown.