This template gives you everything you need to expose any REST API as a set of Model Context Protocol (MCP) tools, resources, and prompts — running globally on the Cloudflare Workers edge with zero cold-starts, sub-millisecond latency, and automatic scaling.
Connect Claude Desktop, Cursor, Continue.dev, or any MCP-compatible AI client to your API in minutes.
- Architecture
- Quickstart
- Project Structure
- Adding MCP Capabilities
- Ingesting API Docs
- Configuration
- Deployment
- Roadmap
- Sponsorship
- Contributing
- License
sequenceDiagram
participant Client as MCP Client<br/>(Claude / Cursor)
participant Worker as Cloudflare Worker<br/>(Hono + MCP SDK)
participant API as External REST API
Client->>Worker: GET /mcp (Authorization: Bearer <key>)
Worker-->>Client: SSE stream established (mcp-session-id header)
Client->>Worker: POST /mcp (mcp-session-id header)
Note over Worker: Routes to McpServer<br/>for this session
Worker->>API: GET /search?q=... (Bearer token)
API-->>Worker: JSON response
Worker-->>Client: SSE: tool result (markdown)
Key design decisions:
- Streamable HTTP transport — uses the MCP SDK's
WebStandardStreamableHTTPServerTransportwith native Cloudflare Workers Web Streams API - Per-session isolation — each
GET /mcpcreates an independentMcpServerinstance - Auth middleware — timing-safe Bearer token check guards all MCP endpoints
- Retry + timeout —
ApiClienthandles 429/5xx with exponential backoff automatically
| Tool | Version |
|---|---|
| Node.js | >= 18.x |
| pnpm | >= 8.x |
| Wrangler | >= 3.x |
# Use this template (GitHub)
gh repo create my-mcp-server --template PCWProps/mcp-server-template --private
cd my-mcp-server
# Install dependencies
pnpm install# Copy the example vars file
cp .dev.vars.example .dev.varsEdit .dev.vars:
TARGET_API_BASE_URL=https://api.example.com
TARGET_API_KEY=your-api-key-here
MCP_AUTH_KEY=your-mcp-auth-key-hereGenerate a secure MCP_AUTH_KEY:
openssl rand -hex 32
pnpm dev
# Wrangler starts at http://localhost:8787# Health check
curl http://localhost:8787/health
# Connect to MCP streamable HTTP endpoint (SSE stream)
curl -N \
-H "Authorization: Bearer your-mcp-auth-key" \
http://localhost:8787/mcpAdd to your Claude Desktop claude_desktop_config.json:
{
"mcpServers": {
"my-api": {
"url": "http://localhost:8787/mcp",
"headers": {
"Authorization": "Bearer your-mcp-auth-key"
}
}
}
}mcp-server-template/
├── src/
│ ├── index.ts # Hono app + SSE/message routing
│ ├── mcp/server.ts # McpServer factory
│ ├── tools/ # MCP tool implementations
│ ├── resources/ # MCP resource implementations
│ ├── prompts/ # MCP prompt templates
│ ├── api/client.ts # Type-safe HTTP client with retry
│ ├── middleware/auth.ts # Bearer token auth middleware
│ └── types/env.d.ts # Cloudflare Worker env bindings
├── scripts/
│ └── ingest-openapi.ts # OpenAPI → MCP tool generator
├── .github/ # GitHub workflows, templates, policies
├── .devcontainer/ # VS Code Dev Container config
├── wrangler.toml # Cloudflare Workers config
└── package.json
// src/tools/my-tool.ts
import { z } from 'zod';
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import type { ApiClient } from '../api/client.js';
export function registerMyTool(server: McpServer, client: ApiClient): void {
server.tool(
'my_tool',
'Description for the AI',
{ query: z.string().describe('Search query') },
async ({ query }) => {
const result = await client.get('/endpoint', { q: query });
return { content: [{ type: 'text', text: `Result: ${JSON.stringify(result)}` }] };
},
);
}Then register in src/tools/index.ts. See CONTRIBUTING.md for the full walkthrough.
Have an OpenAPI 3.x spec? Auto-generate tool skeletons in seconds:
# Place your spec in the project root
cp /path/to/openapi.json ./openapi.json
# Run the ingestion script
pnpm ingest-openapi
# Review and customize generated files in src/tools/
# Then register them in src/tools/index.tsThe script generates:
- A Zod schema from the OpenAPI parameters
- A typed ApiClient call stub
- Markdown-formatted response template
- Full JSDoc documentation
| Variable | Description | Required |
|---|---|---|
TARGET_API_BASE_URL |
Base URL of the external API | ✅ |
TARGET_API_KEY |
API key for the external API | ✅ |
MCP_AUTH_KEY |
Key that MCP clients must present | ✅ |
Set secrets for production:
wrangler secret put TARGET_API_KEY
wrangler secret put MCP_AUTH_KEY# One-command deploy
pnpm deploy
# Deploy to staging environment
pnpm deploy:stagingThe included workflows automate:
- CI — lint, typecheck, and test on every push/PR (Node 18, 20, 22)
- Deploy — automatically deploys to Cloudflare on every push to
main - Release — changesets-based changelog and GitHub Releases
Add these secrets to your GitHub repository:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
- SSE transport for Cloudflare Workers
- Bearer token auth middleware
- Type-safe ApiClient with retry/timeout
- OpenAPI ingestion script
- Example tool, resource, and prompt
- Durable Objects support for multi-instance session state
- OAuth 2.0 / API key rotation support
- Rate limiting middleware
- Streaming tool responses (chunked SSE)
- Tool result caching via KV
- Multi-tenant support (per-user API keys)
- Wrangler AI (Workers AI) integration example
- Metrics and observability dashboard
If this template saves you time, consider supporting continued development:
Your sponsorship funds:
- Keeping dependencies up to date
- Writing tutorials and documentation
- Building new example integrations
- Responding to issues quickly
Contributions are welcome! Please read the Contributing Guidelines before submitting a PR.
