Payment Orchestrator MCP Server
Zahlungsrouting-Orchestrator
Evidenz im heißen Pfad, KI an den Rändern.
Bei einer anstehenden Kartenautorisierung entscheidet er, welcher Zahlungsdienstleister sie erhalten soll – auf Basis empirischer Genehmigungs-Evidenz, innerhalb einer Gebührentoleranz, die der Betreiber in realen Einheiten angibt. Wenn der Versuch abgelehnt wird, entscheidet eine Zustandsmaschine, die auf der Fehlerklasse der Ablehnung basiert, was als Nächstes passiert: derselbe PSP später, Failover jetzt, ein anderer Kanal oder Stopp. Die Routing-Entscheidung selbst ist deterministisch und prüfbar; in ihr läuft kein Sprachmodell.
Gebaut und ausgeliefert in Claude Code: Die Engine, die KI-Randschicht, die Eval-Harness, die Web-UI, die API und diese README wurden in agentischen Sitzungen erstellt – eine orchestrierende Sitzung, die an Subagenten (Backend, UI, Publish, Fallstudie) delegierte – und sind durch die Tests und Evals abgesichert, die Sie selbst ausführen können. Die technische Disziplin ist dieselbe wie in nutri. beschrieben: Konventionen, die der Agent laden muss, strukturelle Leitplanken und eine Maschine – kein Versprechen – als Definition von „fertig". Die Leitplanken fingen ab, was sonst ausgeliefert worden wäre: ein Rewrite, das jeden API-Pfad verlor (gefunden durch Post-Deploy-Verifikation), eine UI, die gültige Emittenten als unbekannt kennzeichnete, und zwei falsche Annahmen des Autors (eine Seitenzahl-Regel, ein DNS-Setup), die Subagenten sich weigerten umzusetzen.
Live-Demo https://orchestrator.vryahn.com · Fallstudie
https://vryahn.com/work/routing · API api/README.md ·
MCP MCP.md
Out-of-Sample-Replay auf 84.011 TEST-Transaktionen (Tage 22–31, Tabellen
trainiert auf Tagen 1–21): erwartete Genehmigungsrate 72,02 % bei
cost_bias=0 gegenüber 66,13 % tatsächlich beobachtet – +5,89
Prozentpunkte, richtungsweisend, kein A/B-Ergebnis. Siehe
Einschränkungen.
Ausführen
Python 3.11. requirements.txt ist die Laufzeit – fastapi plus die
Standardbibliothek, und das Einzige, was Vercel installiert.
requirements-dev.txt ergänzt den Offline-Stack (duckdb, pandas, numpy,
pyarrow, mcp, uvicorn, httpx), der benötigt wird, um Daten neu zu erzeugen,
den Backtest auszuführen, MCP zu bedienen oder lokal zu testen.
python3.11 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/python cli.py --txn-file demo_transactions.json # 8 decision-boundary cases
.venv/bin/uvicorn api.index:app --reload --port 8000 # API on /api/*, UI from public/Die Tabellen, die die Engine liest (routing_tables.json,
routing_meta.json), sind eingecheckt, sodass ein frischer Klon routet – und
deployt – ohne die Offline-Pipeline. Regenerieren Sie sie nur, wenn sich das
Datenmodell ändert:
.venv/bin/python synth_attempts.py # seeded ~300k attempts -> attempts.parquet
.venv/bin/python build_routing_tables.py # -> routing_tables.json, routing_meta.json
.venv/bin/python backtest.py --json # -> backtest_summary.json
.venv/bin/python tests.py # engine
.venv/bin/python tests_ai.py # AI edges + HTTP contract
.venv/bin/python evals/decline_eval.py # normalizer against the golden setRelated MCP server: ai-log-mcp-server
Architektur
flowchart LR
subgraph offline["OFFLINE — batch, once per rebuild"]
G["synth_attempts.py<br/>seeded generator"] --> A[("attempts.parquet<br/>1 row = 1 attempt, ~300k")]
A -->|"build_routing_tables.py"| T[("routing_tables.json + routing_meta.json<br/>segment x PSP: n, approvals, p_hat, Wilson LB<br/>4-level hierarchy")]
A -->|"backtest.py — train d1-21, test d22-31"| B["backtest_summary.json<br/>out-of-sample lift"]
end
subgraph edgein["EDGE IN — language to enum"]
RAW["raw PSP decline<br/>ISO 8583 / decline_code / refusalReason / bank prose"] --> N{"decline_normalizer.py<br/>table -> LLM -> safe fallback"}
EV["evals/ — 48 golden declines<br/>accuracy by route, hallucination gate"] -.->|"scores"| N
end
subgraph online["ONLINE — pure engine, never touches raw data"]
X["txn: amount, bin6/issuer, funding,<br/>channel, attempt #, error history"] --> D{"decide(txn, config)"}
T --> D
N -->|"error_class"| D
D --> S1["1. resolve segment per PSP<br/>walk L0 to L3 until n >= min_support"]
S1 --> S2["2. score = Wilson LB x amount x (1 - fee)<br/>= expected net collected"]
S2 --> S3["3. pick PSP — cost_bias 0..1 maps to<br/>fee tolerance 0..10pp; psps_down excluded"]
S3 --> S4["4. retry state machine<br/>keyed on last error_class"]
S4 --> R["Decision: route_psp, eligible_psps with scores,<br/>retry policy, reasoning lines"]
end
R --> OPS["ops.py — route, explain, simulate,<br/>evidence, normalize, backtest"]
B --> OPS
OPS --> CLI["cli.py"]
OPS --> API["api/index.py — FastAPI on Vercel<br/>+ public/ web UI, same origin"]
OPS --> MCP["mcp_server.py — 6 MCP tools"]Warum dieses Design
Offline/Online-Trennung.
decide(txn, config) -> Decisionist rein. Sie lädt vorab materialisierte Tabellen einmal und liest nie rohe Versuche, sodass die Entscheidung Mikrosekunden dauert, ohne Datenbank testbar und im Nachhinein prüfbar ist. Es ist dieselbe Grenze, die man in der Produktion zwischen einer Abgleichsschicht und einer Routing-Schicht ziehen würde.Segmenthierarchie mit Fallback. L0 ist
gateway_group × funding × issuer_bucket × amount_band; L3 istgateway_groupallein. Support wird pro PSP aufgelöst, eine Dimension nach der anderen (amount band → issuer → funding), bis eine Zellemin_support(Standard 200) überschreitet, und die verwendete Ebene wird mit der Entscheidung gemeldet. Der Kanal ist erstklassig und wird nie verworfen: kartenpräsent und off-session sind verschiedene Welten.Wilson-Untergrenze, nicht die rohe Rate. Ein Segment mit 3/3 Genehmigungen ist kein 100-%-Segment. Die Grenze schrumpft gegen null, wenn der Support dünner wird, sodass eine gut belegte 78 % eine glückliche 100 % schlägt, ohne eine separate Konfidenzregel, die nachgerüstet werden müsste.
cost_biasals expliziter Regler, in realen Einheiten. Der Kompromiss wird formuliert als „Prozentpunkte Genehmigungsrate, die ich für einen günstigeren PSP aufgebe" –tolerance = cost_bias × 10pp, und der günstigste PSP innerhalb dieser Toleranz des besten Genehmigers gewinnt. Ein gewichteter Score würde es einer Gebührendifferenz von Bruchteilen eines Punktes erlauben, eine zweistellige Genehmigungslücke stillschweigend zu überstimmen; ein Toleranzfilter kann das nicht. Der Backtest bepreist den Regler: 72,02 % / +5,89 pp Genehmigungsrate beicost_bias=0, 71,56 % / +5,43 pp bei 0,5, 69,57 % / +3,44 pp bei 1,0.Wiederholung nach Fehlerklasse, nicht nach blindem Zähler.
insufficient_fundsist ein Kontoproblem und wiederholt denselben PSP im nächsten Abrechnungsfenster;bank_auth_requiredoff-session kann ohne den Kunden nicht erfüllt werden, also wird es auf einen kartenpräsenten Kanal umgeplant, statt Versuche zu verbrennen;fraud_riskstoppt die Kette dauerhaft;generic_declineführt einen Failover zum nächsten PSP nach Score aus. Eine unbekannte Klasse degradiert zur generischen Failover-Policy und sagt das.
Wo KI hingehört – und wo nicht
Es gibt kein LLM in decide(). Geld sollte sich nicht auf ein gesampeltes
Token bewegen. Das Sprachmodell ist auf die beiden Ränder beschränkt, an denen
natürliche Sprache tatsächlich das Problem ist.
Drin – decline_normalizer.py. Jeder PSP lehnt in seinem eigenen Dialekt
ab: ISO-8583-Numerik, ein Stripe-ähnlicher decline_code, ein
Adyen-ähnliches refusalReason oder roher Bankprosatext. Die
Wiederholungs-Zustandsmaschine basiert auf einem Enum, also müssen die
Dialekte kollabieren, bevor die Engine sie sieht. Eine deterministische Tabelle
behandelt die Codes, die Volumen tragen – Konfidenz 1,0, keine Latenz, keine
Kosten. Nur ein Tabellen-Fehlgriff erreicht die Modellkette (Gemini, dann
Mistral), die unter einem eingeschränkten Enum-Schema antwortet. Alles außerhalb
des Enums oder unter 0,6 Konfidenz wird zugunsten von generic_decline
verworfen, dem eigenen sicheren Standard der Wiederholungs-Policy. Das
Repository läuft grün ohne gesetzte API-Schlüssel.
Gemessen, nicht vertraut – evals/. 48 goldene Ablehnungen: ~60 %
Tabellentreffer, ~40 % absichtlich außerhalb der Tabelle (Tippfehler,
ausführlicher Banktext, ungewöhnliche Codes) plus ein paar wirklich
mehrdeutige, bei denen generic_decline die richtige Antwort ist. Die
evals/baseline.json verzeichnet zwei Baselines. Nur Tabelle (keine Schlüssel):
32/48 = 66,67 %, d. h. 100 % auf den 28 Tabellenfällen und der sichere
generic_decline-Standard auf den 20, die durchfallen. LLM (Schlüssel
konfiguriert, ausgeführt gegen die deployte API mit --remote): 48/48 =
100 % – 28 Tabelle, 19 beantwortet von gemini-3.6-flash, 1 durch den
Niedrigkonfidenz-Fallback, bei dem generic_decline die erwartete Antwort war.
Der Runner meldet Genauigkeit nach Route und eine Konfusionsmatrix pro Klasse,
behauptet null Halluzinationen und lässt den Build fehlschlagen, wenn die
Genauigkeit mehr als 2 pp unter der passenden Baseline fällt.
Draußen – mcp_server.py. Sechs MCP-Tools – route_transaction,
explain_decision, simulate, segment_evidence, normalize_decline,
backtest_summary – erlauben einem Agenten, die Engine auf Englisch zu
bedienen. Der Agent kann jede Entscheidung hinterfragen und keine davon
ändern. Siehe MCP.md.
Einschränkungen
Die Daten sind synthetisch. Die Struktur ist darauf ausgelegt, Routing-Entscheidungen nicht-trivial zu machen, nicht ein reales Portfolio zu reproduzieren.
Keine Live-PSP-Connectors: Die Engine entscheidet, sie sendet nicht.
Kein Fraud-Scoring, keine 3DS-Orchestrierung, keine Network-Tokens, keine Durchsetzung von Scheme-Retry-Regeln.
Der Backtest ist richtungsweisend. Historisches Routing war nicht randomisiert, Kapazitätsgrenzen werden nicht modelliert, und „erwartete Genehmigungsrate" ist eine TRAIN-Perioden-Wilson-LB-Rate, angewendet auf TEST-Volumen – kein Live-A/B-Ergebnis.
Die Tabellen poolen alle Versuche, während der Backtest nur auf Erstversuchen trainiert und replayt; Nur-Erstversuch-Produktionstabellen wären die nächste Korrektur.
Das LLM-Eval umfasst 48 Fälle und einen Lauf; 100 % auf einer so kleinen goldenen Menge ist ein Tor gegen Regressionen, kein Anspruch über den langen Schwanz in der Produktion.
Dateiübersicht
Datei | Zweck |
| seed-basierter Generator für |
| baut |
| die Engine: |
| PSP-Ablehnungsdialekte → das |
| die Operator-Funktionen (route, explain, simulate, evidence, normalize, backtest), die von API und MCP gemeinsam genutzt werden |
| FastAPI auf Vercel; Vertrag in |
| MCP- stdio-Server, sechs Tools; siehe |
| CLI-Frontend: eine Transaktion über Flags oder einen Batch über |
| statische Web-UI, von Vercel von derselben Origin wie die API ausgeliefert |
| 8 entscheidungsgrenzwertige Transaktionen mit |
| TRAIN-Tage 1–21 / TEST-Tage 22–31-Replay bei |
| 48 goldene Ablehnungen, der Scoring-Runner und die aufgezeichnete Baseline |
| assert-basierte Prüfungen: die Engine, dann die KI-Ränder und der HTTP-Vertrag |
Bryan Rodríguez Abarca · vryahn.com · Entstanden aus einer technischen Übung, verallgemeinert als persönliches Projekt. Synthetische Daten.
This server cannot be installed
Maintenance
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
- AlicenseNot gradedqualityDmaintenanceEnables natural-language investigation of Datadog data including logs, metrics, monitors, traces, hosts, dashboards, events, and incidents, all through read-only API access.2,053MIT
- FlicenseNot gradedqualityBmaintenanceEnables querying and managing AI logs through tools like listing logs, retrieving jobs, and performing AI-powered chat queries. Also provides access to gateway security reports and guardrail testing.
- AlicenseAqualityBmaintenanceInvestigate fraud directly from Claude, Cursor, or any MCP-compatible client. Analyze suspicious activity with clear, evidence-backed verdicts. Pivot from a single signup to every account sharing the same device, IP address, or email inbox. Check entities against a cross-operator abuse network, review linked accounts, and efficiently process your fraud review queue. Read-only by default, with no r10269MIT
- FlicenseNot gradedqualityBmaintenanceEnables operations teams to diagnose and resolve stuck orders via natural-language queries. It provides evidence-based resolution proposals, but any state-changing action requires explicit human confirmation.
Related MCP Connectors
See, price, and control every tool call your AI agents make: policy checks, cost, and audit tools.
A paid remote MCP for AI SDK data query MCP, built to return verdicts, receipts, usage logs, and aud
Enterprise AI Control Plane: governance, guardrails, spend tracking, compliance & smart routing.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/vryahn/payment_orchestrator'
If you have feedback or need assistance with the MCP directory API, please join our Discord server