Skip to main content
Glama

mcp-worker-starter

一个用于 Cloudflare Workers 的最小 Model Context Protocol 服务器。零依赖,一个文件,纯 POST。

我在生产环境中运行着一个 MCP 服务器,通过经过身份验证的工具向 Claude 暴露实时业务数据。这就是那台服务器:业务逻辑已移除,留下的只有伤疤。

一个 MCP 服务器的理想路径大约四十行。真正值得发布的是下面三个陷阱,因为每一个都是无声的,其中一个曾经让我的两个产品宕机。


让你付出宕机代价的 405

MCP 客户端会发起一个带有 Accept: text/event-streamGET 请求,用于监听服务器推送的消息。如果你的服务器不支持 SSE,协议规定应返回 405。这个状态码是 不要再打开这个连接 的信号。

而我却用一个友好的 JSON 响应体返回了 200,因为 200 看起来比错误更有帮助。

客户端把这个 200 理解为已经死亡的流,然后重新连接。立刻。没有退避策略,也没有在我查看的任何地方出现错误。

一天 201,936 个请求。 它烧掉了整个 Cloudflare 账户的每日请求配额,导致另一个恰好共用该账户、完全无关的产品也宕机了。MCP 服务器本身从未记录过任何错误,因为从它这边看一切正常。它正确地回答了每一个请求,一共 201,936 次。

在协议期望 405 的地方返回 200,并不是更友好的回答。这是一个彬彬有礼的无限循环。

if ((request.headers.get("accept") ?? "").includes("text/event-stream")) {
  return new Response(JSON.stringify({ error: "This server does not expose an SSE stream. Use POST." }), {
    status: 405,
    headers: { "content-type": "application/json; charset=utf-8", allow: "POST" },
  });
}

Related MCP server: Remote MCP Server (Authless)

通知没有 id,也不应有响应体

JSON-RPC 通知是即发即弃的。它到达时没有 id,调用方也不会等待应答。如果你回复 {"jsonrpc":"2.0","result":{}},严格的客户端会把这次交互视为格式错误,因为你回答了一个没有人问的问题。

202 加上空响应体才是正确的“已收到,无需多说”。

if (id === undefined || id === null) return new Response(null, { status: 202 });

回显客户端的 protocolVersion

initialize 时,回显客户端提供的 protocolVersion,而不是硬编码你自己的版本。硬编码会让握手在今天正常运作,而在客户端更新的那一周悄然失效。只有当客户端没有指定任何版本时,才回退到默认值。


使用方法

npm install
npx wrangler dev
curl -s http://localhost:8787 \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq

部署:

npx wrangler deploy

然后把部署后的 URL 作为 MCP 服务器添加到你的客户端中。它通过 POST 通信。

添加你自己的工具

编辑 src/index.ts 中的 TOOLS 数组。有两条规则比看上去更重要:

  • description 就是提示词。 模型通过阅读它来选择工具。请为那些看不到你的代码、也不会把 schema 读第二遍的读者撰写它。

  • 返回数据,而不是叙述性文字。 模型比你更擅长描述你的 JSON,而不是由你去猜测它想对这些数据说什么。

认证与速率限制

两者默认都是关闭的,因此这个入门项目无需任何设置即可运行。

Token 认证在你设置 MCP_TOKEN 后开启。此后请求必须携带 Authorization: Bearer <token>

npx wrangler secret put MCP_TOKEN

每小时速率限制在你将一个 KV 命名空间绑定为 RATE_LIMIT 后开启。默认上限是每小时 300 个请求。在生产环境中,我按租户而不是全局设置上限,以任何能识别调用者的信息作为键。

[[kv_namespaces]]
binding = "RATE_LIMIT"
id = "your-kv-namespace-id"

在这里,速率限制不是多此一举。陷阱一正是那种上限可以在几分钟内捕获、而不是等一整天才发现的失败形态。

这不是什么

不是 SDK,不是框架,也没打算成为其中之一。如果你想要开箱即用的完整功能,请使用官方的 TypeScript SDK 或 Cloudflare 的 Agents SDK

这适用于那种你想一口气读完整个服务器、并确切知道它在做什么的情况。

测试

覆盖了握手、工具往返调用,以及上述三个陷阱中的每一个,因为任何一个回归在造成高昂代价之前都是不可见的。

npm test

许可证

MIT

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Allows deploying a Model Context Protocol server on Cloudflare Workers without authentication, enabling AI assistants to access custom tools through the MCP standard.

View all related MCP servers

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.

  • A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/andressalame/mcp-worker-starter'

If you have feedback or need assistance with the MCP directory API, please join our Discord server