Server data from the Official MCP Registry
18 x402 pay-per-call tools for AI agents (USDC/USDT, Base): web, crypto, DeFi, FX, geo-IP, RSS, ENS
About
18 x402 pay-per-call tools for AI agents (USDC/USDT, Base): web, crypto, DeFi, FX, geo-IP, RSS, ENS
Remote endpoints: streamable-http: https://agent-margin-router-production.up.railway.app/mcp
Security Report
Valid MCP server (1 strong, 0 medium validity signals). No known CVEs in dependencies. Imported from the Official MCP Registry.
18 tools verified · Open access · No issues found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Permissions Required
This plugin requests these system permissions. Most are normal for its category.
How to Connect
Remote Plugin
No local installation needed. Your AI client connects to the remote endpoint directly.
Add this to your MCP configuration to connect:
{
"mcpServers": {
"io-github-agentmarginrouter-agent-margin-router": {
"url": "https://agent-margin-router-production.up.railway.app/mcp"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
Agent Margin Router
EN — TL;DR: Pay-per-request data broker for AI agents. One API, 7 upstream providers, automatic routing by quality × cost × latency, paid with x402 micropayments (USDC or USDT on Base) — no account, no API key, no subscription. 3 free requests per wallet.
- Live API:
https://agent-margin-router-production.up.railway.app- Docs & examples: https://agentmarginrouter.com
- Endpoints:
POST /extract-clean(URL → clean JSON, $0.02) ·POST /market-spread(net spread between two venues after fees, $0.05) ·GET /health(free)# Try it free (3 requests per wallet): curl -X POST https://agent-margin-router-production.up.railway.app/market-spread \ -H "Content-Type: application/json" -H "X-WALLET: 0xYourWallet" \ -d '{"asset":"ethereum","buy_venue":"binance","sell_venue":"coinbase"}'Full German documentation below · Vollständige deutsche Dokumentation folgt.
Einheitliche, per x402 bezahlte Routing-Schicht für AI-Agenten. Mehrere Daten-Provider → automatische Auswahl (Qualität, Preis, Latenz, Ausfallrisiko) → normalisiertes JSON → Bezahlung pro Request in USDC oder USDT auf Base.
Agent ──POST /extract-clean──▶ Router ──▶ Provider-Scoring ──▶ bester Provider
▲ │ (Fallback, Circuit-Breaker, Mindestmarge)
│ 402 Payment Required │
│ (USDC + USDT Optionen) ▼
└──X-PAYMENT (signiert)──▶ Facilitator /verify ──▶ 200 OK + Daten ──▶ /settle on-chain
Inhalt
- Was ist der Agent Margin Router
- Schnellstart (lokal ohne Docker)
- Deployment mit Docker-Compose auf Hetzner
- Cloudflare Tunnel Setup 4b. Deployment auf Railway
- Umgebungsvariablen
- API-Endpunkte mit Beispielen 6b. Enterprise: API-Keys, Rate-Limiting, Usage & Stats
- x402 Payment Flow
- Provider hinzufügen
- Tests & Projektstruktur
1. Was ist der Agent Margin Router
Der Router ist ein B2B-Daten-Broker für Maschinen. Ein AI-Agent stellt eine standardisierte Anfrage, der Router
- prüft den Cache (Redis),
- bewertet alle passenden Provider mit
score = quality × success_probability / (price + latency_risk), - führt den Request nur aus, wenn die Mindestmarge (Default 20 %) erhalten bleibt,
- fällt bei Fehlern automatisch auf den nächsten Provider zurück (Circuit-Breaker: 3 Fehler → 5 Minuten Pause),
- normalisiert die Antwort und liefert sie mit Aktualitäts- und Konfidenzangabe aus,
- protokolliert Kosten, Provider und Marge als strukturierte JSON-Logs.
Bezahlt wird pro Request über das x402-Protokoll (HTTP 402). Akzeptiert werden von Anfang an USDC und USDT auf Base. Neue Wallets erhalten 3 kostenlose Requests (Free Tier, in Redis getrackt).
MVP-Endpunkte:
| Endpunkt | Funktion | Preis (Default) |
|---|---|---|
POST /extract-clean | URL → sauberes, schema-konformes JSON | 0,02 USD |
POST /market-spread | Netto-Spread zwischen zwei Handelsplätzen nach Gebühren, Slippage & Transfer | 0,05 USD |
GET /health | Status, Redis, Provider, Uptime, Fehlerrate, Cache-Hit-Rate | kostenlos |
Provider (echte APIs):
Name Capability Anbieter Kosten/Call (Default) Qualität apify_web_scraperextract Apify Actor apify/web-scraper(Headless-Browser, optional Proxy)~0,005 USD (wird aus usageTotalUsdnachjustiert)0.90 httpx_directextract direkter HTTP-Abruf, kein JS ~0,0002 USD 0.60 binance_publicmarket_data Binance Public API /ticker/24hr(Bid/Ask) viadata-api.binance.vision–api.binance.comist regional geo-blockiert0 USD, kein Key 0.95 coinbase_publicmarket_data Coinbase Public API /prices/{pair}/spot0 USD, kein Key 0.90 coingeckomarket_data CoinGecko /simple/price,/coins/{id}/tickers, optional/market_chart0 USD (Demo-Key, Rate-Limit) 0.88 defillamamarket_data DeFi Llama coins.llama.fi/prices/current/coingecko:{id}(Referenzpreis) +api.llama.fi/tvl/{slug}(DEX-Tiefe)0 USD, kein Key 0.75 coinmarketcapmarket_data CMC /cryptocurrency/quotes/latest(Fallback, nur Referenzpreis)~0,0004 USD (Credits) 0.70 Ohne gesetzten API-Key wird ein Provider nicht geroutet (
is_configured == False), taucht aber in/healthmitconfigured: falseauf. Der Free-Tier nutzt nur Provider mitcost_per_request <= FREE_TIER_MAX_PROVIDER_COST_USD(Default 0,001 USD) – alsohttpx_directbzw.binance_public/coinbase_public/coingecko/defillama;/market-spreadholt dabei jedes Leg vom eigenen Exchange-Feed (Binance Bid/Ask, Coinbase Spot), wenn Binance oder Coinbase Teil des Venue-Paars ist; teure Provider sind für kostenlose Requests gesperrt./extract-cleanprüft Ziel-URLs gegen private/interne Netze (SSRF-Guard: nur http/https, keine RFC-1918-, Loopback-, Link-Local- oder Metadata-Adressen, Prüfung pro Redirect-Hop); abgelehnte URLs liefern422und zählen nicht als Provider-Fehler.Einschränkung
/market-spread: Das Ergebnis ist eine Analyse, keine ausführbare Quote. Preise sind Last-Trade-Werte der Venue-Ticker (CoinGecko) bzw. ein Referenzpreis (CMC); „Liquidität“ wird aus 24h-Volumen und einem statischen Depth-Anteil je Venue geschätzt, nicht aus dem Orderbuch. Das Felddata_source/venue_data_source(ticker,mixed,reference) undnoteim Response kennzeichnen die Datenbasis.
2. Schnellstart (lokal ohne Docker)
Voraussetzungen: Python ≥ 3.11, optional ein lokaler Redis (ohne Redis nutzt die App im Dev-Modus automatisch einen In-Memory-Fallback).
git clone <dein-repo> agent_margin_router
cd agent_margin_router
python -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
cp .env.example .env
# Für lokale Tests ohne Wallet/Zahlung:
sed -i 's/^PAYMENT_ENABLED=.*/PAYMENT_ENABLED=false/' .env
sed -i 's#^REDIS_URL=.*#REDIS_URL=redis://localhost:6379/0#' .env
uvicorn app.main:app --reload --port 8000
Dann:
curl -s localhost:8000/health | jq .status
curl -s -X POST localhost:8000/extract-clean \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com/produkt/123"}' | jq
Interaktive API-Doku: http://localhost:8000/docs
Tests:
pytest -q
3. Deployment mit Docker-Compose auf Hetzner
Getestet für einen Hetzner Cloud Server (CX22 reicht für den Start, Ubuntu 24.04).
3.1 Server vorbereiten
ssh root@<SERVER-IP>
# System aktualisieren, Docker installieren
apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
# Nicht-Root-User für den Betrieb
adduser --disabled-password --gecos "" deploy
usermod -aG docker deploy
# Firewall: nur SSH offen lassen (HTTP kommt über Cloudflare Tunnel, s. Abschnitt 4)
apt install -y ufw
ufw allow OpenSSH
ufw --force enable
3.2 Projekt deployen
su - deploy
git clone <dein-repo> agent_margin_router
cd agent_margin_router
cp .env.example .env
nano .env # RECEIVER_WALLET, ENVIRONMENT=production, REDIS_REQUIRED=true, Preise, Provider-Keys
Wichtige Produktionswerte in .env:
ENVIRONMENT=production
REDIS_URL=redis://redis:6379/0
REDIS_REQUIRED=true
PAYMENT_ENABLED=true
RECEIVER_WALLET=0xDeineEchteWallet
Starten:
docker compose up -d --build
docker compose ps
docker compose logs -f app
curl -s localhost:8000/health | jq
Der App-Port 8000 ist im Compose-File nur auf 127.0.0.1 gebunden – von außen ist der Dienst ausschließlich über den Cloudflare Tunnel (oder einen eigenen Reverse Proxy) erreichbar.
3.3 Betrieb
docker compose pull && docker compose up -d --build # Update
docker compose logs --tail=200 app # JSON-Logs
docker compose exec redis redis-cli INFO memory # Redis prüfen
docker compose down # Stoppen (Redis-Daten bleiben im Volume)
Beide Services haben Healthchecks und restart: unless-stopped; nach einem Server-Reboot startet der Stack automatisch.
4. Cloudflare Tunnel Setup
Mit einem Cloudflare Tunnel braucht der Hetzner-Server keinen offenen HTTP-Port; TLS, DDoS-Schutz und WAF übernimmt Cloudflare.
-
Domain bei Cloudflare verwalten (Nameserver umstellen).
-
Cloudflare Dashboard → Zero Trust → Networks → Tunnels → Create a tunnel (Typ „Cloudflared“).
-
Namen vergeben (z. B.
agent-margin-router) und den angezeigten Token kopieren. -
Im Tunnel unter Public Hostname einen Eintrag anlegen:
- Subdomain:
api, Domain:deine-domain.tld - Service:
HTTP→app:8000(Docker-Servicename, da cloudflared im selben Compose-Netz läuft)
- Subdomain:
-
Token in
.enveintragen:CLOUDFLARE_TUNNEL_TOKEN=eyJhIjoi... -
Stack mit Tunnel-Profil starten:
docker compose --profile tunnel up -d docker compose logs -f cloudflared # "Registered tunnel connection" = erfolgreich curl -s https://api.deine-domain.tld/health | jq .status
Empfohlen zusätzlich im Cloudflare-Dashboard: Rate Limiting Rule auf /extract-clean und /market-spread (z. B. 60 Requests/Minute pro IP) sowie Bot Fight Mode deaktivieren, damit Agenten nicht blockiert werden.
4b. Deployment auf Railway
Alternative zu Hetzner/Docker-Compose. Das Repo enthält railway.toml (Dockerfile-Build, Healthcheck /health, Restart-Policy) und ein Procfile.
- Neues Railway-Projekt → Deploy from GitHub repo (oder
railway upper CLI). - Redis-Service hinzufügen (Datenbanken → Redis) und im App-Service die Variable
REDIS_URL=${{Redis.REDIS_URL}}setzen;REDIS_REQUIRED=true. - Variablen aus
.env.exampleim Railway-Dashboard eintragen (RECEIVER_WALLET,APIFY_API_TOKEN,COINGECKO_API_KEY,CMC_API_KEY,ENVIRONMENT=production, ggf.ENABLED_TOKENS=USDC).PORTsetzt Railway selbst – nicht überschreiben. - Deploy abwarten, dann
curl https://<railway-domain>/health– im Feldprovidersmüssen die konfigurierten Providerconfigured: truemelden.
Hinweis: Der Dockerfile-Start (uvicorn ... --port ${PORT:-8000}) läuft unverändert auch lokal und in docker-compose (dort bleibt Port 8000).
5. Umgebungsvariablen
Alle Variablen sind in .env.example mit Kommentaren dokumentiert. Die wichtigsten:
| Variable | Bedeutung | Default |
|---|---|---|
REDIS_URL | Redis-Verbindung (Cache, Free-Tier-Zähler, Replay-Schutz) | redis://redis:6379/0 |
REDIS_REQUIRED | true: kein Start ohne Redis; false: In-Memory-Fallback (nur Dev) | false |
PAYMENT_ENABLED | false schaltet x402 komplett ab (nur lokal!) | true |
FACILITATOR_URL | x402-Facilitator /verify-Endpunkt (PayAI) | facilitator.payai.network |
USDC_CONTRACT_ADDRESS | USDC auf Base | 0x8335…2913 |
USDT_CONTRACT_ADDRESS | USDT auf Base | 0xfde4…9bb2 |
PAYMENT_NETWORK | x402-Netzwerkname (base, base-sepolia) | base |
RECEIVER_WALLET | Deine Einnahmen-Wallet | – |
EXTRACT_PRICE / MARKET_SPREAD_PRICE | Verkaufspreise in USD | 0.02 / 0.05 |
FREE_TIER_LIMIT | Kostenlose Requests pro Wallet | 3 |
MIN_MARGIN_PERCENT | Mindestmarge; darunter wird nicht ausgeführt | 20 |
DAILY_PROVIDER_BUDGET_USD | Tages-Kostendeckel pro Provider | 50 |
CACHE_TTL_SECONDS | Standard-Cache-Dauer | 60 |
CIRCUIT_FAILURE_THRESHOLD / CIRCUIT_OPEN_SECONDS | Circuit-Breaker | 3 / 300 |
ENABLED_TOKENS | Akzeptierte Zahl-Token, kommagetrennt (USDC bis USDT real E2E getestet ist) | USDC,USDT |
APIFY_API_TOKEN | Apify-Token für apify_web_scraper (leer = Provider aus) | leer |
APIFY_ACTOR_ID / APIFY_TIMEOUT_SECONDS / APIFY_USE_PROXY | Actor, Run-Timeout, Apify-Proxy | apify~web-scraper / 90 / true |
APIFY_COST_PER_REQUEST | Startannahme Kosten/Call (wird aus Run-Usage nachgeführt) | 0.005 |
COINGECKO_API_KEY | CoinGecko Demo/Pro-Key für coingecko | leer |
COINGECKO_USE_MARKET_CHART | zusätzlich 24h-Volatilität abrufen (1 Call mehr) | true |
CMC_API_KEY | CoinMarketCap-Key für Fallback coinmarketcap | leer |
HTTPX_FALLBACK_ENABLED | günstigen httpx_direct-Fallback registrieren | true |
FREE_TIER_MAX_PROVIDER_COST_USD | Kostendeckel je Call für Free-Tier-Requests | 0.001 |
PAID_MIN_QUALITY | bezahlte Requests bevorzugen Provider ab dieser Qualität | 0.8 |
API_KEY_RATE_LIMIT_PER_MINUTE / API_KEY_RATE_LIMIT_MAX | Standard-Limit pro API-Key je Fenster / harter Deckel | 100 / 1000 |
ANON_RATE_LIMIT_PER_MINUTE | Limit pro IP ohne API-Key und ohne X-WALLET | 10 |
RATE_LIMIT_WINDOW_SECONDS | Länge des Sliding Windows | 60 |
API_KEY_ADMIN_SECRET | Wenn gesetzt: X-ADMIN-SECRET nötig für Key-Erzeugung/-Deaktivierung (in Produktion setzen) | leer |
USAGE_RECENT_LIMIT / USAGE_DAILY_TTL_SECONDS | Letzte Requests pro Identität / Aufbewahrung der Tageswerte | 20 / 172800 |
CLOUDFLARE_TUNNEL_TOKEN | Nur für --profile tunnel | leer |
Für Testnet-Betrieb (empfohlen vor Mainnet): PAYMENT_NETWORK=base-sepolia, PAYMENT_NETWORK_CHAIN_ID=84532, FACILITATOR_URL=https://x402.org/facilitator/verify und die Sepolia-Token-Adressen eintragen.
6. API-Endpunkte
GET /health (kostenlos)
curl -s https://api.deine-domain.tld/health | jq
{
"status": "ok",
"version": "0.1.0",
"environment": "production",
"timestamp": "2026-09-10T12:00:00Z",
"uptime_seconds": 86400.2,
"redis_connected": true,
"redis_backend": "redis",
"request_count": 1520,
"error_count": 3,
"error_rate": 0.002,
"cache_hits": 610,
"cache_misses": 900,
"cache_hit_rate": 0.404,
"providers": [
{"name": "apify_web_scraper", "capability": "extract", "healthy": true, "circuit_open": false,
"consecutive_failures": 0, "success_rate": 0.98, "avg_latency_ms": 61.2, "requests": 700}
]
}
status ist ok, degraded (z. B. eine Capability ohne gesunden Provider oder Redis im Memory-Fallback) oder down (HTTP 503, Redis fehlt und ist Pflicht).
POST /extract-clean (0,02 USD)
Request:
curl -s -X POST https://api.deine-domain.tld/extract-clean \
-H 'Content-Type: application/json' \
-H 'X-WALLET: 0xDeineWallet' \
-d '{
"url": "https://shop.example.com/produkt/123",
"schema": {"type":"object","properties":{"title":{},"price":{},"currency":{},"availability":{}}},
"max_age_seconds": 60
}' | jq
Response:
{
"data": {"title": "Shop – Product Overview", "price": 149.9, "currency": "EUR", "availability": "in_stock"},
"sources_checked": 1,
"freshness_seconds": 0,
"confidence": 0.91,
"cost_usdc": 0.02,
"token": "USDC",
"fetched_at": "2026-09-10T12:00:01Z",
"routing": {"provider": "apify_web_scraper", "fallback_used": false,
"providers_tried": ["apify_web_scraper"], "cache_hit": false, "latency_ms": 74}
}
Felder: schema (optional) formt die Ausgabe auf die Top-Level-Properties; max_age_seconds: 0 erzwingt einen frischen Abruf.
POST /market-spread (0,05 USD)
curl -s -X POST https://api.deine-domain.tld/market-spread \
-H 'Content-Type: application/json' \
-H 'X-WALLET: 0xDeineWallet' \
-d '{"asset":"ETH","buy_venue":"binance","sell_venue":"coinbase","size_usd":5000}' | jq
{
"asset": "ETH", "quote": "USDT", "buy_venue": "binance", "sell_venue": "coinbase",
"buy_price": 4247.31, "sell_price": 4258.02,
"gross_spread_bps": 25.2, "fees_bps": 70.0, "slippage_bps": 3.4,
"transfer_cost": 1.31, "transfer_cost_bps": 2.62,
"net_spread_bps": -50.8, "estimated_net_profit_usd": -25.4,
"confidence": 0.86, "execution_risk": "high",
"freshness_seconds": 4, "cost_usdc": 0.05, "token": "USDT",
"fetched_at": "2026-09-10T12:00:02Z",
"routing": {"provider": "coingecko", "fallback_used": false, "providers_tried": ["coingecko"], "cache_hit": false, "latency_ms": 58}
}
net_spread_bps = gross − fees − slippage − transfer_cost_bps. execution_risk berücksichtigt Nettospread, Slippage und Transferzeit. Der Dienst verkauft die Prüfung, nicht den Trade – es gibt keine risikofreie Arbitrage.
Fehlerformat
{"error": "http_error", "detail": "No extraction provider available: ..."}
| Status | Bedeutung |
|---|---|
402 | Zahlung fehlt/ungültig oder Free Tier erschöpft (Body enthält Zahlungsoptionen) |
422 | Validierungsfehler im Request |
502 | Facilitator nicht erreichbar / Provider lieferte unbrauchbare Daten |
401 | X-API-KEY unbekannt oder deaktiviert ({"error": "invalid_api_key"}) |
429 | Rate-Limit überschritten ({"error": "rate_limit_exceeded", "retry_after": …}, Header Retry-After) |
503 | Kein Provider verfügbar oder Mindestmarge verletzt |
6b. Enterprise: API-Keys, Rate-Limiting, Usage & Stats
Alle Endpunkte in diesem Abschnitt sind kostenlos (kein x402). Persistenz komplett in Redis; ohne Redis
(REDIS_REQUIRED=false) greift derselbe In-Memory-Fallback wie beim Cache.
Authentifizierung per API-Key
Ein API-Key (UUID4) ist fest an eine Wallet gebunden. Wird der Header X-API-KEY gesendet, ermittelt der Router
die Wallet automatisch – X-WALLET ist dann nicht mehr nötig. Free Tier und x402-Zahlung gelten unverändert
(der Key ersetzt nur die Identifikation und bringt ein eigenes Rate-Limit mit).
# Key erzeugen (Label und Limit optional; Limit wird auf API_KEY_RATE_LIMIT_MAX gedeckelt)
curl -s -X POST https://<host>/api-keys/generate \
-H 'Content-Type: application/json' \
-d '{"wallet": "0xabc…", "label": "trading-bot-1", "rate_limit_per_minute": 300}'
# → 201 {"api_key": "6f1c…", "wallet": "0xabc…", "label": "trading-bot-1", "rate_limit_per_minute": 300, "active": true, …}
# Verwenden
curl -s -X POST https://<host>/extract-clean -H 'X-API-KEY: 6f1c…' \
-H 'Content-Type: application/json' -d '{"url": "https://example.com"}'
# Key ansehen / deaktivieren (Deaktivierung ist idempotent; Usage-Historie bleibt erhalten)
curl -s https://<host>/api-keys/6f1c…
curl -s -X DELETE https://<host>/api-keys/6f1c…
Ist API_KEY_ADMIN_SECRET gesetzt, verlangen POST /api-keys/generate und DELETE /api-keys/{key} zusätzlich
den Header X-ADMIN-SECRET: <secret> (sonst 403). Ohne Secret kann jeder Keys anlegen – nur für Entwicklung.
Rate-Limiting (Sliding Window, Redis ZSET)
| Aufrufer | Identifikation | Limit | Quelle |
|---|---|---|---|
| API-Key | X-API-KEY | rate_limit_per_minute des Keys (Default API_KEY_RATE_LIMIT_PER_MINUTE = 100) | pro Key |
| Wallet | X-WALLET | Free Tier: FREE_TIER_LIMIT (3) Requests pro Wallet, danach x402 | pro Wallet |
| Anonym | keins | ANON_RATE_LIMIT_PER_MINUTE (10) pro Client-IP | pro IP |
Jede Antwort eines bezahlten Endpunkts (/extract-clean, /market-spread) – auch 402/429 – trägt:
X-RateLimit-Limit: 100 # Limit des Fensters (bei X-WALLET: Free-Tier-Limit)
X-RateLimit-Remaining: 97 # verbleibende Requests im aktuellen Fenster
X-RateLimit-Reset: 1789000000 # Unix-Timestamp, ab dem wieder Kontingent frei wird
Retry-After: 42 # nur bei 429
Das Fenster ist ein echtes Sliding Window (RATE_LIMIT_WINDOW_SECONDS, Default 60 s): jeder Request wird mit
Zeitstempel in ein Redis-ZSET geschrieben, ältere Einträge fallen heraus. Bei Redis-Fehlern öffnet der Limiter
(fail-open) und loggt eine Warnung – zahlende Kunden werden nie wegen eines Cache-Problems blockiert.
Ein 429 verbraucht kein Free-Tier-Kontingent.
Usage-Tracking
Jeder erfolgreiche Request auf einem bezahlten Endpunkt wird pro Identität (wallet:0x… bzw. key:<uuid>)
und global gezählt: Requests (heute/gesamt, bezahlt/frei, Cache-Hits), gezahlte Kosten, Provider-Kosten,
Provider- und Endpunkt-Verteilung sowie die letzten USAGE_RECENT_LIMIT Requests.
curl -s 'https://<host>/usage?wallet=0xabc…' # oder ?api_key=6f1c…
{
"identity_type": "api_key", "wallet": "0xabc…", "api_key": "6f1c…", "label": "trading-bot-1", "api_key_active": true,
"requests_today": 12, "requests_total": 340, "paid_requests_total": 337, "free_requests_total": 3, "cache_hits_total": 41,
"cost_usd_today": 0.24, "cost_usd_total": 6.74,
"providers": {"coingecko": 300, "coinmarketcap": 40}, "endpoints": {"/market-spread": 340},
"free_tier": {"limit": 3, "used": 3, "remaining": 0},
"rate_limit": {"limit": 300, "remaining": 298, "window_seconds": 60, "reset": 1789000060},
"last_request_at": "2026-09-10T10:00:00+00:00",
"last_requests": [{"at": "…", "path": "/market-spread", "provider": "coingecko", "mode": "paid", "token": "USDC",
"price_usd": 0.05, "provider_cost_usd": 0.0, "cache_hit": false, "latency_ms": 412, "status": 200}]
}
Hinweise: Usage per API-Key und per nackter Wallet werden getrennt geführt (der Key ist die Identität), der Free Tier ist jedoch wallet-gebunden und damit geteilt. Anonyme x402-Zahlungen werden der Payer-Wallet aus der Facilitator-Verifikation zugeordnet.
Globale Statistiken
curl -s https://<host>/stats
{
"requests_total": 10234, "requests_today": 311, "paid_requests_total": 9800, "free_requests_total": 434,
"cache_hits_total": 1200, "active_wallets_total": 87, "active_wallets_today": 14, "active_api_keys": 23,
"revenue_usd_total": 312.55, "revenue_usd_today": 9.10, "provider_cost_usd_total": 41.02,
"gross_margin_usd_total": 271.53, "providers": {"coingecko": 7000, "httpx_direct": 2100, "apify_web_scraper": 1134},
"endpoints": {"/market-spread": 7000, "/extract-clean": 3234}, "last_request_at": "…", "generated_at": "…"
}
revenue_usd_* summiert nur tatsächlich per x402 bezahlte Requests; active_wallets_* zählt eindeutige Wallets
(API-Key-Wallets, X-WALLET-Wallets und Payer-Wallets).
7. x402 Payment Flow
1) Agent → POST /extract-clean (ohne X-PAYMENT)
2) Router → 402 Payment Required
{
"x402Version": 1,
"error": "payment_required",
"accepts": [
{"scheme":"exact","network":"base","asset":"0x8335…2913","asset_symbol":"USDC",
"max_amount_required":"20000","pay_to":"0xDeineWallet","resource":"https://…/extract-clean", …},
{"scheme":"exact","network":"base","asset":"0xfde4…9bb2","asset_symbol":"USDT",
"max_amount_required":"20000", …}
],
"facilitator": "https://facilitator.payai.network/verify",
"free_tier": {"limit": 3, "how_to": "Send header X-WALLET: 0x… for free requests"}
}
3) Agent wählt USDC ODER USDT, signiert eine EIP-3009 transferWithAuthorization
(from = Agent, to = pay_to, value ≥ max_amount_required, nonce = zufällig)
4) Agent → POST /extract-clean mit X-PAYMENT: <base64(JSON-Payload)>
optional: X-PAYMENT-TOKEN: USDT (spart einen Verify-Roundtrip)
5) Router: lokale Checks (Netzwerk, Empfänger, Betrag, Replay-Nonce in Redis)
→ Facilitator /verify (erst USDC-Requirements, dann USDT, bzw. gemäß Hint)
6) Router führt Request aus → 200 OK + Daten
7) Router → Facilitator /settle (Transfer wird on-chain ausgeführt)
Ergebnis im Header X-PAYMENT-RESPONSE (base64 JSON: success, transaction, payer)
Free Tier: Header X-WALLET: 0x… gewährt FREE_TIER_LIMIT Requests pro Wallet (Zähler in Redis, 30 Tage). Zusätzlich gilt ein IP-Deckel von 20 Free-Requests/Tag gegen Wallet-Enumeration. Der Header X-Free-Tier-Remaining zeigt den Reststand.
Sicherheit: Nonce-Replay-Schutz (Redis, PAYMENT_REPLAY_TTL_SECONDS), Betrags- und Empfängerprüfung vor dem Facilitator-Call, Secrets erscheinen nie in Logs (Scrubbing im JSON-Logger), Settlement erst nach erfolgreicher Auslieferung – ein fehlgeschlagenes Settlement wird als payment.settlement_failed_after_delivery geloggt.
Beispiel mit dem offiziellen x402-Client (TypeScript):
import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.AGENT_PK as `0x${string}`);
const fetchWithPay = wrapFetchWithPayment(fetch, account);
const res = await fetchWithPay("https://api.deine-domain.tld/market-spread", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ asset: "ETH", buy_venue: "binance", sell_venue: "coinbase" }),
});
console.log(await res.json());
8. Provider hinzufügen
-
Adapter anlegen, z. B.
app/services/providers/firecrawl_provider.py:import httpx from app.models.provider import ProviderResult from app.services.providers.base import BaseProvider, ProviderError class FirecrawlProvider(BaseProvider): @property def is_configured(self) -> bool: return bool(self.api_key) # ohne Key wird der Provider nicht geroutet async def _execute(self, request: dict) -> ProviderResult: r = await self.http.post( # gemeinsamer httpx.AsyncClient aus BaseProvider "https://api.firecrawl.dev/v1/scrape", headers={"Authorization": f"Bearer {self.api_key}"}, json={"url": request["url"], "formats": ["extract"], "extract": {"schema": request.get("schema")}}, ) if r.status_code >= 400: raise ProviderError(self.name, f"HTTP {r.status_code}", retryable=r.status_code >= 500) payload = r.json() return ProviderResult( provider=self.name, data=payload["data"]["extract"], confidence=0.9, sources_checked=1, freshness_seconds=0, ) async def _health_probe(self) -> bool: return bool(self.api_key) # oder ein günstiger Ping-Endpunkt -
In
app/services/providers/__init__.py→build_default_providers()registrieren:FirecrawlProvider( ProviderConfig( name="firecrawl", capability=Capability.EXTRACT, cost_per_request=0.005, # echte Kosten pro Call → fließt in Scoring + Margenprüfung base_quality=0.93, expected_latency_ms=1500, timeout_seconds=15, license=LicensePolicy( allowed_use=["derived_output"], max_cache_seconds=300, commercial_resale=True, contract_expiry=None ), ), api_key=settings.firecrawl_api_key, ) -
Neues Feld in
app/config.pyanlegen (z. B.firecrawl_api_key: str = ""), Key in.envsetzen (FIRECRAWL_API_KEY=...), Tests mit demUpstreamStubaustests/conftest.pyergänzen, deployen.
Der Router übernimmt automatisch: Scoring, Fallback-Reihenfolge, Circuit-Breaker, Tagesbudget, Lizenzprüfung (commercial_resale, contract_expiry) und Cache-TTL-Begrenzung (max_cache_seconds).
Für /market-spread muss data die Felder buy_price, sell_price, buy_fee_bps, sell_fee_bps, buy_liquidity_usd, sell_liquidity_usd, transfer_cost, transfer_minutes liefern (siehe Docstring in defi_provider.py).
9. Tests & Projektstruktur
pip install -r requirements-dev.txt
pytest -q # 80 Tests: kostenlose Exchange-Feeds (Binance/Coinbase/DeFi Llama), Payment (USDC/USDT/Free Tier/Replay), Routing, Circuit-Breaker, Marge, Cache, Spread-Mathematik,
# API-Keys, Sliding-Window-Rate-Limiting, Usage-Tracking, /stats
ruff check .
Tests benötigen keinen laufenden Redis (fakeredis) und keinen echten Facilitator (httpx MockTransport).
agent_margin_router/
├── app/
│ ├── main.py # App-Factory, CORS, Lifespan (Redis connect/disconnect), Metriken
│ ├── config.py # pydantic-settings (.env)
│ ├── routers/ # /extract-clean, /market-spread, /health, enterprise.py (/api-keys, /usage, /stats)
│ ├── middleware/x402.py # API-Key-Auflösung, Rate-Limits, 402-Challenge, Free Tier, Verify/Settle
│ ├── services/
│ │ ├── provider_router.py # Scoring, Fallback, Circuit-Breaker, Mindestmarge, Tagesbudget
│ │ ├── cache.py # redis.asyncio Wrapper, Hit/Miss, Free-Tier-Zähler, Replay-Schutz
│ │ ├── payment.py # x402 Facilitator-Client (USDC + USDT)
│ │ ├── api_keys.py # API-Key-Erzeugung/-Auflösung/-Deaktivierung (Redis)
│ │ ├── rate_limit.py # Sliding-Window-Limiter (Redis ZSET), X-RateLimit-Header
│ │ ├── usage.py # Usage-Tracking pro Wallet/Key + globale Stats
│ │ └── providers/ # base.py, scraping_provider.py, defi_provider.py
│ ├── models/ # Pydantic v2 Request/Response/Provider-Modelle
│ └── utils/logging.py # JSON-Logs mit Secret-Scrubbing
├── tests/
├── docker-compose.yml # app + redis (+ cloudflared via --profile tunnel)
├── Dockerfile # Multi-Stage, non-root, Healthcheck
├── .env.example
├── requirements.txt / requirements-dev.txt / pyproject.toml
└── README.md
Rechtlicher Hinweis: Dieses Projekt ist eine technische Infrastruktur. Provider-Lizenzen, Datenschutz, Steuer- und Zahlungsrecht sind vor dem Produktivbetrieb eigenständig zu prüfen. Es werden keine Umsätze garantiert.
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Paperclip
Freeby Paperclipai · Developer Tools
Trending hip-hop artist momentum scores across four cultural dimensions.
Git
Freeby Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
mcp-creator-python
Freeby mcp-marketplace · Developer Tools
Create, build, and publish Python MCP servers to PyPI — conversationally.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
MarkItDown
Freeby Microsoft · Content & Media
Convert files (PDF, Word, Excel, images, audio) to Markdown for LLM consumption
