mcpcraft-sdk

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.ts

Or compile and run:

npm run build
node dist/server.js

Your 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=...&current_weather=true`
    )
    return await res.json()
  }
}))

export default server

Configure Vercel

// vercel.json
{
  "functions": {
    "api/mcp.ts": {
      "maxDuration": 60
    }
  }
}

Set environment variables

vercel env add API_KEY
vercel env add DATABASE_URL

Deploy

vercel deploy --prod

Your server is now live at https://your-project.vercel.app/api/mcp.

Serverless 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-server

Railway

Railway provides easy Node.js deployments with automatic HTTPS and environment variable management.

  1. Create a Dockerfile or use Railway's Node.js builder (auto-detected)
  2. Set environment variables in the Railway dashboard
  3. Deploy by connecting your GitHub repo or using the Railway CLI:
railway up

Railway 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.

  1. Create a Web Service on Render
  2. Connect your repository
  3. Set:
    • Build Command: npm run build
    • Start Command: node dist/server.js
  4. Add environment variables in the Render dashboard
  5. 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 startup

Use 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

ConcernRecommendation
Environment variablesUse .env locally, Vercel env vars or Docker secrets in production
Error monitoringWrap handlers in try/catch and log to stdout/stderr
Rate limitingImplement per-client rate limits if exposing over SSE
AuthenticationUse API keys or JWT for SSE endpoints (stdio is local-only)
Graceful shutdownListen for SIGTERM/SIGINT to close connections cleanly
LoggingStructured JSON logs (pino, console.log with context)
Health checksAdd a ping tool that returns { status: "ok" }