Skip to main content
Glama

MARL Cop & Thief – Duale KI-Agenten über MCP

Ein dezentrales, teilweise beobachtbares Verfolgungsspiel zwischen zwei autonomen KI-Agenten – dem Cop und dem Thief – die in freier natürlicher Sprache über MCP-Server kommunizieren, ihre Züge mit einer spieltheoretischen Minimax- + Self-Play-RL-Engine entscheiden, live in einem Web-Kontrollpanel darstellen und einen gemeinsam vereinbarten JSON-Matchbericht über die Gmail-API per E-Mail versenden.

Universität Haifa · Orchestrierung von KI-Agenten (ex06) · Dr. Yoram Segal. Ein Befehl startet alles; ein Browser-Tab führt ein komplettes Match aus.


Highlights

  • Ein-Befehl-Knotenpython -m cop_thief.app startet beide MCP-Server, die öffentlichen Cloudflare- Tunnel und ein Browser-Kontrollpanel gemeinsam (keine verwaisten Tunnel, kein Port-Gewirr).

  • Web-Kontrollpanel – Live-Knotenstatus, kopierfertige öffentliche URLs/Tokens, ein Herausforderungs- formular für Gegner, ein Mirror-Selbsttest per Klick und ein Live-5×5-Spiel-TV – alles unter http://127.0.0.1:8800.

  • Echte Strategie – eine Angel–Devil-Minimax-Engine (Nullsummen-Markov-Spiel, Alpha-Beta) mit dem Conway-Blockierspiel (Cop = Devil-Wände, §4.3) und Self-Play-RL-Gewichtslernen, weit über die Basis-Q-Tabelle der Aufgabe hinaus. Siehe docs/STRATEGY.md.

  • Dezentral & manipulationsresistent – kein Schiedsrichter; beide Seiten hashen das Ergebnis (SHA-256) und jede Uneinigkeit ergibt 0/0. Eingehende Prosa wird als feindlich behandelt: Prompt-Injection / Nötigung wird gefiltert, als Beweis protokolliert und kann das Ergebnis nicht ändern (es gibt keine Forfeit-Aktion).

  • Einzelne SDK-Grenze + API-Gatekeeper – alle Logik hinter CopThiefSDK; jeder externe Aufruf (LLM, Gmail) läuft durch einen FIFO-backpressure-Gatekeeper mit DeepSeek→Anthropic-Failover.

  • Qualitätsgatespytest ≥ 85 % Abdeckung, null Verstöße bei ruff, ≤ 150 Zeilen/Datei, nur uv.


Related MCP server: Police MCP Server

Schnellstart

uv sync                                   # install (uv is the ONLY package manager)
cp .env-example .env                      # fill in real values (see "Secrets")
uv run ruff check .                       # zero-violation lint gate
uv run pytest                             # full suite (>=85% coverage gate)
uv run python -m cop_thief.app            # launch the control panel + servers + tunnels

Dann öffne http://127.0.0.1:8800.


Ein Match spielen (Kontrollpanel)

  1. uv run python -m cop_thief.app → das Panel öffnet sich; warte, bis Server ● und Tunnel ● grün sind.

  2. Die Statuskarte zeigt deine beiden öffentlichen …/mcp/-URLs + Rollen-Tokens (Kopier-Buttons). Sende diese an deinen Gegner zusammen mit docs/INTER_GROUP_TREATY_SPEC.md. Verwende die Ausfüllformulare in match_setup/ (RULES.txt, OUR_DETAILS, OPPONENT_DETAILS).

  3. Füge die beiden …/mcp/-URLs des Gegners (und ggf. Tokens) in das Herausforderungsformular ein, dann START CHALLENGE – die 6 Sub-Spiele laufen cross-host auf dem TV und der Bericht wird per E-Mail gesendet.

  4. Noch kein Partner? Klicke MIRROR SELF-TEST ⟳ – es füllt deine eigenen localhost-Endpunkte + Tokens aus und spielt dich gegen dich selbst (ideal zum Testen der Strategie).

Ein Spiel = 6 Sub-Spiele (gemäß §4.1): Wir spielen Cop in 3 (Heimspiel) und Thief in 3 (Auswärtsspiel), Thief zuerst, ≤ 25 Züge jeweils. Die Wertung ist unveränderlich: Cop-Fang → 20 / 5; Thief überlebt → 5 / 10.


Screenshots

Das Kontrollpanel – Knotenstatus (Server/Tunnel/Spiel), unsere teilbaren …/mcp/-URLs + Tokens mit Kopier-Buttons, das Herausforderungsformular für Gegner und das Live-Spiel. Hier läuft ein Mirror-Selbsttest; beachte die [INTENT: BARRIER]-Zeile (der Cop blockiert eine angrenzende Zelle und bleibt stehen, §4.3), die grüne B-Barriere und das !-Einfangen.

Kontrollpanel

Live-Brett – das 5×5-Raster mit dem Cop C (blau) und dem Thief T (rot), neben dem Kommunikations-Abfang- Feed, der die natürlichen Sprach-[INTENT: MOVE]-Übertragungen und die HEIMSPIEL / Sub-Spiel-Trenner zeigt.

Live-Brett

Leg-Übergang – der Läufer wechselt in das AUSWÄRTSSPIEL (wir spielen Thief) bei Sub-Spiel 4/6, mit einer B- Barriere und !-Einfang noch auf dem Brett.

Auswärtsspiel und Barriere

Beim Starten des Knotens werden die teilbaren Endpunkte im Terminal ausgegeben (ein Prozess: Server + Tunnel + Panel):

Control panel  >  http://127.0.0.1:8800   (open in a browser)
╔══════════════════════════════════════════════════════════════════╗
║ LIVE PUBLIC MATRIX (Team Alpha)                                   ║
╠══════════════════════════════════════════════════════════════════╣
║ COP   (:8001)  https://acting-tomorrow-yard-raid.trycloudflare.com/mcp/   ║
║ THIEF (:8002)  https://dial-mean-courses-tramadol.trycloudflare.com/mcp/  ║
╚══════════════════════════════════════════════════════════════════╝
Tunnels live and written to config/setup.json. Share these /mcp/ URLs. Ctrl+C to stop.

Architektur

Ebene

Modul

Verantwortung

Domäne

domain/

Unveränderlicher DecPomdpGameState, Grid, Geometrie, NL-Zugsprache ([INTENT: …]).

Strategie

domain/strategy/

minimax (Alpha-Beta), evaluation/features (Angel–Devil), selfplay (RL), Q-Tabellen-Basislinie.

SDK

sdk/

CopThiefSDK als einziger Einstiegspunkt; MatchCoordinator für Terminal-/Trap-Death-Logik; Warfare-/Injection-Screen.

Gatekeeper

infra/gatekeeper/

FIFO-Engpass für alle LLM-/Gmail-Aufrufe; DeepSeek→Anthropic-Failover; Token-Telemetrie.

Server

servers/

Cop- & Thief-FastMCP-Server; Token-Auth; request_move-Tool → StrategyResolver.

Transport

infra/network/

Streamable-HTTP-/mcp-Host, RemoteMoveClient, Cloudflare-Schaltzentrale.

Orchestrierung

orchestrator/

ChallengeRunner (cross-host, pro Leg), reconcile (gegenseitige Übereinkunft / 0-0), Serie.

UI

ui/

Kontrollpanel-Backend (server.py), NodeState, Broadcast-SSE-Bus, static/panel.html.

Berichterstattung

reporting/

Gmail-OAuth-Reporter (Gruppenname in Betreff + Text), append-only Audit-Log, Sicherheitswächter.

Einstiegspunkte

Befehl

Was es tut

python -m cop_thief.app

Kontrollpanel: Server + Tunnel + Web-UI (das Hauptpanel).

python -m cop_thief.challenge

Interaktive Terminal-Herausforderung über Hosts (fragt nach Gegner-URLs).

python -m cop_thief.serve

Nur Server + Tunnel (kein UI).

python -m cop_thief.infra.network.dual_mcp_host

Nur die beiden MCP-Server (:8001/:8002 /mcp).

python -m cop_thief.diagnostic_runner

Offline-, kostenloser Verfolgungsprobe (gemocktes LLM).


Strategie in einem Absatz

Jede request_move wird durch tiefenbegrenztes Alpha-Beta-Minimax über das Nullsummen-Markov-Spiel beantwortet (Cop maximiert, Thief minimiert, Annahme eines optimalen Gegners). Fortschrittsgeformte Terminal- Werte (±WIN ∓ turns) drängen die Politik zu Fang/Überleben, sodass Unentschieden strukturell vermieden werden. Die Aktionsmenge des Cops umfasst das Blockieren einer angrenzenden Zelle (Conway-„Devil“-Zug, §4.3); das Containment-Feature der Bewertung ist die flutgefüllte Fluchtregion des Thiefs, sodass der Planer legale Herden-in-die-Falle-Linien selbst entdeckt. Die linearen Bewertungsgewichte sind durch Self-Play-TD (selfplay.train_weights) einstellbar. Drei Variantenprofile (aggressiv / ausgewogen / defensiv) stellen den geforderten 3-Agenten-Kader. Vollständiges Design: docs/STRATEGY.md.


Formales Modell – Dec-POMDP

Die Verfolgung wird als dezentraler, teilweise beobachtbarer Markov-Entscheidungsprozess modelliert, das Tupel ⟨ n, S, {Aᵢ}, P, R, {Ωᵢ}, O, γ ⟩ (ex06 §11):

Symbol

Bedeutung

In diesem Projekt

n

Agenten

2 – Cop und Thief (unabhängig, kein gemeinsamer Speicher).

S

Zustandsraum

DecPomdpGameState: cop_pos, thief_pos ∈ 5×5-Raster, die Menge der barriers ⊆ G (≤ 5), cop_barriers_left, turn_counter, turn_role. Der gemeinsame Positionsraum ist begrenzt durch (R·C)² = 625; mit Barrieren ist der erreichbare Raum größer, aber endlich.

Aᵢ

Aktionen pro Agent

Cop: 8 Königszüge (Chebyshev ≤ 1) ∪ Barriere auf einer angrenzenden freien Zelle platzieren (stehen bleiben) ∪ HOLD. Thief: 8 Königszüge ∪ HOLD. „Stehen“ ist ein entarteter Zug.

P

Übergang

Deterministische Brett-Zustandsmaschine (apply_action): eine Mutation pro Zug; illegale Züge (außerhalb des Bretts / auf eine Barriere / kein Königszug) werden abgelehnt; ein Barrierenzug blockiert die benannte angrenzende Zelle und der Cop bleibt stehen.

R

Belohnung

Unveränderliche Tabelle 1: Fang → Cop +20 / Thief +5; Ausweichen → Cop +5 / Thief +10. Der Planer verwendet fortschrittsgeformte Terminal-Werte (±WIN ∓ turns), sodass das Spiel strikt entscheidend ist (keine Unentschieden).

Ωᵢ

Beobachtungsraum

Eine subjektive Sicht pro Agent: exakte Gegnerkoordinaten genau dann, wenn innerhalb des Sichtradius, sonst ein qualitativer Okklusions-Sektor (z. B. THIEF_IN_NORTHWEST_QUADRANT).

O

Beobachtungsfunktion

get_subjective_observation(role, radius) – zeigt den Gegner, wenn die Manhattan-Distanz ≤ vision.radius (Standard 2), sonst nur den Quadranten. Symmetrisch für beide Rollen (Nebel des Krieges).

γ

Diskont

rl.gamma = 0.9 für das Self-Play-TD / Q-Baseline; die Minimax-Schicht verwendet stattdessen fortgeschrittsgeformte Terminal-Werte, um auf Fang/Überleben zu drängen.

Teilweise Beobachtbarkeit ist real: Jeder Agent entscheidet aus seiner Überzeugung des Bretts (seiner letzten Beobachtung + geparster Gegnerprosa), niemals aus globaler Ground-Truth.

Orchestrierungs-Herausforderungen (der schwierige Teil)

Gemäß ex06 §14 liegt der Wert der Aufgabe in der Orchestrierung, nicht im Sieg. Die schwierigen Probleme und wie wir sie lösen:

  • Freie natürliche Sprache, kein vordefiniertes Protokoll. Agenten kommunizieren in Prosa. Wir legen einen dünnen deterministischen Vertrag darüber – jede Nachricht beginnt mit genau einem Wegweiser [INTENT: MOVE|BARRIER|HOLD], gefolgt von einem Kompasswort – dadurch ist der Zug maschinell auflösbar, während der Textkörper frei in natürlicher Sprache bleibt. Das hält zwei unabhängig entwickelte Engines ohne gemeinsame Codebasis synchron.

  • Linguistische Mehrdeutigkeit & nicht vertrauenswürdige Eingaben. Eingehende Prosa wird deterministisch geparst (Richtungswort nach dem Longest-Match-Prinzip, Intent nur in eckigen Klammern, sodass Flavour-Text ihn nicht vortäuschen kann) mit einem optionalen LLM-Parse für unstrukturierten Gegnertext; bei geringem Vertrauen → ein sicherer explorativer Fallback (stürzt nie ab, fälscht nie eine Eroberung). Jedes Feld wird als feindlich behandelt – z. B. wird ein nicht-numerisches variant umgewandelt, nie vertraut.

  • Gegenseitiges Verständnis sicherstellen. Beide Peers teilen eine deterministische Zugsprache (Kodieren/Parsen ohne LLM), sodass ein Spiel byte-reproduzierbar ist. Am Ende hashen beide Seiten die kanonischen sub_games (SHA-256, K3); jede Abweichung ⇒ 0/0 für beide – Übereinstimmung wird erzwungen, nicht vorausgesetzt.

  • Lebendigkeit über ein unzuverlässiges Netzwerk. Züge zwischen Hosts werden mit Wiederverbindung wiederholt; eine anhaltende Störung oder ein eingefrorener Peer (Timeout von 20 s pro Zug) verwirkt dieses Teilspiel, sodass die Serie immer alle 6 abschließt und der Bericht weiterhin per E-Mail gesendet wird – ein toter Gegner kann das Match nie aufhalten.

Visualisierung & schlüssige Beweise (§11)

  • GUI – die Screenshots oben zeigen das Live-5×5-Spielfeld, den [INTENT: …]-Kommunikationsabfang-Feed, Barrieren (B), Eroberungen (!) und Phasenübergänge.

  • Cloud-MCP-Kommunikation – der Boot-Block oben gibt die live erreichbaren öffentlichen Cloudflare-/mcp/-URLs aus, und der Kommunikations-Feed des Panels streamt die echten [INTENT:]-Übertragungen, die mit den Cloud-Servern ausgetauscht werden; jeder Zug wird zusätzlich an data/game_audit.jsonl angehängt und in einem manipulationssicheren Archiv pro Spiel versiegelt (data/archive/, Bundle-SHA-256 im Bericht).

  • Lernen – Strategiegewichte werden durch Self-Play-TD (selfplay.train_weights) optimiert; eine tabellarische Q-learning-Basislinie bleibt zum Vergleich erhalten. Design + Kurven: docs/STRATEGY.md.

Sicherheit & faires Spiel

  • Tokens – jeder MCP-Toolaufruf erfordert ein pro Rolle widerrufbares Bearer-Token; out-of-band ausgetauscht, rotierbar zum Widerruf. Server sind fail-closed.

  • Anti-Injection – eingehende Übertragungen sind nicht vertrauenswürdig; Injection/Coercion/Impersonation/Fälschung werden geprüft, in data/game_audit.jsonl als hostile:true markiert, im Bericht gezählt und haben keine Auswirkung auf das von der Engine ermittelte Ergebnis. Im Vertrag für Gegner festgeschrieben (§F).

  • Gegenseitige Übereinkunft – beide Seiten hashen die kanonischen sub_games; jede Abweichung ⇒ 0/0 (both_lose).

  • Berichterstattung – Gmail-API über OAuth2-Desktop (Scope gmail.modify, keine Passwörter); der Gruppenname steht sowohl in der Betreffzeile als auch im JSON-Body; eine Sicherheitsvorkehrung greift standardmäßig auf das Wegwerf-Postfach zurück.


Token-Budget & Kosten

Jeder externe Aufruf wird über den API GatekeeperTokenTracker abgerechnet, der die Live-Nutzung an data/token_usage.json streamt (atomarer Schreibvorgang; vom K3-Vereinbarungs-Hash ausgeschlossen, sodass Kosten nie das Ergebnis beeinflussen). Alle Zahlen sind konfigurationsgesteuert (config/setup.json → token_budget / economics).

Anbieter (Rolle)

Eingabe $/M

Ausgabe $/M

DeepSeek deepseek-chat (primär)

0.15

0.60

Anthropic claude-3-5-sonnet (nur Failover)

3.00

15.00

Budgetposten

Wert

Tatsächliche Ausgaben bisher (alle Läufe zusammen)

≈ $0.01

Lebenszyklus-Budget

200,000 Eingabe- + 50,000 Ausgabe-Tokens

→ voraussichtliche Lebenszykluskosten (primär)

~$0.06

Schätzung pro Zug (120 rein / 40 raus)

~$0.00004

Harte Obergrenze (Warnung bei 80 %)

$0.50 (Warnung bei $0.40)

Durchsetzung

Gatekeeper gibt für abrechenbare LLM-Aufrufe an der Obergrenze BudgetExceeded zurück – stürzt nie ab

In der Praxis hat das gesamte Projekt ≈ $0.01 für LLMs gekostet. Die Züge stammen von der lokalen Minimax-Engine, und die Zugsprache ist deterministisches [INTENT: …]-Kodieren/Parsen – es wird kein LLM benötigt, um zu spielen oder den Bericht zu senden (Gmail-API, kein LLM). Das winzige Budget + das DeepSeek-First-Failover sind Schutzmaßnahmen für optionales LLM-gestütztes Parsen natürlicher Sprache; die Obergrenze liegt bei $0.50 mit reichlich Spielraum.

Geheimnisse & Konfiguration

  • Kopieren Sie .env-example.env und füllen Sie aus: DEEPSEEK_API_KEY, ANTHROPIC_API_KEY, COP_MCP_TOKEN, THIEF_MCP_TOKEN, GMAIL_CREDENTIALS_PATH. Ein Autoloader ohne Abhängigkeiten injiziert .env beim Start – kein export/source nötig; vorhandene Shell-Exports haben immer Vorrang.

  • Alle einstellbaren Parameter liegen in versionierten config/*.json (kein Hardcoding). Geheimnisse (.env, credentials.json, token.json) sind git-ignoriert und gelangen nie in die Versionskontrolle.

Dokumentation

PRD · PLAN · TODO · STRATEGY · RULES_AND_AGREEMENTS · INTER_GROUP_TREATY_SPEC

Lizenz

MIT.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

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/najikay/mcp-marl-pursuit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server