Tool-Output-Bloat-Fix Plan
Overview
Sonnet 4.6 bricht in vf-sonnet (Open WebUI + Bedrock + mcp-vf-hosted) regelmaessig mit unvollstaendiger Antwort ab wenn die Aufgabe mehr als 2-3 Tool-Calls plus nennenswerte Datenmengen verarbeiten muss. Symptom-Bekaempfung mit max_tokens 4k → 16k → 32k skaliert nicht. Dieser Plan adressiert die Wurzel ueber vier Phasen — Quick-Wins, Server-Side-Aggregations-Tools, Tool-Output-Compaction-Defaults, Long-Term-Workflow-Tool-Coverage — und etabliert das Pattern fuer alle kuenftigen Multi-Tool-Use-Cases.
Problem Frame
Konkretes Beispiel (heute 14:30 in VF-Pilot): User fragt nach Event-Bilanz, Sonnet feuert 5 parallele ticketpay_list_*-Calls mit Default size=50. Tool-Output kombiniert: 20-30k Tokens Rohdaten. Sonnet beginnt zu antworten, bricht bei „Lass mich al” ab. Bedrock-Logs zeigen 200 OK fuer alle Calls — also kein API-Fehler, sondern Output-Budget aufgebraucht oder Stream gecuttet.
Wurzelanalyse:
- Tool-Output-Bloat (primaer) — 5 list-Calls × 50 Records mit allen Feldern fressen 20-30k Tokens, die Sonnet erst lesen + aggregieren muss bevor visible Output startet.
- Extended Thinking frisst unsichtbar 3-8k Output-Tokens —
max_tokensdeckt thinking + visible Output gemeinsam. - Cloudflare-Tunnel 100s-Cutoff (Issue #16747) — bei langem Sonnet-Reasoning kommen keine Stream-Bytes durch, CF killt die Verbindung.
- Eskalierende Knappheit — bei jedem zusaetzlichen Tool-Call oder Folge-Schritt wird Output-Headroom enger, bis es kollabiert.
Wie Anthropic das bei claude.ai loest:
- Task-Tools statt Raw-Data-Tools — Connectors haben
get_invoice_summary(period), der Server aggregiert, das LLM bekommt 200 Tokens statt 30k. - Artifacts — lange Outputs gehen in separate Render-Komponente, nicht in den Chat-Stream.
- Extended Thinking budget explizit —
thinking.budget_tokensgetrennt vonmax_tokens. - Prompt-Caching auf Tool-Schemas — billig haeufiger zu callen statt einen Mega-Output zu verarbeiten.
Wir adaptieren #1, #3 strukturell; #2 via HTML-Output-Konvention (schon v2.5 live); #4 ist eh schon teilweise aktiv via LiteLLM cache_control_injection_points.
Requirements Trace
- R1 — Aggregations-Aufgaben (Event-Bilanz, Offene Posten, Monatsabschluss) muessen ohne max_tokens-Cutoff vollstaendig durchlaufen, auch bei 5+ User-Schritten in derselben Konversation
- R2 — Cloudflare-Tunnel-Stream darf nicht durch 100s-Timeout cuttet werden bei langem Reasoning
- R3 — Extended Thinking muss explizit gebudget sein, damit visible Output deterministisch Platz hat
- R4 — Token-Kosten pro Aggregations-Aufgabe sollen signifikant sinken (Ziel: ~Faktor 50-100 weniger Tool-Output-Tokens)
- R5 — Pattern muss wiederverwendbar sein fuer kuenftige VF-Workflow-Tools (offene_posten, monatsabschluss, andere)
- R6 — Bestehende Sub-MCPs (papierkram, ticketpay, m365) duerfen nicht breaking-changed werden — Aggregations-Tools sind additiv
Scope Boundaries
Explizit nicht in Scope:
- v2.5 HTML-Section ist schon live, nicht erneut aufmachen
- Open WebUI Filter-Functions (Audit, PII-Maskierung, Cost-Tracking) — separate Arbeit, eigener Plan
- 2FA, RAG-Migration auf pgvector, Bedrock Titan Embeddings — separate Tier-3-Items
- Stirling-PDF-Setup — separate Aufgabe, wartet auf Marvin’s CF-Setup
- MCP-Pipeline-AWS-Phase 2 (Multi-Tenant) — anderes Projekt
- M365-spezifische Aggregations-Tools — Bedarf noch nicht bewiesen, nicht jetzt
- Open-WebUI-Engine-Wechsel von Pyodide zu Jupyter — separate Compute-/Security-Diskussion
Context & Research
Relevant Code and Patterns
~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/main.py— FastMCP v2 Wrapper, mounted 3 Sub-MCPs als Proxies viacreate_proxy(Client(StdioTransport(...))). Neue Tools werden direkt mit@app.toolregistriert vorapp.mount(proxy, namespace=...).~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/prompts.py— Workflow-Prompts (offene_posten,event_bilanz,monatsabschluss). Aktueller Stand: Prompt-Texte mit Tool-Choreographie-Anweisungen. Wir migrierenevent_bilanzvon Prompt zu echtem Tool (P2).~/source/mcps/mcp-ticketpay/src/mcp_ticketpay/server.py— hat etablierten Output-Compaction-Mechanismus:_AUTO_COMPACT_BYTES = 50_000,_compact_item(),_select_fields(),count_only=True,fields=[...]. Vorbild fuer Aggregations-Tool-Output.~/source/mcps/mcp-vf-hosted/tests/— pytest-Infrastruktur mit asyncio (conftest.py, test_health.py, test_prompts.py). Plan-Test-Files folgen diesem Pattern.~/source/mcps/mcp-vf-hosted/infra/lib/mcp-vf-hosted-stack.ts— Image-Digest gepinnt; nach Code-Aenderung Image-Bump-Pattern (dokumentiert direkt im Stack-File).~/source/apps/open-webui-vf/infra/lib/open-webui-vf-stack.ts— hatDEFAULT_MODEL_PARAMSals globale ENV-Var; thinking-Budget kann dort ergaenzt werden.~/source/apps/open-webui-vf/prompts/vf-sonnet.txt— System-Prompt v2.5 mit<werkzeug_prioritaet>und<fehler_resilienz>. P3 erweitert um Tool-Output-Compaction-Klausel.
Institutional Learnings
agentic-ventures/intern/wissen/prozesse/system-prompt-patterns.md— etabliertes Pattern-File mit Snippets fuer Werkzeug-Prioritaet, Fehler-Resilienz, Output-Format. P3 ergaenzt um „Aggregation-First”-Snippet.agentic-ventures/intern/runs/2026-05-13-research-open-webui-docs/findings.md— hat schon die CF-Tunnel-Config-Empfehlung (connectTimeout: 600s,tcpKeepAlive: 30s) und das Aggregations-Tool-Pattern als wichtigste Production-Hebel identifiziert.- mcp-vf-hosted Lessons (
capabilities/mcps/mcp-vf-hosted.md): Image-Digest-Pinning vermeidet Drift, ECR-Push-Pattern dokumentiert (linux/amd64 wegen Fargate-x86), DeletionPolicy:Retain fuer Secrets vor Stack-Delete.
External References
- Anthropic Extended Thinking Doku —
thinking.budget_tokensParameter, max_tokens umfasst thinking. Empfehlung 1024-16384 je nach Komplexitaet. - AWS Bedrock Converse API thinking — wie Bedrock das thinking-Field uebernimmt (Claude 3.7+, 4.x).
- LiteLLM Anthropic-Parameter-Passthrough —
thinking={"type":"enabled","budget_tokens":4096}wird durchgereicht. - Open WebUI Issue #16747 Cloudflare-100s — Stream-Cutoff-Symptom-Beschreibung und Workaround-Snippets in Comments.
Key Technical Decisions
| Decision | Rationale |
|---|---|
Aggregations-Tools im mcp-vf-hosted Wrapper, nicht in Sub-MCPs | Cross-MCP-Aggregation moeglich (monatsabschluss spannt papierkram + ticketpay), keine Code-Duplikation in Sub-MCPs, konsistent mit Workflow-Prompts-Pattern. Sub-MCPs bleiben „raw data layer”. |
| Wrapper-Tool ruft Sub-MCPs intern via FastMCP-Client | Sub-MCPs sind eh schon als Proxies mounted; FastMCP-Client kann sie direkt aufrufen ohne Subprozess-Overhead. Tool-Output-Aggregation passiert in Python in-process. |
Erstes Pilot-Tool: ticketpay_event_bilanz | Hochfrequenter Use-Case (jedes naechste Event), klare Aggregation-Formel (Brutto, Stornos, Gebuehren, Netto), gut testbar. Andere zwei Workflow-Tools (offene_posten, monatsabschluss) folgen als P4 nach Pilot-Lerneffekten. |
thinking.budget_tokens=4096 als Global-Default | Mitte des Anthropic-Empfehlungs-Range. Bei Multi-Tool-Aufgaben reicht’s; bei Reasoning-schweren Tasks (Code-Review-Style) per-Modell-Override moeglich. |
| System-Prompt-Klausel statt Tool-Schema-Default-Aenderung in ticketpay | Backward-Kompatibilitaet — andere User des ticketpay-MCP (z.B. Marvin’s Claude-Code-Setup) sollen nicht plötzlich anders defaulten. Verhalten beim VF-Sonnet steuern wir ueber Prompt, nicht ueber Tool-Schema. |
| Aggregations-Tool gibt strukturiertes JSON mit Aggregaten + Quellen-Counts, NICHT alle Detail-Records | Faktor 50-100 weniger Tokens. Wenn User Detail braucht, callt er gezielt ticketpay_list_* mit Filter. |
| CF-Tunnel-Config: nur connectTimeout + tcpKeepAlive, kein Wechsel auf ALB/CF-Worker | Minimaler Eingriff; ALB-Wechsel wuerde mcp-hosting-fargate-tunnel-Pattern brechen, das wir gerade etabliert haben. |
Open Questions
Resolved During Planning
- Wo bauen wir das Aggregations-Tool? →
mcp-vf-hostedWrapper. Cross-MCP, weniger Duplikation, gleiche Schicht wie Workflow-Prompts. - Erstes Pilot-Tool? →
ticketpay_event_bilanz. Andere zwei (offene_posten, monatsabschluss) in P4. - Thinking-Budget? → 4096 Tokens. Mitte des Anthropic-Range, anpassbar per-Modell.
- Wo CF-Tunnel-Config aendern? → Cloudflare Zero Trust Dashboard → Networks → Tunnels →
mcp-vf-hostedundvf-chat(beide Tunnels mit den gleichen Settings — Public Hostname → Additional application settings → Connection). - System-Prompt-Klausel oder Tool-Schema-Default? → Klausel. Hat VF-Scope, andere ticketpay-User bleiben unbeeintraechtigt.
Deferred to Implementation
- Genaues JSON-Schema des Aggregations-Tool-Outputs — finalisiert beim Schreiben, abhaengig davon was TicketPAY-API beim Aggregieren genau zurueckliefert (z.B. ob
paid_atpro Transaction da ist oder ueber Status abgeleitet werden muss). - Exact pytest-Fixtures fuer das Aggregations-Tool — abhaengig davon ob wir das Live-API oder Mocks nutzen. Wahrscheinlich Mocks da kein TicketPAY-Test-Account.
- Cloudflare-Tunnel-Config-UI-Reihenfolge — UI-Layout kann sich aendern; die Setting-Namen sind stabil aber der Klick-Pfad pruefe ich erst im Browser.
High-Level Technical Design
Dieser Sketch zeigt die intendierte Struktur des neuen Aggregations-Tools im mcp-vf-hosted-Wrapper. Direktive Guidance fuer Review, nicht Implementation-Spec. Der implementierende Agent soll’s als Kontext nutzen, nicht 1:1 reproduzieren.
Vorher (heute, problematisch):
sequenceDiagram participant User participant Sonnet participant TicketPAY-MCP participant TicketPAY-API User->>Sonnet: "Event-Bilanz fuer naechstes Event" Sonnet->>TicketPAY-MCP: list_events() TicketPAY-MCP->>TicketPAY-API: GET /exports/events TicketPAY-API-->>TicketPAY-MCP: ~50 Events (paginiert) TicketPAY-MCP-->>Sonnet: 5k Tokens par Parallele Tool-Calls Sonnet->>TicketPAY-MCP: list_tickets(event_id=X) TicketPAY-MCP->>TicketPAY-API: GET /exports/tickets TicketPAY-MCP-->>Sonnet: 8k Tokens and Sonnet->>TicketPAY-MCP: list_transactions(event_id=X) TicketPAY-MCP-->>Sonnet: 6k Tokens and Sonnet->>TicketPAY-MCP: list_fees(event_id=X) TicketPAY-MCP-->>Sonnet: 4k Tokens and Sonnet->>TicketPAY-MCP: list_cancellations(event_id=X) TicketPAY-MCP-->>Sonnet: 3k Tokens end Note over Sonnet: 26k Tokens Tool-Output<br/>+ 3-8k thinking<br/>+ system prompt 3.5k<br/>= eng → Cutoff Sonnet-->>User: "Lass mich al..." [ABBRUCH]
Nachher (mit Aggregations-Tool):
sequenceDiagram participant User participant Sonnet participant vf-mono Tool participant Sub-MCPs User->>Sonnet: "Event-Bilanz fuer naechstes Event" Sonnet->>vf-mono Tool: ticketpay_event_bilanz(event_id="next") Note over vf-mono Tool: Intern parallel:<br/>5 Sub-MCP-Calls,<br/>Aggregation in Python vf-mono Tool->>Sub-MCPs: 5 Tool-Calls (intern) Sub-MCPs-->>vf-mono Tool: ~25k Tokens (in-process) Note over vf-mono Tool: Aggregation:<br/>summen + counts<br/>+ key metrics vf-mono Tool-->>Sonnet: ~200 Tokens<br/>{tickets_verkauft, brutto, stornos,<br/> gebuehren, netto, event_meta} Sonnet-->>User: Vollstaendige Bilanz-Antwort (kein Cutoff)
Tool-Output-Schema (Skizze, finalisiert in Implementation):
{
"event": {
"id": 123939,
"name": "Sparkasse Hamm | Comedy",
"date": "2026-05-27",
"status": "soldout"
},
"tickets": {
"verkauft_anzahl": 350,
"brutto_eur": 12250.00
},
"stornos": {
"anzahl": 12,
"refund_eur": 420.00
},
"gebuehren": {
"ticketpay_eur": 367.50,
"zahlungsanbieter_eur": 122.50
},
"netto_auszahlung_eur": 11340.00,
"transaktionen": {
"anzahl_bezahlt": 338,
"summe_eingegangen_eur": 11830.00
},
"_sources": {
"list_tickets_total": 350,
"list_transactions_total": 338,
"list_fees_total": 4,
"list_cancellations_total": 12
}
}Implementation Units
graph TB P1A[P1.1 CF-Tunnel-Config<br/>Browser-Action] --> Test1[Smoke-Test:<br/>lange Calls gehen durch] P1B[P1.2 Thinking-Budget<br/>Stack-ENV] --> Test1 P2A[P2.1 event_bilanz Tool<br/>im mcp-vf-hosted] --> P2B[P2.2 Tests + Build + Deploy] P2B --> Test2[Smoke-Test:<br/>Bilanz-Frage komplett] P3A[P3.1 System-Prompt v2.6<br/>Aggregation-First-Klausel] --> Test3[Verifikation:<br/>Sonnet nutzt Aggregations-Tool] P2B --> P3A P1A -.optional.- P2A P1B -.optional.- P2A Test1 --> Test2 Test2 --> Test3 Test3 --> P4[P4 weitere Workflow-Tools<br/>offene_posten, monatsabschluss]
Phase 1: Quick-Wins (parallel, blockieren nichts)
- Unit P1.1: Cloudflare-Tunnel-Config — connectTimeout + tcpKeepAlive (Marvin Browser-Action pending)
Goal: Cloudflare-Tunnel cuttet keine Streams mehr bei langem Sonnet-Reasoning (Issue 16747-Mitigation).
Requirements: R2
Dependencies: Keine. Pure Cloudflare-Dashboard-Konfiguration durch Marvin.
Files: keine — Cloudflare-Zero-Trust-Dashboard.
Approach:
- In Cloudflare Zero Trust → Networks → Tunnels → fuer beide Tunnels (
mcp-vf-hostedundvf-chat):- Public Hostname-Editor oeffnen → Additional application settings → Connection
connectTimeout: 600s(Default 30s)tcpKeepAlive: 30s(Default 30s — pruefen)keepAliveTimeout: 600s(Default 90s)- Optional:
noTLSVerify: truefalls Origin self-signed (bei uns http://localhost: nicht relevant)
- Settings speichern, kein cloudflared-Restart noetig (CF pusht Config zu Tunnel-Connectors).
Patterns to follow: Keine bestehende Doku im Vault, dieses Setup ist neu. Nach erfolgreicher Konfiguration in mcp-hosting-fargate-tunnel als Sub-Section dokumentieren.
Test scenarios:
- Happy path: Marvin oeffnet
https://vf-chat.agenticventures.de, stellt eine Frage die >120s Bedrock-Reasoning braucht (z.B. „erklaer mir Schritt fuer Schritt wie Stripe-Webhooks funktionieren”) — Antwort kommt komplett durch ohne Cutoff bei 100s. - Edge case: 5+ Min langes Multi-Tool-Reasoning (z.B. Cross-Quartal-Buchhaltungs-Analyse mit vielen Papierkram-Calls) — kein 524 Origin-Error.
Verification: CloudWatch zeigt fuer einen >100s-Call keinen 524 Origin-Error mehr; Open-WebUI-Log zeigt continuous streaming bis stop_reason=end_turn.
Estimated effort: 5-10 min Browser-Klick.
- Unit P1.2: Extended-Thinking-Budget global setzen (deployed 2026-05-14)
Goal: Reasoning-Tokens sind vom visible Output-Budget entkoppelt — Sonnet hat deterministischen Headroom.
Requirements: R3
Dependencies: Keine. Stack-ENV-Aenderung in open-webui-vf.
Files:
- Modify:
~/source/apps/open-webui-vf/infra/lib/open-webui-vf-stack.ts—DEFAULT_MODEL_PARAMSJSON-String erweitern umthinkingBlock
Approach:
- Aktuelles
DEFAULT_MODEL_PARAMS={"max_tokens":8192,"temperature":0.7,"top_p":0.9,"function_calling":"native"}erweitern um:"thinking": {"type":"enabled","budget_tokens":4096} - Vorsicht: LiteLLM muss thinking-Param fuer Bedrock Converse durchreichen — laut Anthropic-LiteLLM-Doku ja, aber bei Erst-Deploy CloudWatch checken ob Bedrock 400 wirft (z.B. bei aelteren Bedrock-Modellen die das nicht koennen).
- Per-Modell-Override moeglich via Custom-Model-
params.thinkingfalls einzelne Modelle anderes Budget brauchen. - CDK-Deploy: ~3-5 min (Make-before-break ist im Stack).
Patterns to follow:
DEFAULT_MODEL_PARAMS-Pattern existiert schon — Section folgt gleicher Konvention.- Stack-Comment-Stil: kurz erklaeren warum (verweist auf diesen Plan).
Test scenarios:
- Happy path: vf-sonnet Chat mit komplexer Aufgabe (z.B. „erstelle einen Vergleichs-Report ueber die letzten 3 Events”) laeuft durch — Antwort ist sichtbar, kein „Lass mich al”-Cutoff.
- Edge case: thinking_budget zu klein gewaehlt → Sonnet’s Reasoning ist abgeschnitten → Antwort wird oberflaechlich. Wenn das auftritt: Budget hochziehen (8192 oder 16384) per-Modell auf vf-sonnet.
- Error path: Bedrock returnt 400 weil thinking-Param nicht akzeptiert → CloudWatch zeigt das klar, Rollback durch Entfernen des thinking-Blocks und Re-Deploy.
Verification: Bei einer komplexen Aufgabe (z.B. Multi-Event-Vergleich) ist die visible Output-Token-Anzahl in der LiteLLM-Response-Usage signifikant hoeher als ohne thinking_budget (Sonnet hat mehr Headroom).
Rollback: thinking-Block aus DEFAULT_MODEL_PARAMS entfernen + Stack-Deploy. ~5 min.
Estimated effort: 20-30 min (Stack-Edit + CDK-Deploy + Smoke-Test).
Phase 2: Server-Side Aggregations-Tool
- Unit P2.1:
ticketpay_event_bilanzTool im mcp-vf-hosted (7/7 tests GREEN, registered in main.py)
Goal: Neues Wrapper-Tool das intern die 5 ticketpay_list_*-Calls macht, aggregiert und ~200 Tokens strukturiertes Ergebnis zurueckgibt. Pattern fuer alle kuenftigen VF-Workflow-Tools.
Requirements: R1, R4, R5, R6
Dependencies: Keine harten Blocker. Bevorzugt nach P1.1 (CF-Tunnel) deployen damit der erste Smoke-Test sauber laeuft.
Files:
- Create:
~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/aggregations/__init__.py - Create:
~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/aggregations/ticketpay.py— Aggregations-Logik (event_bilanz Funktion) - Modify:
~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/main.py— neue Tool-Registrierung@app.toolmit Aufruf in aggregations.ticketpay - Test:
~/source/mcps/mcp-vf-hosted/tests/test_aggregations_ticketpay.py
Approach:
Execution note: Test-first — Mock-basierter Unit-Test fuer die Aggregations-Logik schreiben, dann implementieren. Integration-Test gegen Live-API erst wenn Mocks gruen.
- Aggregations-Modul
aggregations/ticketpay.pyexportiert async functionevent_bilanz(client: FastMCP-Client, event_id: int) -> dict. - In
main.py: nach Sub-MCP-Mount, neuer@app.toolmit Nameticketpay_event_bilanz(Namespace-konsistent), Dokstring beschreibt Zweck + Output-Schema, Body ruftaggregations.ticketpay.event_bilanz(client, event_id). - Die
clientReferenz: FastMCP-v2 Wrapper hat Zugriff auf seine eigenen mounted Sub-MCPs — internally entweder viaclient.call_tool(...)oder ueber direkte Function-Refs der mounted Proxies. Welcher Pfad genau, ist Implementation-Detail (Deferred to Implementation). - Aggregations-Logik:
- Parallel:
list_events()→ finde Event mit ID, hol Name + Date + Status - Parallel:
list_tickets(event_id=X),list_transactions(event_id=X),list_fees(event_id=X),list_cancellations(event_id=X)— alle mitcount_only=Truezuerst, dann nochmal ohne wenn Detail-Aggregation noetig ist - Aggregation in Python: Summen, Counts, Netto-Berechnung
- Output strukturiertes Dict (siehe Schema in High-Level Technical Design)
- Parallel:
- Error-Handling: wenn ein Sub-Call fehlschlaegt → strukturierter Error im Output (
_errors: [{tool: "...", error: "..."}]), nicht hart-raise — der Aufrufer (Sonnet) kann dann entscheiden. - Caching: nicht in P2 (Pilot). Falls Performance-Issue: spaeter.
Patterns to follow:
- Tool-Registrierung wie in
main.pymit@app.tool(FastMCP v2 Decorator). Siehe Pattern bei den Workflow-Prompts inprompts.py. - Async/await ueberall (FastMCP v2 ist asyncio-nativ).
- Compaction-Mechanismus aus
mcp-ticketpay/src/mcp_ticketpay/server.py(_AUTO_COMPACT_BYTES) ist KEIN Vorbild — wir aggregieren komplett anders (keine Listen, sondern Aggregates).
Test scenarios:
- Happy path: event_bilanz mit valider event_id (Mock-Sub-MCP returnt 2 Tickets, 2 Transactions, 1 Fee, 0 Cancellations) → Output enthaelt korrekte Summen, Netto = Brutto - Stornos - Gebuehren,
_sources-Counts stimmen. - Edge case: kein Sold-Out — Event mit 0 Tickets verkauft → Aggregation funktioniert, alle Summen sind 0.00,
_sources.list_tickets_total = 0. - Edge case: viele Stornos — Stornos > Brutto sollte nicht negatives Netto produzieren ohne expliziten Hinweis; in
_warnings-Block hochsetzen wennnetto < 0. - Edge case: paginated Tool-Output — wenn ein Sub-Tool 3 Seiten returnt, alle paginieren (FastMCP-Client kann das oder wir loopen manuell).
- Error path: invalid event_id (negativ, string statt int) → Tool returnt strukturierten Error, kein Crash.
- Error path: TicketPAY-API down — Sub-MCP wirft Exception → Aggregation fangt das ab, returnt
_errors-Block + so-viel-wie-moeglich aggregierte Daten. - Integration scenario: echter Mount im FastMCP-Wrapper — Tool ist via
client.list_tools()sichtbar mit korrektem Schema, Docstring landet als Description (wichtig fuer Sonnet’s Tool-Choice).
Verification:
- pytest gruen mit allen Test-Scenarios
- Tool-Schema bei
await client.list_tools()enthaeltticketpay_event_bilanzmit kompletter Description - Lokaler Smoke-Test mit MCP-Inspector: Tool ruft alle Sub-MCPs, returnt korrekte Aggregate
Rollback: Stack-File auf vorherigen Image-Digest pinnen + CDK-Deploy. Aggregations-Code bleibt im Repo, ist nur nicht mehr im Container. ~5 min.
Estimated effort: 2-3h (Tests schreiben + implementieren + lokal verifizieren).
- Unit P2.2: ECR-Build + ECS-Deploy mit neuem Aggregations-Tool (deployed 2026-05-14, digest ae60756b)
Goal: mcp-vf-hosted Container laeuft mit dem neuen Tool in eu-central-1, ist via Cloudflare-Tunnel erreichbar.
Requirements: R1, R4
Dependencies: P2.1 fertig
Files:
- Modify:
~/source/mcps/mcp-vf-hosted/infra/lib/mcp-vf-hosted-stack.ts— Image-Digest in der vf-mono-Container-Definition
Approach:
docker buildx build --platform linux/amd64 -f mcp-vf-hosted/Dockerfile -t <ecr-uri>:latest --push .aus~/source/mcps/- Neuen Manifest-Digest aus ECR holen:
aws ecr describe-images --repository-name mcp-vf-hosted --image-ids imageTag=latest --query 'imageDetails[0].imageDigest' --output text - Stack-File mit neuem Digest patchen
- CDK Deploy mit
--profile av-prod --require-approval never - ECS macht Make-before-break, ~3 min Deployment-Zeit
Patterns to follow: Exakt das Bump-Pattern aus dem Dockerfile-Kommentar und mcp-vf-hosted-stack.ts (haben wir gestern 2026-05-13 genutzt fuer den ticketpay-Fix).
Test scenarios: Keine direkten Code-Tests — Smoke-Test gegen Live-Endpoint via MCP-Inspector oder vf-sonnet direkt.
Verification:
- ECS describe-services zeigt
runningCount: 1, rolloutState: COMPLETED, taskDefinition: <neue Revision> - vf-sonnet Chat: „Mach mir die Bilanz fuer das naechste Event” → Tool wird aufgerufen, Antwort kommt komplett ohne Cutoff
- CloudWatch-Logs zeigen Sub-MCP-Calls bei ticketpay_event_bilanz-Invocation (interne Calls sichtbar)
Rollback: Vorherigen Digest in Stack-File + Re-Deploy. ~5 min.
Estimated effort: 15-20 min Build + Push + Deploy.
Phase 3: System-Prompt Aggregation-First-Klausel (v2.6)
- Unit P3.1: vf-sonnet System-Prompt v2.6 — Aggregation-First (live 2026-05-14, 15008 chars)
Goal: Sonnet ruft automatisch das neue Aggregations-Tool statt 5 list_*-Tools wenn die Frage nach einer Bilanz/Aggregation aussieht.
Requirements: R1, R5
Dependencies: P2.2 muss deployed sein (sonst kennt Sonnet das Tool nicht im Schema-Discovery).
Files:
- Modify:
~/source/apps/open-webui-vf/prompts/vf-sonnet.txt— neue Section<aggregation_first>oder Erweiterung von<werkzeug_prioritaet> - Modify:
~/source/apps/open-webui-vf/prompts/vf-sonnet.md— Changelog-Eintrag v2.6 - API-Patch via curl auf
https://vf-chat.agenticventures.de/api/v1/models/model/update?id=vf-sonnet(keine Stack-Deploy noetig)
Approach:
Neue Section (oder Ergaenzung) mit klarem Pattern:
<aggregation_first>
Wenn die Aufgabe nach einer Aggregation aussieht (Bilanz, Summe,
Uebersicht, Vergleich, Monatsabschluss): pruefe zuerst ob es einen
spezifischen Workflow-Tool fuer diese Aggregation gibt. Beispiele:
- "Event-Bilanz" / "Was hat das Event eingebracht" / "Tickets + Netto fuer Event X"
-> ticketpay_event_bilanz(event_id), NICHT 5 parallele list_*-Calls
- "Offene Posten" / "Unbezahlte Rechnungen" -> (kuenftig: papierkram_offene_posten)
- "Monatsabschluss Mai" -> (kuenftig: vf_monatsabschluss(monat))
Wenn es einen passenden Aggregations-Tool gibt: IMMER den nutzen statt
mehrere raw list_*-Tools zu chainen. Der Aggregations-Tool macht
serverseitig die Berechnung und liefert ~200 Tokens statt 30k Tokens
Rohdaten — schneller, billiger, kein Output-Cutoff-Risiko.
Wenn KEIN passender Aggregations-Tool existiert UND die Aufgabe trotzdem
viele list_*-Calls braucht: nutze `count_only=True` und `fields=[...]`
aktiv um Tool-Output klein zu halten. Bei ticketpay-Tools z.B.:
list_tickets(from_=..., to=..., count_only=True) gibt nur Total zurueck,
keine 50 Detail-Records.
</aggregation_first>
Patterns to follow: XML-Section-Schema des v2.5-Prompts; etabliertes system-prompt-patterns-Snippet-Format.
Test scenarios:
- Happy path: Marvin fragt „Wie lief das naechste Event finanziell?” → Sonnet ruft
ticketpay_event_bilanzals ersten und einzigen Tool, gibt strukturierte Bilanz zurueck. - Edge case: Frage ist NICHT-Aggregations „Liste mir die 5 letzten verkauften Tickets” → Sonnet ruft
ticketpay_list_tickets(size=5)und NICHT event_bilanz. Klausel darf nicht overreach-en. - Edge case: Aggregation, aber kein dediziertes Tool (noch nicht vorhanden) „Erstell mir den Monatsabschluss” → Sonnet erkennt dass es kein vf_monatsabschluss-Tool gibt, faellt zurueck auf manuelle Aggregation mit
count_only=Trueals erstem Schritt.
Verification: vf-sonnet’s Custom-Model-API-GET zeigt system_len ~12k+ Zeichen, updated_at aktuell; Smoke-Test im neuen Chat zeigt einzigen Tool-Call statt 5.
Rollback: vorherige Prompt-Version (v2.5) per API zurueckspielen. ~30 Sekunden.
Estimated effort: 30 min (Section schreiben + API-Patch + Smoke-Test).
Phase 4: Long-Term — Weitere Workflow-Tools nach Bedarf
- Unit P4.1 (deferred):
papierkram_offene_postenAggregations-Tool
Goal: Server-side Aggregation aller unbezahlten Rechnungen mit Tagen-offen und Mahnstufen.
Triggered durch: Wenn Marvin’s regelmaessige Buchhaltungs-Reviews den Workflow-Prompt /offene_posten haeufig nutzen und dort Cutoffs / langsam laeuft. Konkrete Schwelle: 2+ Vorfaelle in 2 Wochen → Tool bauen.
Pattern: Identisch zu P2.1, anderer Aggregations-Code.
Estimated effort: 1-2h.
- Unit P4.2 (deferred):
vf_monatsabschluss(monat)Cross-MCP-Aggregation
Goal: Kombiniert Papierkram-Rechnungen + TicketPAY-Auszahlungen + Bank-Bewegungen fuer einen Monat in ein konsolidiertes Ergebnis.
Triggered durch: Wenn das monatliche Reporting fuer VF tatsaechlich ueber vf-sonnet ablaeuft (nicht nur Marvin’s Console-Sessions). Plus: Pattern-Validation aus P2.1 muss durch sein.
Estimated effort: 2-3h (Cross-MCP-Logik komplexer).
Beide P4-Units: Status deferred, nicht in Scope dieses Plans. Hier nur erwaehnt damit das Pattern-Investment in P2 klar kontextualisiert ist.
System-Wide Impact
-
Interaction graph:
vf-sonnet(Custom-Model) →mcp-vf-hosted(Wrapper) → neueticketpay_event_bilanzTool → intern:mcp-ticketpay(Sub-MCP) → TicketPAY-API- LiteLLM-Layer wird
thinking-Param durchreichen — neue API-Surface gegen Bedrock Converse - Cloudflare-Tunnel-Config aendert sich fuer beide Tunnels (mcp-vf-hosted UND vf-chat) — Symmetry pruefen
-
Error propagation:
- Sub-MCP-Fehler innerhalb des Aggregations-Tools werden gefangen, in
_errorsstrukturiert, Tool returnt aber so-viel-wie-moeglich. Sonnet entscheidet ob das nutzbar ist. - Wenn LiteLLM thinking-Param nicht akzeptiert → 400 Bedrock-Error → CloudWatch zeigt das, Rollback durch Entfernen.
- Cloudflare-Tunnel-Config-Fehler (z.B. ungueltige Timeout-Werte) → CF Dashboard validiert vor Save.
- Sub-MCP-Fehler innerhalb des Aggregations-Tools werden gefangen, in
-
State lifecycle risks:
- Aggregations-Tool ist stateless — keine DB-Writes, keine Sessions. Sicher.
- Cloudflare-Tunnel-Config ist persistiert pro Hostname. Vor Aenderung dokumentieren was vorher war (Rollback-Pfad).
-
API surface parity:
- mcp-vf-hosted ist Single-Tenant (VF-only). Andere Kunden die das Pattern adoptieren wollen, wuerden eigenen Wrapper mit eigenen Aggregations-Tools bekommen.
- Sub-MCPs (papierkram, ticketpay, m365) bleiben unbeeintraechtigt — kein Breaking Change in deren API.
-
Integration coverage: Tests mit gemockten Sub-MCP-Tools decken die Aggregations-Logik. Real-World-Smoke-Test im VF-Chat ist der eigentliche Integration-Test der nicht durch Mocks ersetzt werden kann.
-
Unchanged invariants:
- Sub-MCPs: API-Vertrag unveraendert
- Scalekit-OAuth-Layer: unveraendert
- Cloudflared-Sidecar-Pattern: unveraendert (nur Config-Param-Tweak im CF-Dashboard)
- Open-WebUI-LiteLLM-Bedrock-Pfad: nur additive Param-Erweiterung
Risks & Dependencies
| Risk | Mitigation |
|---|---|
LiteLLM reicht thinking-Param nicht an Bedrock durch | Smoke-Test direkt nach P1.2-Deploy; Rollback ist 1 Zeile + CDK-Deploy |
| Aggregations-Tool macht selbst zu viele Sub-Calls und cuttet intern | count_only=True als ersten Pass, gezielt Details holen nur wenn noetig; max. 3-5 Sub-Calls pro Aggregation |
Sonnet ignoriert die neue <aggregation_first>-Klausel und ruft trotzdem raw list_*-Tools | Tool-Description sehr klar schreiben (Sonnet folgt Tool-Descriptions mehr als Prompt-Klauseln); A/B im Test pruefen |
| Cloudflare-Tunnel-Config-Aenderung bricht laufende Connections | CF macht Hot-Reload; im worst case Tunnel-Restart ueber Dashboard (cloudflared in ECS bleibt running) |
| Image-Digest-Bump im mcp-vf-hosted-Stack vergisst CDK-Diff zu pruefen → falsche Stack-Aenderung | Vor cdk deploy IMMER cdk diff pruefen — Pattern aus mcp-vf-hosted-Lessons schon etabliert |
| Aggregations-Tool-Output-Schema aendert sich spaeter → breaking change fuer Sonnet | Erst beim 2. Workflow-Tool (P4) das Output-Schema generalisieren; bis dahin per-Tool eigenes Schema OK |
| Tests sind alle gegen Mocks, Real-API hat Schema-Drift | Smoke-Test gegen Live-TicketPAY mit echtem Event vor Deploy (manuell). VF-Pilot-Phase erlaubt das. |
Cost-Implikation
P1.1 (CF-Tunnel): Keine Cost-Aenderung. Verhindert User-Frustration und Re-Runs.
P1.2 (Thinking-Budget): Output-Tokens steigen leicht (thinking_budget zaehlt zu Output-Kosten), aber Erfolgsrate komplexer Aufgaben deutlich hoeher → weniger Retry-Calls. Sonnet 4.6 Output @ 0.061 pro Call. Bei aktuell ~50 komplexen Calls/Monat = ~3 EUR/Monat Mehrkosten. Marginal.
P2 (Aggregations-Tool): Hauptsparhebel. Pro Bilanz-Aufruf:
- Vorher: 5 list_*-Tool-Outputs zu ~25k Tokens Input fuer Sonnet’s Output-Generation → ca. 0.08 EUR Input + 0.30 EUR Output = ~0.38 EUR
- Nachher: 1 aggregation-Tool-Output zu ~200 Tokens + kuerzere Output-Antwort → ca. 0.001 EUR Input + 0.05 EUR Output = ~0.05 EUR
- Ersparnis pro Aufruf: ~0.33 EUR (~85% weniger)
- Bei 30 Bilanz-Aufrufen/Monat: 10 EUR/Monat Ersparnis. Nicht riesig, aber kompounded mit anderen Workflow-Tools (P4) skaliert das.
P3 (System-Prompt v2.6): Token-Cost +~150 Tokens System-Prompt pro Call. Bei prompt-caching (eh aktiv): ~zero Marginalkosten.
Netto-Cost-Bilanz: Klar positiv. Plus: groesserer Wert ist „User-Experience” (keine abgebrochenen Antworten) und „Skalierbarkeit” (Pattern fuer kuenftige Tools).
Sources & References
- Origin: Marvin’s Brief aus /ce:plan Aufruf 2026-05-14, plus aktuelle Inzidenz-Logs in CloudWatch (open-webui-vf log group)
- Recherche-Run: _index (System-Prompt-Patterns + 8 Adaptions-Snippets)
- Recherche-Run: _index (Open-WebUI-ENV-Vars, CF-Timeout, Tool-Use-Pattern)
- Code-Vorbild:
~/source/mcps/mcp-ticketpay/src/mcp_ticketpay/server.py(_AUTO_COMPACT_BYTES,count_only,fieldsPattern) - Workflow-Prompts:
~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/prompts.py(event_bilanz Prompt-Text als Logik-Vorlage) - Anthropic Extended Thinking
- AWS Bedrock Converse + Reasoning
- Open WebUI Issue #16747
- LiteLLM Anthropic-Provider-Doku