mcp-worker-starter
mcp-worker-starter
Минимальный Model Context Protocol сервер для Cloudflare Workers. Ноль зависимостей, один файл, обычный POST.
Я запускаю MCP-сервер в продакшене, который отдаёт Claude живые бизнес-данные через аутентифицированные инструменты. Это тот сервер, из которого убрали бизнес-логику, а шрамы оставили.
Счастливый путь MCP-сервера — это около сорока строк. Публиковать стоит три ловушки ниже, потому что каждая из них молчалива, и одна из них обрушила два моих продукта.
405, который стоит вам простоя
MCP-клиенты открывают GET с Accept: text/event-stream, чтобы слушать сообщения, отправляемые сервером. Если ваш сервер не говорит на SSE, протокол требует ответить 405. Этот статус — сигнал больше не открывать это.
Я вместо этого отвечал 200 с дружелюбным JSON-телом, потому что 200 казался полезнее ошибки.
Клиент воспринял этот 200 как поток, который умер, и переподключился. Сразу. Без backoff и без единой ошибки там, куда я смотрел.
201 936 запросов за один день. Это сожгло дневную квоту запросов всего аккаунта Cloudflare и обрушило второй, совершенно не связанный продукт, которому случилось делить этот аккаунт. Сам MCP-сервер не залогировал ни одной ошибки, потому что с его стороны всё было в порядке. Он отвечал на каждый запрос правильно — 201 936 раз.
200 там, где протокол ожидает 405, — это не более дружелюбный ответ. Это бесконечный цикл с хорошими манерами.
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 devcurl -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.
Добавляйте свои инструменты
Отредактируйте массив TOOLS в src/index.ts. Два правила, которые важнее, чем кажется:
description— это промпт. Модель выбирает инструменты, читая его. Пишите его для читателя, который не видит ваш код и не станет перечитывать схему дважды.Возвращайте данные, а не прозу. Модель лучше умеет описывать ваш JSON, чем вы — угадывать, что она хочет о нём сказать.
Аутентификация и ограничение частоты запросов
Обе функции отключены по умолчанию, поэтому стартовый шаблон работает без настройки.
Аутентификация по токену включается, когда вы задаёте MCP_TOKEN. Запросы должны тогда предъявлять Authorization: Bearer <token>.
npx wrangler secret put MCP_TOKENПочасовое ограничение частоты запросов включается, когда вы привязываете KV-namespace как RATE_LIMIT. Лимит по умолчанию — 300 запросов в час. В продакшене я ограничиваю каждого тенанта по отдельности, а не глобально, ключуя по тому, что идентифицирует вызывающего.
[[kv_namespaces]]
binding = "RATE_LIMIT"
id = "your-kv-namespace-id"Ограничение частоты здесь — не паранойя. Ловушка номер один — это ровно та форма отказа, которую лимит поймал бы за минуты, а не за день.
Чем это не является
Это не SDK, не фреймворк и не пытается им быть. Если вам нужны батарейки в комплекте, используйте официальный TypeScript SDK или Agents SDK от Cloudflare.
Это для случая, когда вы хотите прочитать весь сервер за один присест и точно знать, что он делает.
Тесты
npm testПокрывает рукопожатие, полный цикл вызова инструмента и каждую из трёх ловушек, потому что регрессия в любой из них незаметна, пока не обойдётся дорого.
Лицензия
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Cloudflare Workers MCP server: ai-model-router
Cloudflare Workers MCP server: ai-token-counter
Cloudflare Workers MCP server: ai-rate-limit-tracker
Cloudflare Workers MCP server: ai-guardrails
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceA Cloudflare Workers-based MCP server that enables deployment of custom tools accessible via the Model Context Protocol without authentication requirements.-
- -licenseNot gradedqualityNot gradedmaintenanceAllows deploying a Model Context Protocol server on Cloudflare Workers without authentication, enabling AI assistants to access custom tools through the MCP standard.-
- AlicenseNot gradedqualityCmaintenanceA deployable server implementation of the Model Context Protocol that allows you to run custom tools on Cloudflare Workers without authentication requirements.3,386 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables deployment of a remote Model Context Protocol server on Cloudflare Workers without authentication. Allows custom tool definitions and connection from MCP clients like Claude Desktop or Cloudflare AI Playground.-