ECS Express Mode statt App Runner / klassisches Fargate fuer eigene Hosted-MCPs

Kontext

Mit der Migration nach AWS (aws-multi-account-strategie) und dem Start der MCP-Hosting-Pipeline (_index) musste eine Compute-Plattform fuer den ersten hosted MCP (gsuite-hosted) gewaehlt werden. Anforderungsprofil:

  • Eu-central-1 (DSGVO)
  • HTTP/HTTPS-Workload, persistent (nicht event-driven)
  • Niedrige Last in Phase 1 (nur Marvin selbst), Skalierung in Phase 2/3
  • TLS-Cert auf eigener Domain via Cloudflare-Proxy
  • Multi-Service-faehig (perspektivisch papierkram-hosted, ticketpay-hosted, m365-hosted parallel)
  • Wenig Boilerplate-Code, weil das Pattern fuer kuenftige MCPs wiederholbar bleiben muss

Bis April 2026 waere AWS App Runner der naheliegende Default gewesen — single-CLI-Deploy auf Fargate-Underbau, AWS-managed ALB+TLS. Aber: App Runner ist seit April 2026 closed for new customers (AWS-Announcement). Bestehende Kunden duerfen weiter nutzen, neu anlegen geht nicht. Damit faellt der primaere Kandidat raus.

Optionen

Option A — Klassisches ECS Fargate + ALB + ACM (selbst gebaut)

Standard-Pattern: eigener FargateService + ApplicationLoadBalancer + Certificate mit DNS-Validation + Listener mit HTTPS-Redirect + Target Group + Security Groups + ggf. eigene VPC.

Pro:

  • Maximale Kontrolle ueber jede Schicht
  • Reife CDK-L2-Konstrukte (aws-cdk-lib/aws-ecs/FargateService, aws-cdk-lib/aws-elasticloadbalancingv2)
  • Etabliert seit Jahren, viel Doku, viele Beispiele

Contra:

  • ~14 CFN-Resourcen pro Service zu pflegen (Cluster, Task-Def, Service, ALB, TG, Listener-HTTPS, Listener-HTTP-Redirect, ACM-Cert, SG-ALB, SG-Service, Log-Group, Cluster-Container-Insights, Output-DNSName, Output-ServiceArn)
  • ACM-Cert braucht DNS-Validation → Henne-Ei-Problem mit Cloudflare-DNS-Setup waehrend des Deploys
  • Pro neuem MCP wird der ALB neu angelegt — keine Sharing-Optimierung „out of the box”

Option B — ECS Express Mode (AWS::ECS::ExpressGatewayService)

Neue CFN-Resource (GA April 2026, Doku) die AWS-managed ALB+TLS+AutoScaling+LogGroup+SGs in einer Resource zusammenfasst. Service-URL ist <service>.ecs.<region>.on.aws mit AWS-vergebenem Cert.

Pro:

  • 8 statt 14 CFN-Resourcen (ECR + Secret + 3 IAM-Rollen + Service)
  • ALB wird ueber bis zu 25 Express-Services in derselben Region+VPC geteilt — der zweite hosted MCP zahlt keinen extra ALB-Posten (~25 USD/Monat eingespart pro zusaetzlichem Service)
  • Auto-Provisioning ALB + TLS-Cert + Auto-Scaling + Log-Group + SGs — keine manuellen Glue-Resourcen
  • TLS-Cert AWS-managed, kein DNS-Validation-Henne-Ei
  • Nutzt darunter weiterhin Fargate — gleicher Underbau wie Option A, gleiche Reife
  • 5xx-Rollback-Alarme + Canary-Deploys eingebaut

Contra:

  • Nur CDK L1 (CfnExpressGatewayService) — Properties als Strings statt Enums (cpu: '1' statt Cpu.ONE_VCPU). L2 wird nachgerueckt aber Stand 2026-05 nicht da, tracking issue
  • Custom-Domain via Cloudflare-Proxy noetig (Endpoint ist AWS-DNS, eigene Domain ist Cloudflare-CNAME) — gleicher Setup wie bei Option A, aber expliziter Schritt
  • Neuere Tech, vereinzelt Doku-Luecken (z.B. genaue IAM-Role-Trust-Topology nur in Tutorials, nicht in Standard-Reference)
  • AWS-vergebene Default-DNS-Endpunkte sind nicht mit Verbots-Filtern wie „nur eigene Domain darf draufzeigen” kombinierbar

Option C — Lambda + API Gateway

Pro:

  • Scale-to-zero (kein Idle-Cost)
  • Kein VPC / kein Container-Build / kein ALB
  • Sehr billig fuer geringe Last

Contra:

  • Cold-Starts (5-10 Sekunden bei Container-Lambda mit Python+grosser Package-Liste) — unbrauchbar fuer interaktive MCP-Tool-Calls in claude.ai
  • 15-Minuten-Maximum pro Aufruf — okay fuer MCP-Tool-Calls, aber stdio-Subprocess-Lifecycle macht Kontainer-Reuse schwierig
  • Keine persistent stdio-Subprocesses (gsuite-Sub-MCP startet stdio neu pro Call)
  • Pricing-Modell nicht praedikatabel bei wachsender Nutzung — bei 50 Customers eher teurer als ECS Fargate

Option D — Status-quo: Railway weiter nutzen

Pro:

  • Bestehender mcp-vf-hosted laeuft dort produktiv (mcp-vf-hosted)
  • DX exzellent (git push deployed)

Contra:

  • Komplette Begruendungs-Linie aus aws-multi-account-strategie greift hier — fuer Compliance-Pfad nicht weiterfuehrbar
  • Multi-Tenancy nicht so sauber wie AWS-Account-Trennung
  • Kein OAuth-Server-Hosting (Scalekit muss extern bleiben → bei AWS koennte das spaeter inhouse als Cognito o.ae. wandern)

Entscheidung

ECS Express Mode (Option B) in eu-central-1, deployed via CDK L1 in av-production (Account 425924867359).

Begruendung:

  1. Boilerplate-Reduktion ist der wichtigste Faktor — das Pattern muss wiederholbar bleiben fuer kuenftige MCPs. 8 vs 14 Resourcen ist nicht nur weniger Code, sondern weniger Failure-Surface beim Deploy und weniger zu verstehen fuer den naechsten Agent-Lauf.

  2. ALB-Sharing macht den Stack ab dem zweiten MCP signifikant guenstiger. Bei der „MCP-as-a-Service”-Vision (mcp-as-a-service-vision) ist das ein dickes Argument — wir wollen 5-8 hosted MCPs parallel betreiben.

  3. AWS-managed Cert loest das DNS-Validation-Problem mit Cloudflare elegant — Cloudflare ist eh als TLS-Edge geplant, der AWS-Origin braucht „nur” einen gueltigen Cert auf seiner eigenen DNS-Identity. ACM-Validation-CNAMEs in Cloudflare zu setzen waere unnoetiger Schritt.

  4. L1-Only-Constraint ist ein vertretbarer Tradeoff — der Stack wird einmal geschrieben und kopiert, nicht haendisch jeden Tag editiert. L2 kommt bei AWS gewohnt nach 6-12 Monaten nach.

  5. App Runner haette das gleiche geliefert ohne L1-Constraint, ist aber nicht mehr verfuegbar — daher kein Vergleichspunkt fuer Neubauten.

  6. Lambda+APIGW wurde wegen Cold-Start-Latenz verworfen — interaktive MCP-Tool-Calls vertragen keine 5-10s Latenz beim ersten Aufruf nach Idle.

  7. Railway wurde durch aws-multi-account-strategie schon allgemein abgeloest, hier nur Bestaetigung der Konsistenz.

Konsequenzen

Sofort:

  • CDK-Stack fuer gsuite-hosted nutzt ecs.CfnExpressGatewayService (L1) — siehe phase-1 und mcp-hosting-aws-ecs-express
  • Pattern-File haelt fest: 3-Rollen-IAM (Exec / Infra / Task), Trust-Principal-Verwechslung als haeufigster Fehler dokumentiert
  • Cost-Modell: ~50-65 USD/Monat fuer ersten Service (Default-Sizing 1 vCPU/2 GB), ab dem zweiten Service ~25 USD/Monat weniger durch ALB-Sharing
  • mcp-vf-hosted bleibt vorerst auf Railway — Migration auf AWS-Variante des Patterns ist Phase 4 / wenn ein neuer Kunde reinkommt, nicht jetzt

Mittelfristig:

  • Wenn AWS L2 fuer ECS Express Mode shippt, Stack auf L2 migrieren (Diff-only, Funktionalitaet bleibt)
  • Wenn Last hochkommt: Container-Sizing von Default 1/2 auf 0.25/0.5 runter testen — ECS Express akzeptiert beide laut Doku-Standard-Sizes
  • Phase 2 fuegt DynamoDB + KMS-Customer-Key zur Multi-Tenant-Isolation hinzu — orthogonal zur Compute-Wahl, ECS Express bleibt
  • Phase 3 mit Composio-Hybrid: Composio-Endpoint als Sub-MCP einklinken, sonst gleiche Architektur

Risiken:

  • ECS Express ist neu, vereinzelt Doku-Luecken — bei Bug-Reports gegen AWS-Support schreiben statt monatelang selber suchen. Workaround-Pfad: bei wirklichem Blocker auf klassisches Fargate (Option A) ausweichen, gleicher Underbau, mehr Boilerplate aber bewaehrt
  • L1-Properties sind String-typed — Tippfehler werden erst beim Deploy gefangen, nicht beim tsc. Mitigation: gut getestetes Template-Repo, Diffs ueber bestehende Stacks
  • AWS-Endpoint-DNS (<svc>.ecs.<region>.on.aws) ist oeffentlich — wenn der Cloudflare-Proxy umgangen wird, geht ein Request am WAF vorbei. Mitigation: Origin-Auth via Cloudflare-Header oder spaeter via WAF-on-AWS-Side, in Phase 1 akzeptiert weil Scalekit-JWT die echte Auth-Boundary ist