MCP-Hosting-Pipeline auf AWS
Vision
Wiederverwendbare Pipeline „Spec → Hosted MCP auf AWS” — am gsuite-Beispiel gebaut, parallel als Pattern extrahiert. Endzustand: Marvin sagt „Bau MCP für Software X”, schrittweise Pipeline läuft mit Decision-Points, 2-3 Tage später ist hosted MCP auf AWS produktiv.
Stack-Entscheidungen (final, NICHT mehr diskutieren)
| Schicht | Wahl | Warum |
|---|---|---|
| Compute | ECS Express Mode in eu-central-1 | App Runner ist seit April 2026 closed for new customers. Express Mode = Single-CLI-Deploy auf Fargate-Underbau |
| Mono-MCP-Framework | FastMCP v2 (Prefect’s fastmcp) | bewährt in mcp-vf-hosted, ScalekitProvider offiziell |
| Edge-Auth | Scalekit (EU-Region, bestehender Account) | bereits produktiv für VF-MCP, Migrations-Aufwand niedrig |
| Token-Storage (Phase 2) | DynamoDB + Customer-Managed-KMS-Key + Client-Side-Encryption (AWS Encryption SDK) | Pattern: ABAC-Tag aws:PrincipalTag/TenantId, ein KMS-Key für alle Tenants. Quelle: AWS Security Blog |
| AWS-Account | av-production (425924867359) | Per _index der vorgesehene Workload-Account |
| Domain | gmail.agenticventures.de | DNS via Strato, Cloudflare davor (TLS, WAF) |
| Container-Registry | ECR im av-production-Account | EU-Region, IAM-integriert |
| IaC | AWS CDK (TypeScript) | bessere DX als Terraform für ECS-Setups, AWS-native |
| Phase 3 OAuth-Strategie | Composio/Pipedream-Hybrid (verified Google-App von dort), NICHT Self-Verification | spart 5-15k$/Jahr Audit + 6 Wochen Verification-Wartezeit |
Was schon existiert (NICHT doppelt bauen)
- mcp-vf-hosted —
~/source/mcps/mcp-vf-hosted/— Template-Basis. Kopieren, Sub-MCP-Liste tauschen - mcp-gsuite —
~/source/mcps/mcp-gsuite/— der Sub-MCP der gehosted wird (Marvin’s Fork mit Bulk/Unsubscribe/YouTube) - mcp-eigenbau — Skill für lokalen Sub-MCP-Bau
- mcp-cloud-bereitstellung — Skill für Mono-MCP-Hosting auf Railway (wird Phase 4 um AWS-Variante erweitert)
- _index — AWS Org + Accounts dokumentiert
- OAuth-Tokens lokal:
~/.config/mcp-gsuite/.oauth2.{hello,marvinkuehlmann}@*.json - Anthropic-Skill
mcp-builder(Plugin-Cache) — Tool-Design-Patterns als Referenz - Compound-Engineering-Skill
agent-native-architecture— Design-Prinzipien (Tools = Primitives, CRUD-Vollständigkeit)
Phasen + Steps mit Status
Phase 1A: gsuite Single-User auf AWS (für Marvin allein, Pattern-Etablierung)
Ziel: gsuite-MCP läuft hosted in av-production, Marvin erreicht ihn von claude.ai Pro / iPhone. Erstanwendung des ECS-Express-Patterns — Lessons-Learned wandern in mcp-hosting-aws-ecs-express.
| Step | Was | Aktive Bauzeit | Status |
|---|---|---|---|
| 1A.1 | Repo mcp-gsuite-hosted aus mcp-vf-hosted-Pattern, FastMCP+ScalekitProvider, Dockerfile (Multi-Stage, Non-Root, Healthcheck) | 60-90 Min | ✅ |
| 1A.2 | CDK-Stack: ECS Express Mode (AWS-managed ALB) + ECR + IAM (Exec/Infra/Task) + Secrets-Manager | 60-90 Min | ✅ |
| 1A.3 | Lokal Container bauen (linux/amd64) + Smoke-Test /health + Boot-Logs verifizieren | 30 Min | ✅ |
| 1A.4 | Deploy in av-production via SSO (Marvin: aws sso login --profile av-prod), Health-URL prüfen | 60 Min + 5-30 Min DNS/Cert-Wartezeit | ☐ |
| 1A.5 | Cloudflare-DNS auf gmail.agenticventures.de (Marvin in Strato + Cloudflare-UI) | 15 Min Marvin + 5-15 Min Wartezeit | ☐ |
| 1A.6 | Scalekit-Resource konfigurieren (Resource Identifier = exakt https://gmail.agenticventures.de/mcp) + claude.ai Custom-Connector einrichten + Smoke-Test mit 3 Prompts | 30 Min Marvin | ☐ |
Wall-Clock: 1-2 Tage (bottleneck: Marvin-Reviews + DNS/TLS-Wartezeiten)
Phase 1B: VF-Migration auf AWS (papierkram + ticketpay, M365 deferred)
Ziel: Bestehender Mono-MCP mcp-vf-hosted (heute auf Railway, mcp-vf-hosted) wandert nach av-production. Cloudflare-Origin schaltet von Railway auf AWS um, Domain mcp-vf.agenticventures.de bleibt, claude.ai-Connector bei André unverändert. Railway-Instanz bleibt 1-2 Wochen parallel als Rollback-Sicherung. M365 ist bewusst draussen bis Compliance-Review (Mail-Zugriff, Drive-Files, Tenant-Isolation, AVV-Klauseln) abgeschlossen ist — Code im Repo auskommentiert, Re-Enable ist 6-Stellen-Patch.
| Step | Was | Aktive Bauzeit | Status |
|---|---|---|---|
| 1B.1 | Repo-Trim: mcp-m365-Dependency raus, _SUB_MCP_COMMANDS/_SUB_MCP_ENV/Settings/Dockerfile/.env.example/README anpassen, .dockerignore neu, Tests grün | 60 Min | ✅ |
| 1B.2 | CDK-Stack infra/ analog gsuite-hosted (ECR + Secrets-Manager + 3 IAM-Rollen + ExpressGatewayService), ENV-Vars für Scalekit + Sub-MCP-Tokens als secrets:-Mapping | 60-90 Min | ✅ deprecated (Pivot zu Fargate-Tunnel, siehe 1B.8) |
| 1B.3 | Container lokal bauen (linux/amd64) + /health-Smoke gegen lokalen Container | 30 Min | ✅ |
| 1B.4 | Production-Tokens aus Railway holen (Marvin via railway variables) → Secrets Manager (Marvin gibt Wert, Claude pusht via aws CLI) → cdk deploy + ECR-Push + ECS-Force-Deploy → Service ACTIVE, /health 200 auf AWS-Endpoint | 60 Min + 5-30 Min Wartezeit | ✅ deprecated (siehe 1B.8) |
| 1B.5 | Cloudflare-DNS-Origin-Switch von Railway auf <service>.ecs.eu-central-1.on.aws. Blockiert auf Domain-Migration (cloudflare-migration-guide) — Strato-Direct-CNAME geht wegen TLS-Cert-Mismatch nicht. Scalekit-Resource bleibt — Identifier https://mcp-vf.agenticventures.de/mcp ist unverändert | 15 Min Marvin + Wartezeit | ❌ aufgegeben (ALB-Custom-Domain-Issue, Pivot zu Tunnel) |
| 1B.6 | Smoke-Test mit Andrés bestehendem claude.ai-Connector (papierkram + ticketpay-Tools rufen, kurz mit André koordinieren), AWS-Logs auf Tool-Calls beobachten | 30 Min Marvin + Andre | ☐ blocked auf 1B.9 |
| 1B.7 | Nach ≥ 24h stabilem AWS-Lauf: Railway-Service stoppen, Backup der Railway-ENVs | 15 Min Marvin | ☐ blocked auf 1B.6 |
| 1B.8 | Fargate-Tunnel-Pivot (mcp-hosting-fargate-tunnel): alten McpVfHosted-Stack (ECS Express) loeschen mit DeletionPolicy-Patch fuer Secrets, neuer CDK-Stack (klassisches Fargate + cloudflared-Sidecar + egress-only SG, kein ALB), beide Secrets per fromSecretCompleteArn importieren (Wildcard-Suffix-Bug umgehen), Python-stdlib statt curl im Health-Check (Image hat kein curl). Stack CREATE_COMPLETE, Service ACTIVE 1/1/0, Tunnel 4 Connections registered, Health intern 200 | 60-90 Min | ✅ 2026-05-11 |
| 1B.9 | DNS-Cutover in Cloudflare: CNAME mcp-vf → ce6dd7c0-d31c-456c-be8a-8705c079982d.cfargotunnel.com, proxied=true, TTL=Auto. Aktueller Record zeigt noch auf alten ECS-Express-Endpoint (mc-1a56ed08...on.aws) und gibt 530 (Origin DNS Error) | 5 Min Marvin (UI) oder Claude (wenn CF_API_TOKEN + CF_ZONE_ID exportiert) | ☐ blocked auf Marvin |
| 1B.10 | End-to-End Smoke: curl https://mcp-vf.agenticventures.de/health ohne Host-Override → 200 mit submcps_active: [papierkram, ticketpay, m365], cf-ray-Header sichtbar | 5 Min | ☐ blocked auf 1B.9 |
Aktueller Stand 2026-05-11 (Architektur-Pivot durchgezogen): ECS-Express-Cutover-Versuch gescheitert wegen Custom-Domain-Issue (AWS-managed ALB akzeptiert nur eigenen Hostname → 404). Plus: ECS Express unterstuetzt nur 1 primary Container, kein Cloudflare-Tunnel-Sidecar moeglich. Pivot auf klassisches ECS Fargate + Cloudflare-Tunnel-Sidecar erfolgreich deployed (1B.8 ✅). Pattern-File: mcp-hosting-fargate-tunnel. Decision: hosted-mcp-architektur-2026. Tunnel ce6dd7c0-d31c-456c-be8a-8705c079982d mit 4 Connections nach Frankfurt registered. M365 ist wieder aktiv im Stack (3 Sub-MCPs proxied — papierkram + ticketpay + m365). Production-Risiko bleibt 0 — Andre nutzt noch nicht aktiv. Naechster Schritt: 1B.9 DNS-Cutover.
Repo-Stand seit 2026-05-10 (lokal, AWS-Deploy gebuendelt mit Cloudflare-Cutover): Drei Workflow-Prompts in prompts.py registriert (/offene_posten, /event_bilanz(event_id), /monatsabschluss(monat)) — André bekommt Slash-Commands die Sub-MCP-Tools choreografieren. /health erweitert auf Diagnostic-JSON (version + submcps_active + uptime). Test-Suite 27/27 grün (5 neue für Prompts, 3 neue fuer Health). Container lokal gebaut + gesmoked. ECR-Push + ECS-Force-Deploy faellt zusammen mit Cloudflare-Cutover an, damit nur ein Deploy-Event statt zwei.
Wall-Clock: 1-2 Tage aktiv + 1-2 Wochen Parallel-Lauf bevor Railway abgeschaltet wird
Compliance-Folge-Schritt (separat, nicht hier): M365 Re-Enable — eigenes Mini-Projekt mit AVV-Klauseln, Tenant-Isolation-Test, Audit-Plan. Kommt nach VF-Migration stabil + Compliance-Review-OK.
Phase 2: Multi-Tenant-Architektur (DynamoDB Operational + S3-Vault Knowledge)
Ziel: Multi-Tenant-Foundation des Produkt-Bundles (produkt-bundle). Pro Kunde: eigener Vault (S3) fuer Knowledge + eigene DynamoDB-Items fuer Operational, beide KMS-encrypted und ABAC-isoliert. Andre (oder beliebiger User) klickt „Connect Gmail” → autorisiert mit seinem Gmail → sieht seine Mails. Strikte User-Isolation. Architektur: markdown-und-db-trennung.
| Step | Was | Aktive Bauzeit | Status |
|---|---|---|---|
| 2.1 | DynamoDB-Table gsuite-user-tokens (PK=subject, KMS-Encryption, ABAC-Tag) via CDK | 60 Min | ☐ |
| 2.2 | OAuth-Consent-Endpoint /auth/google/callback im Container, Refresh-Token-Persist | 90 Min | ☐ |
| 2.3 | Token-Refresh-Logik mit ABAC-IAM (Container kann nur eigene Tenant-Items lesen) | 90 Min | ☐ |
| 2.4 | User-Isolation-Tests: kann ich mit fremdem JWT auf andere Mailboxen? Sollte NEIN | 60 Min | ☐ |
| 2.5 | Andre als Test-User einladen (Marvin koordiniert), Onboarding-Doku | 30 Min Marvin + Wartezeit | ☐ |
| 2.6 | Audit-Log-Layer (CloudWatch Logs strukturiert, pro Tool-Call: subject, tool, timestamp, success) | 60 Min | ☐ |
Wall-Clock: 2-3 Tage (bottleneck: Andre-Test koordinieren)
Phase 3: Production-Ready für externe Nutzer (Composio-Hybrid)
| Step | Was | Status |
|---|---|---|
| 3.1 | Composio-Account anlegen, Gmail-Toolkit verbinden, eigenen MCP-Endpoint dahinter schalten | ☐ |
| 3.2 | Onboarding-Page gmail.agenticventures.de/connect (statisch, Cloudflare Pages) | ☐ |
| 3.3 | AVV-Template + Datenschutzerklärung (rechtlich review lassen) | ☐ |
| 3.4 | Per-User Rate-Limiting in GuardMiddleware (existiert in vf-hosted, anpassen) | ☐ |
| 3.5 | Cost-Alarme: 50€-Schwelle für gsuite-hosted Service in av-production | ☐ |
Wall-Clock: 1-2 Wochen aktiv + AVV-Wartezeiten
Phase 4: Pipeline als Skills (parallel zu Phase 2/3)
| Step | Was | Status |
|---|---|---|
| 4.1 | Templates extrahieren: ~/source/mcps/_templates/single-aws-hosted/ (Dockerfile, CDK-Stack, FastMCP-Skeleton) | ☐ |
| 4.2 | Neuer Skill mcp-aws-deploy — nimmt lokalen MCP, deployed nach AWS | ☐ |
| 4.3 | Update mcp-cloud-bereitstellung mit AWS-Variante (statt nur Railway) | ☐ |
| 4.4 | Master-Skill mcp-pipeline der orchestriert (Spec → Local → Container → AWS → Auth → Doku) | ☐ |
| 4.5 | Test mit zweitem MCP-Bedarf — messen ob es wirklich 2-3 Tage statt 5-7 ist | ☐ |
Wall-Clock: 2-3 Tage (parallel)
Decision-Points (wo Marvin im Loop bleibt)
| Punkt | Was Marvin entscheidet | Wann |
|---|---|---|
| Nach 1A.1 | gsuite-Repo-Skeleton OK? | nach 60-90 Min Bau |
| Nach 1A.2 | CDK-Plan OK? Welche Resource-Sizes? | nach Skeleton |
| Nach 1A.3 | Smoke-Test grün? Tools liefern plausibel? | nach lokalem Container |
| Vor 1A.4 | SSO-Login aws sso login --profile av-prod ausführen | bevor Deploy |
| Vor 1A.5 | DNS-Eintrag in Strato + Cloudflare-Routing setzen | nach AWS-Deploy |
| Vor 1A.6 | claude.ai Custom-Connector einrichten | nach DNS-Setup |
| Nach 1B.1 | Repo-Trim sauber? Tests grün? | nach Repo-Edits |
| Nach 1B.2 | CDK-Stack OK? Sizing identisch zu gsuite (1 vCPU/2 GB)? | nach Skeleton |
| Nach 1B.3 | Container baut + /health lokal grün? | nach Container-Build |
| Vor 1B.4 | Railway-Production-Tokens exportieren (railway variables --kv) — Marvin gibt Werte, Claude pusht ins Secrets Manager | bevor Deploy |
| Vor 1B.5 | DNS-Origin-Switch im Cloudflare-UI — Marvin klickt mit Anleitung | nach AWS-Deploy stabil |
| Vor 1B.6 | André kurz pingen für Connector-Smoke-Test | nach DNS-Switch |
| Vor 1B.7 | ≥ 24h grüne AWS-Logs ohne Tool-Errors? Dann erst Railway abschalten | nach Smoke |
| Nach 2.4 | User-Isolation-Tests grün? KEIN Datenleak möglich? | bevor 2.5 |
| Nach 2.5 | Andre als Test-User OK mit Setup? Sein Gmail erfolgreich verbunden? | nach Test-Run |
| Phase 3 Start | Composio-Hybrid bestätigt vs Self-Verification? | vor Phase 3 |
| M365-Re-Enable | Compliance-Review (Mail/Drive/Tenant/AVV) abgeschlossen? | separates Mini-Projekt nach VF-Stabilität |
Was Claude (Agent) NICHT kann
- AWS Console-Klicks (nur via CLI)
- OAuth-Browser-Consent-Flow durchklicken
- DNS-Records in Strato setzen
- claude.ai Custom-Connector einrichten (Marvins Account)
- Composio/Scalekit Production-Account anlegen
- Echte User-Tests mit Andre koordinieren
→ Bei diesen Punkten stoppt Claude und gibt Marvin konkrete Anleitung mit Deep-Links.
Risiken & Mitigationen
| Risiko | Mitigation |
|---|---|
| ECS Express Mode neu in 2026 — Doku-Lücken möglich | Fallback zu klassischem ECS Fargate wenn Express-Mode-Quirks auftreten (gleicher Underbau, mehr Boilerplate) |
| Token-Isolation-Bug → Datenleak | strikte Test-Battery in Phase 2.4, kein Go-Live für Externe ohne grüne Tests |
| ECS Cold-Starts → langsame erste Tool-Calls | Min-Tasks=1 (~5-10$/Monat), Cost-Alarm bei 50€ |
| Pattern-Extraktion fällt unter den Tisch | Eigene Sub-Tasks in Phase 4, nicht „mach ich später” |
AWS-CDK-Bootstrap noch nicht in av-production gemacht | Step 1.4 enthält cdk bootstrap falls noch nötig |
Cross-Refs
- produkt-bundle — uebergeordnetes Produkt das diese Pipeline ausfuehrt. Phase 1-4 hier sind technische Bausteine fuer Phasen A/B/C dort.
- markdown-und-db-trennung — erweitert Phase 2 um S3-Vault zusaetzlich zu DynamoDB (~+1 Woche)
- service-first-zu-produkt — Sequenzierung Service → Produkt
- mcp-hosting-aws-ecs-express — destilliertes Pattern (Architektur, IAM, Cost-Modell, Lessons-Learned). Ab Phase 1.2 fortlaufend gepflegt.
- _index — AWS-Account-Inventar + Bedrock-Status
- accounts — Account-IDs + CLI-Profile
- mcp-vf-hosted — Template-Basis
- mcp-gsuite — Sub-MCP-Source
- mcp-vf-hosted — Hosting-Pattern (Railway-Variante als Referenz)
- mcp-eigenbau — Lokal-Bau Skill
- mcp-cloud-bereitstellung — Cloud-Deploy Skill (wird Phase 4 erweitert)
- Memory:
MCP-as-a-Service Vision,AWS-First Hosting
Verlauf
- 2026-05-09: Projekt angelegt. Plan finalisiert nach Recherche (App Runner ist tot → ECS Express Mode; Restricted-Scope-Verification ist 5-15k$/Jahr → Composio-Hybrid für Phase 3). Stack-Entscheidungen final.
- 2026-05-10 (Hebel 2/3/4 — UX/Diagnostic-Polish): Drei Workflow-Prompts (
offene_posten,event_bilanz,monatsabschluss) inmcp-vf-hosted/src/mcp_vf_hosted/prompts.pyvia@mcp.prompt-Decorator registriert. Erweiterter/healthmitversion/submcps_active/uptime_seconds. Sub-MCP-Tool-Descriptions geprueft — schon deutsch und prägnant, keine Aktion noetig (= Hebel 3 stiller Skip). Tests +8 (27/27 grün). Container lokal gesmoked. AWS-Deploy mit Cloudflare-Cutover gebuendelt. - 2026-05-11 (Fargate-Tunnel-Pivot 1B.8 durchgezogen): Alter McpVfHosted-Stack abgerissen (vorher DeletionPolicy
Delete→Retainaufmcp-vf-hosted/upstream-tokensgepatcht via update-stack — sonst waeren die 6 Sub-MCP-Tokens beim Delete weg gewesen). Neuer Stack komplett umgeschrieben (mcp-vf-hosted-stack.ts.ecs-express-backupals Backup behalten):FargateService+FargateTaskDefinitionmit 2 Containern (vf-mono + cloudflared/cloudflared:latest-Sidecar), egress-only SG, kein ALB, Clusterdefaultund Default-VPC importiert. 3 Versuche bis CREATE_COMPLETE: (1)fromSecretNameV2generiert Wildcard-ARN-??????in IAM-Policy, aber ECSValueFromruft Name-only-ARN → AccessDenied. Fix:fromSecretCompleteArnmit echtem ARN inkl.-AHEi6G/-q5MEkS. (2) Health-Checkcurl -f localhost:8080/healthschlaegt fehl weilpython:3.12-slimkein curl hat. Fix:python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen(\"http://localhost:8080/health\", timeout=3).status==200 else 1)". (3) Deploy CREATE_COMPLETE in 149s, Service ACTIVE 1/1/0, Tunnel registered (4 QUIC-Connections nach fra16/03/20/08), interner Health-Check alle 30s 200. M365 wieder aktiv mitsamt papierkram + ticketpay — alle 3 Sub-MCPs proxied. Offen: 1B.9 DNS-Cutover — Marvin muss CNAMEmcp-vfin CF aufce6dd7c0...cfargotunnel.comaendern (UI oder API mit CF_API_TOKEN/CF_ZONE_ID). - 2026-05-10: Phase 1 in 1A (gsuite, Pattern-Etablierung, 1A.1-1A.3 ✅) und 1B (VF-Migration, papierkram + ticketpay, M365 deferred) gesplittet. 1B.1 ✅ —
mcp-vf-hostedrepo getrimmt: M365-Dependency + Code-Pfade in-place auskommentiert mit konsistentem Re-Enable-Marker,boto3für Bootstrap-Optionalität dazu,.dockerignoreneu gegen.env-Leak, README auf AWS-ECS-Express umgeschrieben, 19/19 Tests grün. 1B.2 ✅ — CDK-Stackinfra/analog gsuite-hosted angelegt, Sub-MCP-Tokens via ECS-secrets:-Mapping (<arn>:KEY::-Syntax) statt File-Bootstrap (kein entrypoint.sh nötig).cdk diffgrün gegenav-production: 7 Resources + 1 IAM-Policy, Trust-Principals korrekt (ExecRole/TaskRole = ecs-tasks, InfraRole = ecs.amazonaws.com). 1B.3 ✅ —docker buildx build --platform linux/amd64durch (430 MB Build-Context, Sub-MCP-venvs ziehen mit — Tweak vor Push siehe Status). Container startet, beide Sub-MCP-Subprozessesubmcp_proxied(papierkram + ticketpay, kein m365),/health→ 200{"ok":true}. Architektur-Doc neu unter~/source/mcps/mcp-vf-hosted/docs/architecture.mdmit Mermaid-Diagrammen für Trust-Boundaries, Sub-MCP-Komposition und Tool-Call-Sequenz. 1B.4 ✅ — Production-Tokens viarailway variables --service vf-mcp --kvlokal gezogen, 3 Sub-MCP-Tokens (PAPIERKRAM_TOKEN/SUBDOMAIN, TICKETPAY_API_KEY) als JSON ins Secrets Managermcp-vf-hosted/upstream-tokensgepusht (Python-Pipe, nie in Bash-Stdout). 2 Scalekit-Werte hardcoded im Stack (nicht-secret).cdk deploybrauchte 3 Anläufe (5 Lessons-Learned ins Pattern-File geschrieben): IAM-Description darf nur ASCII enthalten (Em-Dash failed), CPU/Memory braucht Fargate-MiB-Format'1024'/'2048'nicht'1'/'2', retained ECR-Repo nach Failed-Stack-Rollback viaRepository.fromRepositoryNameumgehen. StackCREATE_COMPLETEnach 380s, ServiceEndpointmc-1a56ed08537b4f9fae11028fe698af47.ecs.eu-central-1.on.aws,/healthHTTP 200{"ok":true}mit Security-Headern. Railway-Token-File geshredded.