Deployment
Deploy your MCP server to production — Vercel, Docker, Railway, Render, and more.
Deployment
MCP servers communicate over stdio (standard input/output) or SSE (server-sent events). The transport determines where and how you deploy.
Local Development
For local testing, run your server with ts-node or tsx:
npx tsx server.tsOr compile and run:
npm run build
node dist/server.jsYour server listens on stdio by default. Connect using the MCP Inspector or Claude Desktop.
stdio (Local & Desktop)
Stdio is the simplest transport — your server runs as a child process of the MCP client. No network setup, no ports.
Use when: running with Claude Desktop, VS Code Copilot, or local development.
// claude_desktop_config.json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["dist/server.js"],
"env": {
"API_KEY": "sk-..."
}
}
}
}No deployment needed — just build and point the config to your script.
Vercel (Serverless)
For remote access, deploy your MCP server as a Vercel serverless function. The function listens for incoming SSE connections from MCP clients.
Create the API route
// api/mcp.ts
import { createServer, tool } from "mcpcraft-sdk"
const server = createServer({ name: "my-server" })
server.add(tool({
name: "get_weather",
description: "Fetches weather for a city",
input: {
city: { type: "string", description: "City name" }
},
run: async ({ city }) => {
const res = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=...¤t_weather=true`
)
return await res.json()
}
}))
export default serverConfigure Vercel
// vercel.json
{
"functions": {
"api/mcp.ts": {
"maxDuration": 60
}
}
}Set environment variables
vercel env add API_KEY
vercel env add DATABASE_URLServerless functions have cold starts and execution time limits. For latency-sensitive workloads, consider a long-running container instead.
Docker
For full control over runtime and scaling, or for deploying to container platforms.
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY dist/ ./dist/
EXPOSE 3000
CMD ["node", "dist/server.js"]docker build -t mcp-server .
docker run -e API_KEY=sk-... mcp-serverRailway
Railway provides easy Node.js deployments with automatic HTTPS and environment variable management.
- Create a
Dockerfileor use Railway's Node.js builder (auto-detected) - Set environment variables in the Railway dashboard
- Deploy by connecting your GitHub repo or using the Railway CLI:
railway upRailway assigns a *.railway.app URL. Use this as your SSE endpoint.
Render
Render supports Node.js web services with free SSL and auto-deploys from Git.
- Create a Web Service on Render
- Connect your repository
- Set:
- Build Command:
npm run build - Start Command:
node dist/server.js
- Build Command:
- Add environment variables in the Render dashboard
- Deploy
Your server will be available at https://your-service.onrender.com.
VPS (Bare Metal)
For maximum control, run your server on any VPS (DigitalOcean, Hetzner, AWS EC2).
# Build
npm run build
# Run with process manager
npm install -g pm2
pm2 start dist/server.js --name mcp-server
pm2 save
pm2 startupUse a reverse proxy (nginx, Caddy) if exposing over SSE:
server {
listen 80;
server_name mcp.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Production Checklist
| Concern | Recommendation |
|---|---|
| Environment variables | Use .env locally, Vercel env vars or Docker secrets in production |
| Error monitoring | Wrap handlers in try/catch and log to stdout/stderr |
| Rate limiting | Implement per-client rate limits if exposing over SSE |
| Authentication | Use API keys or JWT for SSE endpoints (stdio is local-only) |
| Graceful shutdown | Listen for SIGTERM/SIGINT to close connections cleanly |
| Logging | Structured JSON logs (pino, console.log with context) |
| Health checks | Add a ping tool that returns { status: "ok" } |