> ## Documentation Index
> Fetch the complete documentation index at: https://learn.orbexa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server deployment and scaling strategies

> MCP Server deployment strategies — local npm package publishing, remote Streamable HTTP deployment, Docker containerization, session management, and scaling

# Deployment Guide

## 9.1 Local Deployment (stdio)

Suitable for personal tools and team internal use.

### npm Package Method

Publish your Server as an npm package; users install it globally and use it directly:

```bash theme={null}
# Publish
npm publish

# User installs
npm install -g my-commerce-server

# Claude Desktop configuration
{
  "mcpServers": {
    "my-store": {
      "command": "my-commerce-server",
      "env": { "DB_URL": "..." }
    }
  }
}
```

### Direct Execution Method

Without publishing an npm package, specify the script path directly:

```json theme={null}
{
  "mcpServers": {
    "my-store": {
      "command": "node",
      "args": ["/absolute/path/to/dist/index.js"],
      "env": { "DB_URL": "..." }
    }
  }
}
```

### Python Server Local Deployment

```json theme={null}
{
  "mcpServers": {
    "my-python-server": {
      "command": "python",
      "args": ["/absolute/path/to/server.py"],
      "env": { "API_KEY": "..." }
    }
  }
}
```

## 9.2 Remote Deployment (Streamable HTTP)

Suitable for SaaS services serving external users.

### Complete Express.js Streamable HTTP Server

```typescript theme={null}
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

const app = express();
app.use(express.json());

// Session storage (use Redis or another external store in production)
const sessions = new Map();

app.post("/mcp", async (req, res) => {
  const sessionId = req.headers["mcp-session-id"];

  if (sessionId && sessions.has(sessionId)) {
    // Existing session, reuse
    const transport = sessions.get(sessionId);
    await transport.handlePost(req, res);
  } else {
    // New session
    const transport = new StreamableHTTPServerTransport({
      endpoint: "/mcp"
    });
    const server = createMcpServer(); // Your Server factory function
    await server.connect(transport);

    // Save session
    const newSessionId = transport.getSessionId();
    sessions.set(newSessionId, transport);

    await transport.handlePost(req, res);
  }
});

// SSE endpoint (optional, for Server-initiated pushes)
app.get("/mcp", async (req, res) => {
  const sessionId = req.headers["mcp-session-id"];
  const transport = sessions.get(sessionId);
  if (transport) {
    await transport.handleGet(req, res);
  } else {
    res.status(404).end();
  }
});

// Health check
app.get("/health", (req, res) => {
  res.json({ status: "ok", activeSessions: sessions.size });
});

app.listen(3000, () => {
  console.error("MCP Server (Streamable HTTP) running on port 3000");
});
```

### Docker Deployment

```dockerfile theme={null}
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
COPY dist/ ./dist/
EXPOSE 3000
CMD ["node", "dist/server-http.js"]
```

### Cloud Platform Deployment

| Platform               | Approach         | Advantages                                | Considerations                                             |
| ---------------------- | ---------------- | ----------------------------------------- | ---------------------------------------------------------- |
| **Vercel**             | Edge Function    | Global CDN, auto-scaling                  | Stateless; requires external session storage               |
| **Railway**            | Docker container | Simple deployment, persistent connections | Good for stateful Servers                                  |
| **AWS Lambda**         | Serverless       | Pay-per-invocation                        | Cold start latency; mind the timeout                       |
| **Cloudflare Workers** | Edge Worker      | Ultra-low latency                         | Stateless; requires Durable Objects for session management |
| **Self-hosted**        | PM2 + Nginx      | Full control                              | Requires self-maintenance                                  |

## 9.3 Session Management

Streamable HTTP is a stateful protocol; the `Mcp-Session-Id` header maintains sessions. Production deployments must address the following:

### Stateless Deployment (Multiple Instances)

If the Server is deployed across multiple instances (e.g., K8s Pods), external session storage is needed:

```typescript theme={null}
// Use Redis for session state storage
import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL);

app.post("/mcp", async (req, res) => {
  const sessionId = req.headers["mcp-session-id"];
  if (sessionId) {
    const sessionData = await redis.get(`mcp:session:${sessionId}`);
    // Restore session...
  }
});
```

### Session Cleanup

Set reasonable session timeouts and cleanup policies:

```typescript theme={null}
// Session timeout: clean up after 30 minutes of inactivity
const SESSION_TTL = 30 * 60 * 1000;

setInterval(() => {
  for (const [id, session] of sessions) {
    if (Date.now() - session.lastActivity > SESSION_TTL) {
      session.transport.close();
      sessions.delete(id);
    }
  }
}, 60 * 1000); // Check every minute
```

## 9.4 Client Connection Configuration

### Remote Server (Streamable HTTP)

```json theme={null}
{
  "mcpServers": {
    "my-remote-store": {
      "url": "https://mcp.mystore.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TOKEN"
      }
    }
  }
}
```

### Remote Server with OAuth

When the Server implements the full OAuth 2.1 flow, the Host application handles authentication automatically; the user only needs to provide the Server URL:

```json theme={null}
{
  "mcpServers": {
    "my-oauth-store": {
      "url": "https://mcp.mystore.com/mcp"
    }
  }
}
```

The Host automatically discovers the Server's OAuth configuration (via Protected Resource Metadata) and guides the user through authorization.

## 9.5 Monitoring and Logging

Recommended for production environments:

### Health Check

```typescript theme={null}
app.get("/health", (req, res) => {
  res.json({
    status: "ok",
    version: "1.0.0",
    activeSessions: sessions.size,
    uptime: process.uptime()
  });
});
```

### Request Logging

```typescript theme={null}
// Log every tool call
function logToolCall(method, params, duration, error) {
  console.error(JSON.stringify({
    timestamp: new Date().toISOString(),
    method,
    tool: params?.name,
    duration_ms: duration,
    error: error?.message
  }));
}
```

### Monitoring Metrics

| Metric                      | Description                            | Alert Threshold                         |
| --------------------------- | -------------------------------------- | --------------------------------------- |
| P95 response time           | 95th percentile latency for tool calls | Depends on business; typically under 5s |
| Error rate                  | Proportion of failed tool calls        | Alert above 5%                          |
| Active sessions             | Number of currently connected Clients  | Alert when approaching server capacity  |
| Initialization success rate | MCP handshake success rate             | Investigate below 99%                   |

### Reconnection Recovery

Streamable HTTP supports reconnection recovery via SSE's `Last-Event-ID`. In production, the Server should maintain an event ID sequence so Clients can resume from the disconnection point:

```typescript theme={null}
// Server-side event sequence management
let eventCounter = 0;

function sendNotification(sessionId, data) {
  eventCounter++;
  const event = {
    id: `evt-${eventCounter}`,
    data: JSON.stringify(data)
  };
  // Send SSE event and persist (for reconnection recovery)
  sendSSEEvent(sessionId, event);
  persistEvent(sessionId, event);
}
```

***

**Next Chapter**: [Case Studies](/en/book-5/ch10-case-studies) — MCP Server implementations for different scenarios
