Skip to main content
Glama

mcp-worker-starter

Ein minimaler Model Context Protocol-Server für Cloudflare Workers. Keine Abhängigkeiten, eine Datei, reines POST.

Ich betreibe einen MCP-Server in Produktion, der Claude über authentifizierte Tools Live-Geschäftsdaten zugänglich macht. Das ist dieser Server, mit herausgenommener Geschäftslogik und zurückgelassenem Narbengewebe.

Der Happy Path eines MCP-Servers ist etwa vierzig Zeilen lang. Was sich zu veröffentlichen lohnt, sind die drei unten aufgeführten Fallen, denn jede von ihnen ist lautlos, und eine hat zwei meiner Produkte lahmgelegt.


Der 405, der dich einen Ausfall kostet

MCP-Clients öffnen eine GET-Anfrage mit Accept: text/event-stream, um auf vom Server gesendete Nachrichten zu lauschen. Wenn dein Server kein SSE spricht, sieht das Protokoll eine Antwort mit 405 vor. Dieser Status ist das Signal für nicht noch einmal öffnen.

Ich habe stattdessen mit 200 und einem freundlichen JSON-Body geantwortet, weil eine 200 hilfreicher wirkte als ein Fehler.

Der Client las diese 200 als einen abgebrochenen Stream und verband sich neu. Sofort. Ohne Backoff und ohne dass irgendwo, wo ich hinsah, ein Fehler auftauchte.

201.936 Anfragen an einem Tag. Das verbrannte das tägliche Anfragekontingent des gesamten Cloudflare-Kontos und legte damit ein zweites, völlig unabhängiges Produkt lahm, das dieses Konto zufällig mitnutzte. Der MCP-Server selbst protokollierte keinen einzigen Fehler, denn von seiner Seite aus war nichts falsch. Er beantwortete jede Anfrage korrekt, 201.936 Mal.

Eine 200 dort, wo das Protokoll eine 405 erwartet, ist keine freundlichere Antwort. Sie ist eine Endlosschleife mit guten Manieren.

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)

Benachrichtigungen haben keine id und dürfen keinen Body bekommen

Eine JSON-RPC-Benachrichtigung ist Fire-and-Forget. Sie kommt ohne id an, und der Aufrufer wartet nicht auf eine Antwort. Wenn du mit {"jsonrpc":"2.0","result":{}} antwortest, behandeln strikte Clients den Austausch als fehlerhaft, weil du auf etwas geantwortet hast, das niemand gefragt hat.

202 mit leerem Body ist die korrekte Antwort: „erhalten, nichts zu sagen“.

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

Gib die protocolVersion des Clients zurück

Bei initialize gib die protocolVersion zurück, die der Client angeboten hat, anstatt deine eigene fest zu verdrahten. Das Festverdrahten ergibt einen Handshake, der heute funktioniert und in der Woche, in der der Client aktualisiert wird, leise nicht mehr funktioniert. Verwende einen Standardwert nur dann als Fallback, wenn der Client keinen nennt.


Verwendung

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

Bereitstellen:

npx wrangler deploy

Füge dann die bereitgestellte URL als MCP-Server in deinem Client hinzu. Er spricht POST.

Eigene Tools hinzufügen

Bearbeite das TOOLS-Array in src/index.ts. Zwei Regeln, die wichtiger sind, als sie aussehen:

  • description ist der Prompt. Das Modell wählt Tools aus, indem es ihn liest. Schreib ihn für jemanden, der deinen Code nicht sehen kann und das Schema kein zweites Mal lesen wird.

  • Gib Daten zurück, keine Prosa. Das Modell kann dein JSON besser beschreiben, als du erraten kannst, was es dazu sagen will.

Authentifizierung und Rate-Limiting

Beides ist standardmäßig deaktiviert, sodass der Starter ohne Einrichtung läuft.

Token-Authentifizierung wird aktiviert, wenn du MCP_TOKEN setzt. Anfragen müssen dann Authorization: Bearer <token> vorweisen.

npx wrangler secret put MCP_TOKEN

Stündliches Rate-Limiting wird aktiviert, wenn du einen KV-Namespace als RATE_LIMIT bindest. Das Standardlimit ist 300 Anfragen pro Stunde. In Produktion begrenze ich pro Mandant statt global, basierend auf dem, was den Aufrufer identifiziert.

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

Ein Rate-Limit ist hier keine Paranoia. Falle eins ist genau die Art von Fehler, die ein Limit in Minuten statt in einem Tag abgefangen hätte.

Was das nicht ist

Kein SDK, kein Framework, und es versucht auch nicht, eines zu sein. Wenn du den vollen Funktionsumfang willst, verwende das offizielle TypeScript SDK oder das Agents SDK von Cloudflare.

Das ist für den Fall gedacht, dass du den gesamten Server in einem Durchgang lesen und genau wissen willst, was er tut.

Tests

npm test

Deckt den Handshake, den Tool-Roundtrip und jede der drei Fallen ab, denn eine Regression bei einer von ihnen ist unsichtbar, bis sie teuer wird.

Lizenz

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