Skip to content

Production Server

Prerequisites

Install MCP Fusion before following this recipe: npm install @vinkius-core/mcp-fusion @modelcontextprotocol/sdk zod — or scaffold a project with npx fusion create.

Introduction

MCP Fusion tools are transport-agnostic — the same ToolRegistry runs on Stdio (local development), HTTP/SSE (persistent servers), and serverless edge runtimes. For edge deployment, the Vercel Adapter turns your registry into a Next.js App Router route with Edge Runtime support (~0ms cold starts), while the Cloudflare Workers Adapter gives your tool handlers direct access to D1, KV, and R2 from 300+ edge locations. For AWS infrastructure, the @vinkius-core/mcp-fusion-aws connector integrates with Lambda and Step Functions. All adapters cache registry compilation at cold start and handle warm requests as stateless JSON-RPC — no SSE sessions, no streaming state, no infrastructure to manage.

Stdio Transport

The simplest deployment. The MCP client spawns your server as a child process:

typescript
import { ToolRegistry } from '@vinkius-core/mcp-fusion';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const registry = new ToolRegistry();
registry.registerAll(...tools);

const server = new McpServer({
  name: 'my-mcp-server',
  version: '1.0.0',
});

registry.attachToServer(server, {
  contextFactory: async (extra) => ({
    db: getDatabaseClient(),
    tenantId: 'default',
  }),
});

const transport = new StdioServerTransport();
await server.connect(transport);

Add to claude_desktop_config.json:

json
{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["tsx", "/path/to/src/server.ts"]
    }
  }
}

HTTP/SSE Transport

For remote servers accessible over the network:

typescript
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express from 'express';

const app = express();
const sessions = new Map<string, SSEServerTransport>();

app.get('/sse', async (req, res) => {
  const transport = new SSEServerTransport('/messages', res);
  sessions.set(transport.sessionId, transport);

  const server = new McpServer({ name: 'my-server', version: '1.0.0' });
  registry.attachToServer(server, {
    contextFactory: async (extra) => ({
      db: getDatabaseClient(),
      tenantId: req.headers['x-tenant-id'] ?? 'default',
    }),
  });

  await server.connect(transport);
});

app.post('/messages', async (req, res) => {
  const sessionId = req.query.sessionId as string;
  const transport = sessions.get(sessionId);
  if (transport) await transport.handlePostMessage(req, res);
});

app.listen(3000);

Cloudflare Workers

See the full Cloudflare Adapter guide. Quick start:

typescript
import { ToolRegistry } from '@vinkius-core/mcp-fusion';
import { McpAgent } from 'agents/mcp';

const registry = new ToolRegistry();
registry.registerAll(...tools);

export class MyMcpAgent extends McpAgent {
  server = new McpServer({ name: 'cf-server', version: '1.0.0' });

  async init() {
    registry.attachToServer(this.server, {
      contextFactory: async () => ({
        db: getDatabaseClient(this.env),
      }),
    });
  }
}

Vercel Edge Functions

See the full Vercel Adapter guide. Quick start:

typescript
import { createMcpHandler } from '@vercel/mcp-adapter';
import { ToolRegistry } from '@vinkius-core/mcp-fusion';

const registry = new ToolRegistry();
registry.registerAll(...tools);

export const GET = createMcpHandler(
  (server) => {
    registry.attachToServer(server, {
      contextFactory: async () => ({
        db: getDatabaseClient(),
      }),
    });
  },
  {},
  { basePath: '/api/mcp', maxDuration: 60 },
);

Graceful Shutdown

Handle SIGTERM and SIGINT for clean shutdown in containerized environments:

typescript
process.on('SIGTERM', async () => {
  console.log('Shutting down gracefully...');
  await server.close();
  await db.$disconnect();
  process.exit(0);
});

process.on('SIGINT', async () => {
  console.log('Interrupted, shutting down...');
  await server.close();
  await db.$disconnect();
  process.exit(0);
});

IMPORTANT

In Docker and Kubernetes, the entrypoint must handle signals. Use exec form in Dockerfile: CMD ["node", "dist/server.js"] (not CMD node dist/server.js).