MCP Remote vs. Lokal

Wann muss ein MCP-Server „remote” liegen, was bedeutet das technisch, und was muessen wir konkret umbauen wenn wir einen heute-lokalen MCP zu einem Remote-Service machen? Festgehalten am Beispiel ticketpay.

Zwei Transport-Modi

1. stdio. Der Client (Claude Desktop, Claude Code, Wrapper) spawnt den MCP als Subprocess. JSON-RPC ueber STDIN/STDOUT. Server lebt nur solange der Client lebt. Auth = „wer den Prozess starten kann, darf alles”.

2. Streamable HTTP (frueher SSE). Server ist HTTP-Daemon mit /mcp-Endpunkt. Session via Mcp-Session-Id-Header. Server-Push via SSE-Stream. Mehrere Clients gleichzeitig moeglich.

„Remote MCP” = Streamable HTTP + oeffentliche URL + TLS + OAuth davor.

Wann ist Remote zwingend

  • Claude.ai Pro im Browser kann ausschliesslich Remote MCPs — Browser kann keine Subprocesses spawnen. Custom Connectors sind per Definition remote.
  • Cloudflare Workers als Hosting → kein stdio moeglich (keine subprocess.Popen(), kein fork()). Alle Subs muessen HTTP sein.
  • Mehrere Clients teilen einen MCP — z.B. drei Wrapper-Instanzen die alle TicketPay anbinden.

Claude Desktop und Claude Code koennen beides — lokal stdio reicht fuer Single-User-Setups.

TicketPay heute — zwei Realitaeten gleichzeitig

Use-CaseSetup
(A) Marvin in Claude Codestdio/HTTP auf 127.0.0.1:8766, API-Key in ~/source/mcps/mcp-ticketpay/.env.local, kein OAuth, Single-Tenant
(B) Andre in claude.ai ProEmbedded als stdio-Sub im mcp-vf-hosted-Wrapper. Wrapper macht den Remote-Teil (OAuth via Scalekit, TLS via Cloudflare, ECS-Container). TicketPay-MCP selbst ist weiterhin dumm und stdio.

Die Remote-Schale liegt einen Layer hoeher. Sub-MCPs bleiben simpel.

Wann muessten wir TicketPay selbst remote machen

  1. Migration zu Cloudflare Workers (Workers koennen stdio-Subs nicht spawnen)
  2. TicketPay als eigenstaendiger Connector in claude.ai (z.B. Kunde der nur TicketPay braucht, nicht das VF-Bundle)
  3. Mehrere Wrapper-Instanzen sollen einen zentralen TicketPay-MCP teilen statt jeder seinen eigenen Subprocess fork

Umbau-Liste — TicketPay als standalone Remote MCP

#WasHeuteRemote-Variante
1Transportstdio + lokaler HTTPnur Streamable HTTP, public bind
2URL/TLS127.0.0.1:8766ticketpay.mcp.agenticventures.de mit Cert
3Auth-LayerAPI-Key in .envOAuth davor (Scalekit oder CF Access), JWT-Validation pro Request
4OAuth-Discovery/.well-known/oauth-protected-resource, Resource-Identifier = exakte MCP-URL
5API-Key-QuelleEine ENV-VariablePer-User-Mapping: aus authentifiziertem Token → welcher TicketPay-Key. Storage: DB/Secrets-Manager/Durable Object. Server kennt beim Start keinen Key
6Hostingdein Mac via uv toolECS Express Container ODER Cloudflare Worker (dann komplette Reimpl., weil Python→TS)
7Health-Endpoint/health auth-frei fuer Loadbalancer (VF-Wrapper-Pattern kopieren)
8Loggingprint to stderrstrukturiertes JSON-Logging mit PII-Scrubbing (GuardMiddleware-Pattern aus VF-Wrapper)
9Rate-LimitPer-Subject Token-Bucket (Abuse-Schutz)
10Secrets.env.localAWS Secrets Manager oder CF Secrets, niemals im Image
11Statelessstateful ok bei einer Instanzbei Multi-Instance Session-Affinity oder externer Session-Store

Code-Aufwand realistisch: 1-2 Tage. Klonen von mcp-vf-hosted als Template, create_proxy()-Liste reduzieren, Punkt 5 (Per-User-Key) ist die einzige echt neue Sache.

Default-Empfehlung: nicht machen

Solange wir das Mono-Wrapper-Pattern fahren (mcp-vf-hosted), muessen Sub-MCPs nicht remote sein. Der Wrapper loest Remote/OAuth/TLS einmal zentral, Sub-MCPs bleiben simple stdio-Tools die wir auch lokal in Claude Code nutzen koennen. Doppelter Use-Case ohne Doppelarbeit.

Trigger fuer Umbau: Wenn wir cloudflare-capability-map Option A ernsthaft verfolgen (MCP-Hosting auf Workers statt ECS), brauchen wir HTTP-native Subs. Dann waere der erste Schritt: TicketPay HTTP-Mode produktionstauglich machen (Punkte 7-10 aus der Tabelle), Auth weiterhin Sache des Wrappers lassen. Sub im Wrapper umstellen von StdioTransport auf StreamableHttpTransport — und sehen ob die Architektur traegt, bevor wir die Per-User-Auth-Story dranhaengen.