Skip to main content
Glama

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 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.

Добавляйте свои инструменты

Отредактируйте массив 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

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