typescript-mcp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TypeScript MCP Server on Cloudflare Workers

在Cloudflare Workers上构建TypeScript MCP服务器

Build production-ready Model Context Protocol (MCP) servers using TypeScript and deploy them on Cloudflare Workers. This skill covers the official
@modelcontextprotocol/sdk
, HTTP transport setup, authentication patterns, Cloudflare service integrations, and comprehensive error prevention.

使用TypeScript构建可投入生产的Model Context Protocol(MCP)服务器,并部署到Cloudflare Workers。本技能涵盖官方
@modelcontextprotocol/sdk
、HTTP传输配置、认证模式、Cloudflare服务集成以及全面的错误预防方案。

When to Use This Skill

适用场景

Use this skill when:
  • Building MCP servers to expose APIs, tools, or data to LLMs
  • Deploying serverless MCP endpoints on Cloudflare Workers
  • Integrating external APIs as MCP tools (REST, GraphQL, databases)
  • Creating stateless MCP servers for edge deployment
  • Exposing Cloudflare services (D1, KV, R2, Vectorize) via MCP protocol
  • Implementing authenticated MCP servers with API keys, OAuth, or Zero Trust
  • Building multi-tool MCP servers with resources and prompts
  • Needing production-ready templates that prevent common MCP errors
Do NOT use this skill when:
  • Building Python MCP servers (use FastMCP skill instead)
  • Needing stateful agents with WebSockets (use Cloudflare Agents SDK)
  • Wanting long-running persistent agents with SQLite storage (use Durable Objects)
  • Building local CLI tools (use stdio transport, not HTTP)

在以下场景中使用本技能:
  • 构建MCP服务器,向LLM暴露API、工具或数据
  • 在Cloudflare Workers上部署无服务器MCP端点
  • 外部API集成作为MCP工具(REST、GraphQL、数据库)
  • 创建用于边缘部署的无状态MCP服务器
  • 通过MCP协议暴露Cloudflare服务(D1、KV、R2、Vectorize)
  • 实现支持API密钥、OAuth或Zero Trust的认证MCP服务器
  • 构建包含资源与提示词的多工具MCP服务器
  • 需要可预防常见MCP错误的生产就绪模板
请勿在以下场景使用本技能
  • 构建Python MCP服务器(请改用FastMCP技能)
  • 需要带WebSocket的有状态Agent(请使用Cloudflare Agents SDK)
  • 想要带SQLite存储的长期运行持久化Agent(请使用Durable Objects)
  • 构建本地CLI工具(请使用stdio传输而非HTTP)

Core Concepts

核心概念

MCP Protocol Components

MCP协议组件

1. Tools - Functions LLMs can invoke
  • Input/output schemas defined with Zod
  • Async handlers return structured content
  • Can call external APIs, databases, or computations
2. Resources - Static or dynamic data exposure
  • URI-based addressing (e.g.,
    config://app/settings
    )
  • Templates support parameters (e.g.,
    user://{userId}
    )
  • Return text, JSON, or binary data
3. Prompts - Pre-configured prompt templates
  • Provide reusable conversation starters
  • Can include placeholders and dynamic content
  • Help standardize LLM interactions
4. Completions (Optional) - Argument auto-complete
  • Suggest valid values for tool arguments
  • Improve developer experience

1. 工具(Tools) - LLM可调用的函数
  • 使用Zod定义输入/输出Schema
  • 异步处理器返回结构化内容
  • 可调用外部API、数据库或执行计算
2. 资源(Resources) - 静态或动态数据暴露
  • 基于URI的寻址方式(例如:
    config://app/settings
  • 模板支持参数(例如:
    user://{userId}
  • 返回文本、JSON或二进制数据
3. 提示词(Prompts) - 预配置的提示词模板
  • 提供可复用的对话起始内容
  • 可包含占位符与动态内容
  • 帮助标准化LLM交互流程
4. 自动补全(Completions)(可选) - 工具参数自动补全
  • 为工具参数建议有效值
  • 提升开发者体验

Quick Start

快速开始

1. Basic MCP Server Template

1. 基础MCP服务器模板

Use the
basic-mcp-server.ts
template for a minimal working server:
typescript
// See templates/basic-mcp-server.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { Hono } from 'hono';
import { z } from 'zod';

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

// Register a simple tool
server.registerTool(
  'echo',
  {
    description: 'Echoes back the input text',
    inputSchema: z.object({
      text: z.string().describe('Text to echo back')
    })
  },
  async ({ text }) => ({
    content: [{ type: 'text', text }]
  })
);

// HTTP endpoint setup
const app = new Hono();

app.post('/mcp', async (c) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
    enableJsonResponse: true
  });

  // CRITICAL: Close transport on response end to prevent memory leaks
  c.res.raw.on('close', () => transport.close());

  await server.connect(transport);
  await transport.handleRequest(c.req.raw, c.res.raw, await c.req.json());

  return c.body(null);
});

export default app;
Install dependencies:
bash
npm install @modelcontextprotocol/sdk hono zod
npm install -D @cloudflare/workers-types wrangler typescript
Deploy:
bash
wrangler deploy

使用
basic-mcp-server.ts
模板搭建最简可用服务器:
typescript
// 参见 templates/basic-mcp-server.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { Hono } from 'hono';
import { z } from 'zod';

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

// 注册一个简单工具
server.registerTool(
  'echo',
  {
    description: 'Echoes back the input text',
    inputSchema: z.object({
      text: z.string().describe('Text to echo back')
    })
  },
  async ({ text }) => ({
    content: [{ type: 'text', text }]
  })
);

// HTTP端点配置
const app = new Hono();

app.post('/mcp', async (c) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
    enableJsonResponse: true
  });

  // 关键:在响应结束时关闭传输连接以防止内存泄漏
  c.res.raw.on('close', () => transport.close());

  await server.connect(transport);
  await transport.handleRequest(c.req.raw, c.res.raw, await c.req.json());

  return c.body(null);
});

export default app;
安装依赖
bash
npm install @modelcontextprotocol/sdk hono zod
npm install -D @cloudflare/workers-types wrangler typescript
部署
bash
wrangler deploy

2. Tool-Server Template

2. 工具服务器模板

Use
tool-server.ts
for exposing multiple tools (API integrations, calculations):
typescript
// Example: Weather API tool
server.registerTool(
  'get-weather',
  {
    description: 'Fetches current weather for a city',
    inputSchema: z.object({
      city: z.string().describe('City name'),
      units: z.enum(['metric', 'imperial']).default('metric')
    })
  },
  async ({ city, units }, env) => {
    const response = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=${units}&appid=${env.WEATHER_API_KEY}`
    );
    const data = await response.json();

    return {
      content: [{
        type: 'text',
        text: `Temperature in ${city}: ${data.main.temp}°${units === 'metric' ? 'C' : 'F'}`
      }]
    };
  }
);

使用
tool-server.ts
暴露多个工具(API集成、计算功能):
typescript
// 示例:天气API工具
server.registerTool(
  'get-weather',
  {
    description: 'Fetches current weather for a city',
    inputSchema: z.object({
      city: z.string().describe('City name'),
      units: z.enum(['metric', 'imperial']).default('metric')
    })
  },
  async ({ city, units }, env) => {
    const response = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=${units}&appid=${env.WEATHER_API_KEY}`
    );
    const data = await response.json();

    return {
      content: [{
        type: 'text',
        text: `Temperature in ${city}: ${data.main.temp}°${units === 'metric' ? 'C' : 'F'}`
      }]
    };
  }
);

3. Resource-Server Template

3. 资源服务器模板

Use
resource-server.ts
for exposing data:
typescript
import { ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';

// Static resource
server.registerResource(
  'config',
  new ResourceTemplate('config://app', { list: undefined }),
  { description: 'Application configuration' },
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: 'application/json',
      text: JSON.stringify({ version: '1.0.0', features: ['tool1', 'tool2'] })
    }]
  })
);

// Dynamic resource with parameter
server.registerResource(
  'user-profile',
  new ResourceTemplate('user://{userId}', { list: undefined }),
  { description: 'User profile data' },
  async (uri, { userId }, env) => {
    const user = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();

    return {
      contents: [{
        uri: uri.href,
        mimeType: 'application/json',
        text: JSON.stringify(user)
      }]
    };
  }
);

使用
resource-server.ts
暴露数据:
typescript
import { ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';

// 静态资源
server.registerResource(
  'config',
  new ResourceTemplate('config://app', { list: undefined }),
  { description: 'Application configuration' },
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: 'application/json',
      text: JSON.stringify({ version: '1.0.0', features: ['tool1', 'tool2'] })
    }]
  })
);

// 带参数的动态资源
server.registerResource(
  'user-profile',
  new ResourceTemplate('user://{userId}', { list: undefined }),
  { description: 'User profile data' },
  async (uri, { userId }, env) => {
    const user = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();

    return {
      contents: [{
        uri: uri.href,
        mimeType: 'application/json',
        text: JSON.stringify(user)
      }]
    };
  }
);

4. Authenticated Server Template

4. 认证服务器模板

Use
authenticated-server.ts
for production security:
typescript
import { Hono } from 'hono';

const app = new Hono();

// API Key authentication middleware
app.use('/mcp', async (c, next) => {
  const authHeader = c.req.header('Authorization');
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return c.json({ error: 'Unauthorized' }, 401);
  }

  const apiKey = authHeader.replace('Bearer ', '');
  const isValid = await c.env.MCP_API_KEYS.get(`key:${apiKey}`);

  if (!isValid) {
    return c.json({ error: 'Invalid API key' }, 403);
  }

  await next();
});

app.post('/mcp', async (c) => {
  // MCP server logic (user is authenticated)
  // ... transport setup and handling
});

使用
authenticated-server.ts
实现生产级安全:
typescript
import { Hono } from 'hono';

const app = new Hono();

// API密钥认证中间件
app.use('/mcp', async (c, next) => {
  const authHeader = c.req.header('Authorization');
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return c.json({ error: 'Unauthorized' }, 401);
  }

  const apiKey = authHeader.replace('Bearer ', '');
  const isValid = await c.env.MCP_API_KEYS.get(`key:${apiKey}`);

  if (!isValid) {
    return c.json({ error: 'Invalid API key' }, 403);
  }

  await next();
});

app.post('/mcp', async (c) => {
  // MCP服务器逻辑(用户已通过认证)
  // ... 传输配置与处理逻辑
});

Authentication Patterns

认证模式

Pattern 1: API Key (Recommended for Most Cases)

模式1:API密钥(推荐用于多数场景)

Setup:
  1. Create KV namespace:
    wrangler kv namespace create MCP_API_KEYS
  2. Add to
    wrangler.jsonc
    :
jsonc
{
  "kv_namespaces": [
    { "binding": "MCP_API_KEYS", "id": "YOUR_NAMESPACE_ID" }
  ]
}
Implementation:
typescript
async function verifyApiKey(key: string, env: Env): Promise<boolean> {
  const storedKey = await env.MCP_API_KEYS.get(`key:${key}`);
  return storedKey !== null;
}
Manage keys:
bash
undefined
配置步骤
  1. 创建KV命名空间:
    wrangler kv namespace create MCP_API_KEYS
  2. 添加到
    wrangler.jsonc
jsonc
{
  "kv_namespaces": [
    { "binding": "MCP_API_KEYS", "id": "YOUR_NAMESPACE_ID" }
  ]
}
实现代码
typescript
async function verifyApiKey(key: string, env: Env): Promise<boolean> {
  const storedKey = await env.MCP_API_KEYS.get(`key:${key}`);
  return storedKey !== null;
}
密钥管理
bash
undefined

Add key

添加密钥

wrangler kv key put --binding=MCP_API_KEYS "key:abc123" "true"
wrangler kv key put --binding=MCP_API_KEYS "key:abc123" "true"

Revoke key

吊销密钥

wrangler kv key delete --binding=MCP_API_KEYS "key:abc123"
undefined
wrangler kv key delete --binding=MCP_API_KEYS "key:abc123"
undefined

Pattern 2: Cloudflare Zero Trust Access

模式2:Cloudflare Zero Trust访问

typescript
import { verifyJWT } from '@cloudflare/workers-jwt';

const jwt = c.req.header('Cf-Access-Jwt-Assertion');
if (!jwt) {
  return c.json({ error: 'Access denied' }, 403);
}

const payload = await verifyJWT(jwt, c.env.CF_ACCESS_TEAM_DOMAIN);
// User authenticated via Cloudflare Access
typescript
import { verifyJWT } from '@cloudflare/workers-jwt';

const jwt = c.req.header('Cf-Access-Jwt-Assertion');
if (!jwt) {
  return c.json({ error: 'Access denied' }, 403);
}

const payload = await verifyJWT(jwt, c.env.CF_ACCESS_TEAM_DOMAIN);
// 用户已通过Cloudflare Access认证

Pattern 3: OAuth 2.0

模式3:OAuth 2.0

See
references/authentication-guide.md
for complete OAuth implementation.

完整OAuth实现请参见
references/authentication-guide.md

Cloudflare Service Integration

Cloudflare服务集成

D1 Database Tool Example

D1数据库工具示例

typescript
server.registerTool(
  'query-database',
  {
    description: 'Executes SQL query on D1 database',
    inputSchema: z.object({
      query: z.string(),
      params: z.array(z.union([z.string(), z.number()])).optional()
    })
  },
  async ({ query, params }, env) => {
    const result = await env.DB.prepare(query).bind(...(params || [])).all();

    return {
      content: [{
        type: 'text',
        text: JSON.stringify(result.results, null, 2)
      }]
    };
  }
);
Wrangler config:
jsonc
{
  "d1_databases": [
    { "binding": "DB", "database_name": "my-db", "database_id": "..." }
  ]
}
typescript
server.registerTool(
  'query-database',
  {
    description: 'Executes SQL query on D1 database',
    inputSchema: z.object({
      query: z.string(),
      params: z.array(z.union([z.string(), z.number()])).optional()
    })
  },
  async ({ query, params }, env) => {
    const result = await env.DB.prepare(query).bind(...(params || [])).all();

    return {
      content: [{
        type: 'text',
        text: JSON.stringify(result.results, null, 2)
      }]
    };
  }
);
Wrangler配置
jsonc
{
  "d1_databases": [
    { "binding": "DB", "database_name": "my-db", "database_id": "..." }
  ]
}

KV Storage Tool Example

KV存储工具示例

typescript
server.registerTool(
  'get-cache',
  {
    description: 'Retrieves cached value by key',
    inputSchema: z.object({ key: z.string() })
  },
  async ({ key }, env) => {
    const value = await env.CACHE.get(key);
    return {
      content: [{ type: 'text', text: value || 'Key not found' }]
    };
  }
);
typescript
server.registerTool(
  'get-cache',
  {
    description: 'Retrieves cached value by key',
    inputSchema: z.object({ key: z.string() })
  },
  async ({ key }, env) => {
    const value = await env.CACHE.get(key);
    return {
      content: [{ type: 'text', text: value || 'Key not found' }]
    };
  }
);

R2 Object Storage Tool Example

R2对象存储工具示例

typescript
server.registerTool(
  'upload-file',
  {
    description: 'Uploads file to R2 bucket',
    inputSchema: z.object({
      key: z.string(),
      content: z.string(),
      contentType: z.string().optional()
    })
  },
  async ({ key, content, contentType }, env) => {
    await env.BUCKET.put(key, content, {
      httpMetadata: { contentType: contentType || 'text/plain' }
    });

    return {
      content: [{ type: 'text', text: `File uploaded: ${key}` }]
    };
  }
);
typescript
server.registerTool(
  'upload-file',
  {
    description: 'Uploads file to R2 bucket',
    inputSchema: z.object({
      key: z.string(),
      content: z.string(),
      contentType: z.string().optional()
    })
  },
  async ({ key, content, contentType }, env) => {
    await env.BUCKET.put(key, content, {
      httpMetadata: { contentType: contentType || 'text/plain' }
    });

    return {
      content: [{ type: 'text', text: `File uploaded: ${key}` }]
    };
  }
);

Vectorize Search Tool Example

Vectorize搜索工具示例

typescript
server.registerTool(
  'semantic-search',
  {
    description: 'Searches vector database',
    inputSchema: z.object({
      query: z.string(),
      topK: z.number().default(5)
    })
  },
  async ({ query, topK }, env) => {
    const embedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
      text: query
    });

    const results = await env.VECTORIZE.query(embedding.data[0], {
      topK,
      returnMetadata: true
    });

    return {
      content: [{
        type: 'text',
        text: JSON.stringify(results.matches, null, 2)
      }]
    };
  }
);

typescript
server.registerTool(
  'semantic-search',
  {
    description: 'Searches vector database',
    inputSchema: z.object({
      query: z.string(),
      topK: z.number().default(5)
    })
  },
  async ({ query, topK }, env) => {
    const embedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
      text: query
    });

    const results = await env.VECTORIZE.query(embedding.data[0], {
      topK,
      returnMetadata: true
    });

    return {
      content: [{
        type: 'text',
        text: JSON.stringify(results.matches, null, 2)
      }]
    };
  }
);

Testing Strategies

测试策略

1. Unit Testing with Vitest

1. 使用Vitest进行单元测试

typescript
import { describe, it, expect } from 'vitest';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

describe('Calculator Tool', () => {
  it('should add two numbers', async () => {
    const server = new McpServer({ name: 'test', version: '1.0.0' });

    server.registerTool(
      'add',
      {
        description: 'Adds two numbers',
        inputSchema: z.object({
          a: z.number(),
          b: z.number()
        })
      },
      async ({ a, b }) => ({
        content: [{ type: 'text', text: String(a + b) }]
      })
    );

    // Test tool execution
    const result = await server.callTool('add', { a: 5, b: 3 });
    expect(result.content[0].text).toBe('8');
  });
});
Install:
bash
npm install -D vitest @cloudflare/vitest-pool-workers
Run:
bash
npx vitest
typescript
import { describe, it, expect } from 'vitest';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

describe('Calculator Tool', () => {
  it('should add two numbers', async () => {
    const server = new McpServer({ name: 'test', version: '1.0.0' });

    server.registerTool(
      'add',
      {
        description: 'Adds two numbers',
        inputSchema: z.object({
          a: z.number(),
          b: z.number()
        })
      },
      async ({ a, b }) => ({
        content: [{ type: 'text', text: String(a + b) }]
      })
    );

    // 测试工具执行
    const result = await server.callTool('add', { a: 5, b: 3 });
    expect(result.content[0].text).toBe('8');
  });
});
安装依赖
bash
npm install -D vitest @cloudflare/vitest-pool-workers
运行测试
bash
npx vitest

2. Integration Testing with MCP Inspector

2. 使用MCP Inspector进行集成测试

bash
undefined
bash
undefined

Run server locally

本地运行服务器

npm run dev
npm run dev

In another terminal

在另一个终端执行

npx @modelcontextprotocol/inspector
npx @modelcontextprotocol/inspector
undefined
undefined

3. E2E Testing with Claude Agent SDK

3. 使用Claude Agent SDK进行端到端测试

See
references/testing-guide.md
for comprehensive testing patterns.

全面测试模式请参见
references/testing-guide.md

Known Issues Prevention

已知问题预防

This skill prevents 10+ production issues documented in official MCP SDK and Cloudflare repos:
本技能可预防官方MCP SDK与Cloudflare仓库中记录的10余种生产环境问题:

Issue #1: Export Syntax Issues (CRITICAL)

问题1:导出语法问题(严重)

Error:
"Cannot read properties of undefined (reading 'map')"
Source: honojs/hono#3955, honojs/vite-plugins#237 Why It Happens: Incorrect export format with Vite build causes cryptic errors Prevention:
typescript
// ❌ WRONG - Causes cryptic build errors
export default { fetch: app.fetch };

// ✅ CORRECT - Direct export
export default app;
错误信息
"Cannot read properties of undefined (reading 'map')"
来源:honojs/hono#3955, honojs/vite-plugins#237 问题原因:Vite构建时使用错误的导出格式导致模糊错误 预防方案
typescript
// ❌ 错误写法 - 会导致构建错误
export default { fetch: app.fetch };

// ✅ 正确写法 - 直接导出
export default app;

Issue #2: Unclosed Transport Connections

问题2:未关闭传输连接

Error: Memory leaks, hanging connections Source: Best practice from SDK maintainers Why It Happens: Not closing StreamableHTTPServerTransport on request end Prevention:
typescript
app.post('/mcp', async (c) => {
  const transport = new StreamableHTTPServerTransport(/*...*/);

  // CRITICAL: Always close on response end
  c.res.raw.on('close', () => transport.close());

  // ... handle request
});
错误影响:内存泄漏、连接挂起 来源:SDK维护者推荐的最佳实践 问题原因:未在请求结束时关闭StreamableHTTPServerTransport 预防方案
typescript
app.post('/mcp', async (c) => {
  const transport = new StreamableHTTPServerTransport(/*...*/);

  // 关键:务必在响应结束时关闭连接
  c.res.raw.on('close', () => transport.close());

  // ... 请求处理逻辑
});

Issue #3: Tool Schema Validation Failure

问题3:工具Schema验证失败

Error:
ListTools request handler fails to generate inputSchema
Source: GitHub modelcontextprotocol/typescript-sdk#1028 Why It Happens: Zod schemas not properly converted to JSON Schema Prevention:
typescript
// ✅ CORRECT - SDK handles Zod schema conversion automatically
server.registerTool(
  'tool-name',
  {
    inputSchema: z.object({ a: z.number() })
  },
  handler
);

// No need for manual zodToJsonSchema() unless custom validation
错误信息
ListTools request handler fails to generate inputSchema
来源:GitHub modelcontextprotocol/typescript-sdk#1028 问题原因:Zod Schema未正确转换为JSON Schema 预防方案
typescript
// ✅ 正确写法 - SDK会自动处理Zod Schema转换
server.registerTool(
  'tool-name',
  {
    inputSchema: z.object({ a: z.number() })
  },
  handler
);

// 除非需要自定义验证,否则无需手动调用zodToJsonSchema()

Issue #4: Tool Arguments Not Passed to Handler

问题4:工具参数未传递到处理器

Error: Handler receives
undefined
arguments Source: GitHub modelcontextprotocol/typescript-sdk#1026 Why It Happens: Schema type mismatch between registration and invocation Prevention:
typescript
const schema = z.object({ a: z.number(), b: z.number() });
type Input = z.infer<typeof schema>;

server.registerTool(
  'add',
  { inputSchema: schema },
  async (args: Input) => {
    // args.a and args.b properly typed and passed
    return { content: [{ type: 'text', text: String(args.a + args.b) }] };
  }
);
错误影响:处理器收到
undefined
参数 来源:GitHub modelcontextprotocol/typescript-sdk#1026 问题原因:注册与调用时的Schema类型不匹配 预防方案
typescript
const schema = z.object({ a: z.number(), b: z.number() });
type Input = z.infer<typeof schema>;

server.registerTool(
  'add',
  { inputSchema: schema },
  async (args: Input) => {
    // args.a与args.b会被正确类型化并传递
    return { content: [{ type: 'text', text: String(args.a + args.b) }] };
  }
);

Issue #5: CORS Misconfiguration

问题5:CORS配置错误

Error: Browser clients can't connect to MCP server Source: Common production issue Why It Happens: Missing CORS headers for HTTP transport Prevention:
typescript
import { cors } from 'hono/cors';

app.use('/mcp', cors({
  origin: ['http://localhost:3000', 'https://your-app.com'],
  allowMethods: ['POST', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization']
}));
错误影响:浏览器客户端无法连接MCP服务器 来源:常见生产环境问题 问题原因:HTTP传输缺少CORS头 预防方案
typescript
import { cors } from 'hono/cors';

app.use('/mcp', cors({
  origin: ['http://localhost:3000', 'https://your-app.com'],
  allowMethods: ['POST', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization']
}));

Issue #6: Missing Rate Limiting

问题6:缺少速率限制

Error: API abuse, DDoS vulnerability Source: Production security best practice Why It Happens: No rate limiting on MCP endpoints Prevention:
typescript
app.post('/mcp', async (c) => {
  const ip = c.req.header('CF-Connecting-IP');
  const rateLimitKey = `ratelimit:${ip}`;

  const count = await c.env.CACHE.get(rateLimitKey);
  if (count && parseInt(count) > 100) {
    return c.json({ error: 'Rate limit exceeded' }, 429);
  }

  await c.env.CACHE.put(
    rateLimitKey,
    String((parseInt(count || '0') + 1)),
    { expirationTtl: 60 }
  );

  // Continue...
});
错误影响:API滥用、DDoS漏洞 来源:生产环境安全最佳实践 问题原因:MCP端点未配置速率限制 预防方案
typescript
app.post('/mcp', async (c) => {
  const ip = c.req.header('CF-Connecting-IP');
  const rateLimitKey = `ratelimit:${ip}`;

  const count = await c.env.CACHE.get(rateLimitKey);
  if (count && parseInt(count) > 100) {
    return c.json({ error: 'Rate limit exceeded' }, 429);
  }

  await c.env.CACHE.put(
    rateLimitKey,
    String((parseInt(count || '0') + 1)),
    { expirationTtl: 60 }
  );

  // 继续处理请求...
});

Issue #7: TypeScript Compilation Memory Issues

问题7:TypeScript编译内存问题

Error:
Out of memory
during
tsc
build Source: GitHub modelcontextprotocol/typescript-sdk#985 Why It Happens: Large dependency tree in MCP SDK Prevention:
bash
undefined
错误信息
Out of memory
tsc
构建期间 来源:GitHub modelcontextprotocol/typescript-sdk#985 问题原因:MCP SDK的依赖树过大 预防方案
bash
undefined

Add to package.json scripts

添加到package.json的scripts中

"build": "NODE_OPTIONS='--max-old-space-size=4096' tsc && vite build"
undefined
"build": "NODE_OPTIONS='--max-old-space-size=4096' tsc && vite build"
undefined

Issue #8: UriTemplate ReDoS Vulnerability

问题8:UriTemplate ReDoS漏洞

Error: Server hangs on malicious URI patterns Source: GitHub modelcontextprotocol/typescript-sdk#965 (Security) Why It Happens: Regex denial-of-service in URI template parsing Prevention: Update to SDK v1.20.2 or later (includes fix)
错误影响:服务器在恶意URI模式下挂起 来源:GitHub modelcontextprotocol/typescript-sdk#965(安全问题) 问题原因:URI模板解析中的正则表达式拒绝服务漏洞 预防方案:升级到SDK v1.20.2或更高版本(已包含修复)

Issue #9: Authentication Bypass

问题9:认证绕过

Error: Unauthenticated access to MCP tools Source: Production security best practice Why It Happens: Missing or improperly implemented authentication Prevention: Always implement authentication for production servers (see Authentication Patterns section)
错误影响:未授权访问MCP工具 来源:生产环境安全最佳实践 问题原因:缺少或未正确实现认证逻辑 预防方案:生产服务器务必实现认证(参见认证模式章节)

Issue #10: Environment Variable Leakage

问题10:环境变量泄漏

Error: Secrets exposed in error messages or logs Source: Cloudflare Workers security best practice Why It Happens: Environment variables logged or returned in responses Prevention:
typescript
// ❌ WRONG - Exposes secrets
console.log('Env:', JSON.stringify(env));

// ✅ CORRECT - Never log env objects
try {
  // ... use env.SECRET_KEY
} catch (error) {
  // Don't include env in error context
  console.error('Operation failed:', error.message);
}

错误影响:敏感信息在错误信息或日志中暴露 来源:Cloudflare Workers安全最佳实践 问题原因:环境变量被记录或在响应中返回 预防方案
typescript
// ❌ 错误写法 - 暴露敏感信息
console.log('Env:', JSON.stringify(env));

// ✅ 正确写法 - 永远不要记录env对象
try {
  // ... 使用env.SECRET_KEY
} catch (error) {
  // 错误上下文不要包含env
  console.error('Operation failed:', error.message);
}

Deployment Workflow

部署流程

Local Development

本地开发

bash
undefined
bash
undefined

Install dependencies

安装依赖

npm install
npm install

Run locally with Wrangler

使用Wrangler本地运行

npm run dev
npm run dev

or

wrangler dev
wrangler dev

Server available at: http://localhost:8787/mcp

服务器地址:http://localhost:8787/mcp

undefined
undefined

Production Deployment

生产环境部署

bash
undefined
bash
undefined

Build

构建项目

npm run build
npm run build

Deploy to Cloudflare Workers

部署到Cloudflare Workers

wrangler deploy
wrangler deploy

Deploy to specific environment

部署到指定环境

wrangler deploy --env production
undefined
wrangler deploy --env production
undefined

CI/CD with GitHub Actions

使用GitHub Actions实现CI/CD

yaml
name: Deploy MCP Server
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm test

      - name: Deploy to Cloudflare Workers
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

yaml
name: Deploy MCP Server
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm test

      - name: Deploy to Cloudflare Workers
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

Package Versions (Verified 2025-10-28)

已验证的包版本(2025-10-28)

json
{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.20.2",
    "@cloudflare/workers-types": "^4.20251011.0",
    "hono": "^4.10.1",
    "zod": "^3.23.8",
    "zod-to-json-schema": "^3.24.1"
  },
  "devDependencies": {
    "@cloudflare/vitest-pool-workers": "^0.5.29",
    "vitest": "^3.0.0",
    "wrangler": "^4.43.0",
    "typescript": "^5.7.0"
  }
}

json
{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.20.2",
    "@cloudflare/workers-types": "^4.20251011.0",
    "hono": "^4.10.1",
    "zod": "^3.23.8",
    "zod-to-json-schema": "^3.24.1"
  },
  "devDependencies": {
    "@cloudflare/vitest-pool-workers": "^0.5.29",
    "vitest": "^3.0.0",
    "wrangler": "^4.43.0",
    "typescript": "^5.7.0"
  }
}

When to Use Cloudflare Agents SDK Instead

何时改用Cloudflare Agents SDK

Use Cloudflare Agents MCP when you need:
  • Stateful agents with persistent storage (SQLite up to 1GB)
  • WebSocket support for real-time bidirectional communication
  • Long-running sessions with conversation history
  • Scheduled agent tasks with Durable Objects alarms
  • Global distribution with automatic state replication
Use this skill (standalone TypeScript MCP) when you need:
  • Stateless tools and API integrations
  • Edge deployment with minimal cold start latency
  • Simple authentication (API keys, OAuth)
  • Pay-per-request pricing (no Durable Objects overhead)
  • Maximum portability (works on any platform, not just Cloudflare)
See
references/cloudflare-agents-vs-standalone.md
for detailed comparison.

当你需要以下功能时,请使用Cloudflare Agents MCP
  • 带持久化存储(SQLite最大1GB)的有状态Agent
  • 支持实时双向通信的WebSocket
  • 带对话历史的长期运行会话
  • 带Durable Objects告警的定时Agent任务
  • 自动状态复制的全局分布式部署
当你需要以下功能时,请使用本技能(独立TypeScript MCP)
  • 无状态工具与API集成
  • 冷启动延迟极低的边缘部署
  • 简单的认证方式(API密钥、OAuth)
  • 按请求付费的定价模式(无Durable Objects开销)
  • 最高的可移植性(可在任何平台运行,不仅限于Cloudflare)
详细对比请参见
references/cloudflare-agents-vs-standalone.md

Using Bundled Resources

使用捆绑资源

Templates (templates/)

模板(templates/)

All templates are production-ready and tested on Cloudflare Workers:
  • templates/basic-mcp-server.ts
    - Minimal working server (echo tool example)
  • templates/tool-server.ts
    - Multiple tools implementation (API integrations, calculations)
  • templates/resource-server.ts
    - Resource-only server (static and dynamic resources)
  • templates/full-server.ts
    - Complete server (tools + resources + prompts)
  • templates/authenticated-server.ts
    - Production server with API key authentication
  • templates/wrangler.jsonc
    - Cloudflare Workers configuration with all bindings
When Claude should use these: When creating a new MCP server, copy the appropriate template based on the use case (tools-only, resources-only, authenticated, or full-featured).
所有模板均为生产就绪版本,并已在Cloudflare Workers上测试:
  • templates/basic-mcp-server.ts
    - 最简可用服务器(echo工具示例)
  • templates/tool-server.ts
    - 多工具实现(API集成、计算功能)
  • templates/resource-server.ts
    - 仅包含资源的服务器(静态与动态资源)
  • templates/full-server.ts
    - 完整服务器(工具+资源+提示词)
  • templates/authenticated-server.ts
    - 带API密钥认证的生产服务器
  • templates/wrangler.jsonc
    - 包含所有绑定的Cloudflare Workers配置
Claude使用时机:创建新MCP服务器时,根据使用场景(仅工具、仅资源、认证版或全功能版)复制对应的模板。

Reference Guides (references/)

参考指南(references/)

Comprehensive documentation for advanced topics:
  • references/tool-patterns.md
    - Common tool implementation patterns (API wrappers, database queries, calculations, file operations)
  • references/authentication-guide.md
    - All authentication methods detailed (API keys, OAuth 2.0, Zero Trust, JWT)
  • references/testing-guide.md
    - Unit testing, integration testing with MCP Inspector, E2E testing with Claude Agent SDK
  • references/deployment-guide.md
    - Wrangler workflows, environment management, CI/CD with GitHub Actions
  • references/cloudflare-integration.md
    - Using D1, KV, R2, Vectorize, Workers AI, Queues, Durable Objects
  • references/common-errors.md
    - All 10+ errors with detailed solutions, root causes, and prevention strategies
  • references/cloudflare-agents-vs-standalone.md
    - Decision matrix for choosing between standalone MCP and Cloudflare Agents SDK
When Claude should load these: When developer needs advanced implementation details, debugging help, or architectural guidance.
高级主题的全面文档:
  • references/tool-patterns.md
    - 常见工具实现模式(API包装、数据库查询、计算、文件操作)
  • references/authentication-guide.md
    - 所有认证方法详解(API密钥、OAuth 2.0、Zero Trust、JWT)
  • references/testing-guide.md
    - 单元测试、使用MCP Inspector的集成测试、使用Claude Agent SDK的端到端测试
  • references/deployment-guide.md
    - Wrangler工作流、环境管理、使用GitHub Actions的CI/CD
  • references/cloudflare-integration.md
    - 使用D1、KV、R2、Vectorize、Workers AI、Queues、Durable Objects
  • references/common-errors.md
    - 所有10余种错误的详细解决方案、根本原因与预防策略
  • references/cloudflare-agents-vs-standalone.md
    - 选择独立MCP还是Cloudflare Agents SDK的决策矩阵
Claude使用时机:当开发者需要高级实现细节、调试帮助或架构指导时。

Scripts (scripts/)

脚本(scripts/)

Automation scripts for initializing and testing MCP servers:
  • scripts/init-mcp-server.sh
    - Initializes new MCP server project with dependencies, wrangler config, and template selection
  • scripts/test-mcp-connection.sh
    - Tests MCP server connectivity and validates tool/resource endpoints
When Claude should use these: When setting up a new project or debugging connectivity issues.

用于初始化与测试MCP服务器的自动化脚本:
  • scripts/init-mcp-server.sh
    - 初始化新MCP服务器项目,包含依赖、wrangler配置与模板选择
  • scripts/test-mcp-connection.sh
    - 测试MCP服务器连通性并验证工具/资源端点
Claude使用时机:设置新项目或调试连通性问题时。

Official Documentation

官方文档

Example Servers:

示例服务器

Critical Rules

关键规则

Always Do

务必遵守

✅ Close transport on response end to prevent memory leaks ✅ Use direct export syntax (
export default app
) not object wrapper ✅ Implement authentication for production servers ✅ Add rate limiting to prevent API abuse ✅ Use Zod schemas for type-safe tool definitions ✅ Test with MCP Inspector before deploying to production ✅ Update to SDK v1.20.2+ for security fixes ✅ Document all tools with clear descriptions ✅ Handle errors gracefully and return meaningful messages ✅ Use environment variables for secrets (never hardcode)
✅ 响应结束时关闭传输连接以防止内存泄漏 ✅ 使用直接导出语法(
export default app
)而非对象包装 ✅ 生产服务器务必实现认证 ✅ 配置速率限制以防止API滥用 ✅ 使用Zod Schema实现类型安全的工具定义 ✅ 部署到生产环境前用MCP Inspector测试 ✅ 升级到SDK v1.20.2+以获取安全修复 ✅ 为所有工具添加清晰的描述 ✅ 优雅处理错误并返回有意义的信息 ✅ 使用环境变量存储敏感信息(绝对不要硬编码)

Never Do

绝对禁止

❌ Export with object wrapper (
export default { fetch: app.fetch }
) ❌ Forget to close StreamableHTTPServerTransport ❌ Deploy without authentication in production ❌ Log environment variables or secrets ❌ Use CommonJS format (must use ES modules) ❌ Skip CORS configuration for browser clients ❌ Hardcode API keys or credentials ❌ Return raw error objects (may leak sensitive data) ❌ Deploy without testing tools/resources locally ❌ Use outdated SDK versions with known vulnerabilities

❌ 使用对象包装导出(
export default { fetch: app.fetch }
) ❌ 忘记关闭StreamableHTTPServerTransport ❌ 生产环境部署未实现认证 ❌ 记录环境变量或敏感信息 ❌ 使用CommonJS格式(必须使用ES模块) ❌ 浏览器客户端场景跳过CORS配置 ❌ 硬编码API密钥或凭证 ❌ 返回原始错误对象(可能泄漏敏感数据) ❌ 未在本地测试工具/资源就部署 ❌ 使用存在已知漏洞的旧版SDK

Complete Setup Checklist

完整设置检查清单

Use this checklist to verify your MCP server setup:
  • SDK version is 1.20.2 or later
  • Export syntax is correct (direct export, not object wrapper)
  • Transport is closed on response end
  • Authentication is implemented (if production)
  • Rate limiting is configured (if public-facing)
  • CORS headers are set (if browser clients)
  • All tools have clear descriptions and Zod schemas
  • Environment variables are used for secrets
  • wrangler.jsonc includes all necessary bindings
  • Local testing with
    wrangler dev
    succeeds
  • MCP Inspector can connect and list tools
  • Production deployment succeeds
  • All tools/resources return expected responses

使用此清单验证你的MCP服务器设置:
  • SDK版本为1.20.2或更高
  • 导出语法正确(直接导出,非对象包装)
  • 响应结束时关闭传输连接
  • 已实现认证(若为生产环境)
  • 已配置速率限制(若为公开访问)
  • 已设置CORS头(若为浏览器客户端)
  • 所有工具均有清晰描述与Zod Schema
  • 使用环境变量存储敏感信息
  • wrangler.jsonc包含所有必要的绑定
  • wrangler dev
    本地测试成功
  • MCP Inspector可连接并列出工具
  • 生产环境部署成功
  • 所有工具/资源返回预期响应

Production Example

生产环境示例

This skill is based on patterns from:

Questions? Issues?
  1. Check
    references/common-errors.md
    for troubleshooting
  2. Verify all steps in the Quick Start section
  3. Test with MCP Inspector:
    npx @modelcontextprotocol/inspector
  4. Check official docs: https://spec.modelcontextprotocol.io/
  5. Ensure SDK version is 1.20.2 or later

Last Updated: 2025-10-28 SDK Version: @modelcontextprotocol/sdk@1.20.2 Maintainer: Claude Skills Repository
本技能基于以下项目的模式构建:

有疑问?遇到问题?
  1. 查看
    references/common-errors.md
    进行故障排除
  2. 验证快速开始章节的所有步骤
  3. 使用MCP Inspector测试:
    npx @modelcontextprotocol/inspector
  4. 查看官方文档:https://spec.modelcontextprotocol.io/
  5. 确保SDK版本为1.20.2或更高

最后更新:2025-10-28 SDK版本:@modelcontextprotocol/sdk@1.20.2 维护者:Claude Skills Repository