Local MCP servers with stdio transport are great for single-user setups. The moment you want a team, an integration partner, or any remote consumer, you need a hosted MCP server speaking HTTP + Server-Sent Events. Here is a production-ready recipe: Docker container, Cloudflare Tunnel, structured logging, zero-downtime updates.
Stdio vs HTTP transport
MCP supports two transports:
- stdio — client launches the server as a subprocess. Perfect for Claude Desktop / Cursor running on your machine.
- HTTP + SSE — remote server, clients connect over the network. What you need for anything multi-user.
The MCP SDK handles both. You pick the transport at server startup.
Step 1: wrap your server for HTTP transport
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express from 'express';
const app = express();
const server = new Server({ name: 'my-mcp', version: '1.0.0' }, { capabilities: { tools: {} } });
// ... register your tools on 'server' (same as stdio version)
const transports = new Map();
app.get('/sse', async (_req, res) => {
const transport = new SSEServerTransport('/messages', res);
transports.set(transport.sessionId, transport);
res.on('close', () => transports.delete(transport.sessionId));
await server.connect(transport);
});
app.post('/messages', express.json(), async (req, res) => {
const sessionId = req.query.sessionId;
const transport = transports.get(sessionId);
if (!transport) return res.status(404).end();
await transport.handlePostMessage(req, res);
});
app.listen(process.env.PORT ?? 3000);
Step 2: Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY dist ./dist
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]
Non-root user, multi-stage for smaller image (150 MB vs 800 MB for single-stage). Build and push:
docker build -t ghcr.io/yourorg/my-mcp:latest .
docker push ghcr.io/yourorg/my-mcp:latest
Step 3: run somewhere with edge access
Three good options:
- Fly.io —
fly launch+fly deploy. Global edge for $3-10/mo. - Railway — paste your GHCR image URL. $5/mo hobby.
- VPS + Cloudflare Tunnel — most control, best privacy. $5/mo Hetzner + free Cloudflare Tunnel.
For the Cloudflare Tunnel path (what we recommend for MCP because it avoids exposing ports):
# On your VPS:
docker run -d --name my-mcp --restart unless-stopped \
-p 127.0.0.1:3000:3000 \
-e SOMETOKEN=$SOMETOKEN \
ghcr.io/yourorg/my-mcp:latest
# Install cloudflared:
cloudflared tunnel create my-mcp
cloudflared tunnel route dns my-mcp mcp.example.com
cloudflared tunnel run my-mcp
The MCP server is reachable at https://mcp.example.com/sse without any port open to the public internet.
Step 4: MCP client config
{
"mcpServers": {
"my-mcp": {
"url": "https://mcp.example.com/sse",
"headers": { "Authorization": "Bearer ${SERVICE_TOKEN}" }
}
}
}
Step 5: observability that matters
Three metrics every hosted MCP server must emit:
mcp_tool_calls_total{tool, status}— countermcp_tool_call_duration_seconds{tool}— histogrammcp_active_sessions— gauge
Add structured logs with session_id so you can reconstruct every agent conversation. Pipe to Sentry for errors, Grafana for metrics.
Step 6: zero-downtime updates
MCP sessions are long-lived. A naive container restart drops every connected agent mid-conversation. Two patterns:
- Blue-green via Cloudflare: two instances, Cloudflare rules flip traffic. Old stays up until its sessions drain.
- Graceful shutdown: on SIGTERM, stop accepting new SSE connections but keep existing ones alive up to 5 minutes, then exit.
Security considerations
A hosted MCP server is a new API on the internet. Same rules as any other API:
- Require auth (bearer token minimum; mTLS or JWT for multi-tenant).
- Rate-limit per session. One compromised token should not DoS your backend.
- Sanitize tool outputs — never reflect user input unescaped.
- Log sessionId with every tool call for forensics.
See our MCP security best practices for the full checklist.
Submit your deployed server
Once live, submit it to Loadout. Free review, 24h turnaround, brings in developer traffic that already knows how to install MCP servers.