Skip to main content
Glama

approval-gate-mcp

Ein MCP-Server, der ein menschliches Genehmigungs-Gate vor einen langlaufenden autonomen Prozess schaltet, plus die betrieblichen Werkzeuge, die man braucht, um tatsächlich mit einem zu leben: Status, Logs, Neustart, Hot-Reload-Parameter und eine Zusammenfassung dessen, was er getan hat.

Erstellt mit FastMCP. Funktioniert mit jedem MCP-Client.

Das Problem

Ein Prozess, der eigenständig handelt, ist nützlich – bis eine seiner Aktionen folgenreich ist. Die üblichen Antworten sind beide schlecht. Schaltet man ihn ab, verliert man alles, was er gut gemacht hat. Lässt man ihn laufen, erfährt man es hinterher.

Das Tor ist eine dritte Option. Der Prozess läuft unbeaufsichtigt weiter, aber wenn er eine Aktion ausführen will, die du als folgenreich markiert hast, schreibt er einen Vorschlag und macht stattdessen weiter. Du prüfst Vorschläge, wann immer du dazu kommst, in welchem MCP-Client auch immer du gerade offen hast, und genehmigst oder lehnst ab. Der Prozess nimmt deine Entscheidung im nächsten Zyklus auf.

Keine Seite blockiert die andere. Es gibt keinen Dienst dazwischen. Der Vertrag besteht aus zwei JSON-Dateien.

  process                            you
     |                                |
     |-- writes proposal ----> pending.json
     |                                |
     |                          list_pending_approvals
     |                          approve(0) / reject(1)
     |                                |
     |<-- reads on next cycle -- approved.json
     |
     |-- acts, appends to records.json

Werkzeuge

Genehmigungs-Gate

Tool

Was es tut

list_pending_approvals

Jeden Vorschlag, der auf eine Entscheidung wartet, mit allen Feldern

approve(index)

Verschiebt einen Vorschlag in die Datei der Genehmigten

reject(index)

Verwirft einen Vorschlag

Prozesssteuerung

Tool

Was es tut

process_status

Läuft oder nicht, PID, Laufzeit, CPU, Speicher, Festplatte, letzte Logzeile

process_logs(lines)

Das Ende der Logdatei anzeigen

restart_process

Neustart über dein Startskript, abgekoppelt, sodass es die SSH-Sitzung überlebt

run_command(cmd)

Notausgang für einmalige Prüfungen

Datensätze

Tool

Was es tut

record_summary(n)

Summen, erledigt gegenüber offen, Aufschlüsselung nach Typ, letzte Einträge

record_dashboard

Breitere Tabellenansicht plus aktuell offene Datensätze und deren Risiko

Parameter – nur registriert, wenn PARAMS_SCHEMA auf dein Manifest zeigt

Tool

Was es tut

list_params

Was diese Bereitstellung als einstellbar deklariert und was gerade überschrieben ist

set_param(name, value)

Schreibt eine Überschreibung, validiert gegen dein Manifest

clear_param(name)

Entfernt eine Überschreibung oder alle

Blockchain – nur registriert, wenn EVM_RPC_URL, WALLET_ADDRESS und TOKEN_CONTRACT gesetzt sind

Tool

Was es tut

wallet_balance

Schreibgeschützter ERC-20- und nativer Kontostand für eine Überwachungsadresse. Es wird nichts signiert

Installation

git clone https://github.com/WillyV347/approval-gate-mcp
cd approval-gate-mcp
pip install -r requirements.txt
cp .env.example .env      # then edit it

Probiere es im Inspector aus, bevor du es in einen Client einbindest:

fastmcp dev server.py

Dann registriere es. Für einen Client, der eine JSON-Konfiguration liest:

{
  "mcpServers": {
    "approval-gate": {
      "command": "python3",
      "args": ["/absolute/path/to/approval-gate-mcp/server.py"],
      "env": {
        "VPS_HOST": "your.host.or.ip",
        "VPS_USER": "your-ssh-user",
        "PROCESS_DIR": "/srv/my-process",
        "PROCESS_MATCH": "my_process.py",
        "PARAMS_SCHEMA": "/absolute/path/to/params.schema.json"
      }
    }
  }
}

Es gibt keine Standardwerte für VPS_HOST, VPS_USER oder PROCESS_DIR. Der Server beendet sich mit einer klaren Meldung, wenn sie fehlen. Ein Überwachungswerkzeug, das stillschweigend auf einen vom Autor eingebauten Host zurückfällt, ist ein Fehler, also weigert sich dieses, zu raten.

Die Authentifizierung erfolgt über deine bestehende SSH-Einrichtung. Der Server ruft die System-ssh-Binärdatei auf, sodass Agenten, Hardware-Schlüssel und Passwortmanager, die einen Agenten bereitstellen, unverändert funktionieren. Er liest selbst nie einen privaten Schlüssel.

Den Vertrag, den dein Prozess implementiert

Du brauchst drei Dinge auf der Prozessseite. Keines davon erfordert eine Bibliothek.

1. Datensätze. An ein JSON-Array anhängen. Vier Schlüssel werden interpretiert, wenn sie vorhanden sind, und alles andere wird unverändert durchgereicht:

[
  {
    "id": "job-1041",
    "record_type": "reindex",
    "resolved": true,
    "outcome": "win",
    "cost": 4.25,
    "result": 11.80,
    "label": "nightly reindex, shard 3"
  }
]

2. Vorschläge. Wenn du im Genehmigungsmodus läufst, schreibe hierhin, anstatt zu handeln:

{
  "proposals": [
    {
      "id": "job-1042",
      "label": "reindex shard 7",
      "action": "reindex",
      "cost": 6.00,
      "created_at": "2026-08-18T22:14:07Z"
    }
  ]
}

Jedes Feld, das du aufnimmst, wird angezeigt. Der Server hat kein Schema für Vorschläge und will auch keins.

3. Die Datei für Genehmigte abfragen. Lies bei jedem Zyklus approved.json, reagiere auf das, was da ist, und leere sie. Ungefähr:

approved = read_json(APPROVED_FILE) or {"proposals": []}
for proposal in approved["proposals"]:
    execute(proposal)
write_json(APPROVED_FILE, {"proposals": []})

Die Reihenfolge ist serverseitig beabsichtigt. Eine Entscheidung entfernt den Vorschlag aus pending.json, bevor in approved.json geschrieben wird. Der Fehlermodus einer halb abgeschlossenen Entscheidung ist also ein verworfener Vorschlag, niemals eine doppelte Aktion.

Parameter und warum es in diesem Repository keine gibt

Hot-Reload ist nur nützlich, wenn der Server weiß, was einstellbar ist. Und die Parameter einer einzelnen Bereitstellung in ein gemeinsames Werkzeug zu codieren, macht es zu einem Einzweck-Werkzeug. Du deklarierst deine also in einem Manifest und weist PARAMS_SCHEMA darauf:

{
  "poll_interval_seconds": { "type": "int",  "description": "Seconds between work cycles" },
  "max_concurrent_jobs":   { "type": "int",  "description": "Jobs in flight at once" },
  "dry_run":               { "type": "bool", "description": "Plan work but do not execute" },
  "approval_mode":         { "type": "bool", "description": "Queue proposals instead of acting" }
}

Unterstützte Typen sind int, float, bool, str, dict und list. set_param wandelt um und validiert dagegen und lehnt alles ab, was sich nicht konvertieren lässt. Ohne Manifest werden die Parameterwerkzeuge einfach nicht registriert, was besser ist, als einen Schreibpfad ohne Prüfung bereitzustellen.

params.schema.json ist in der .gitignore eingetragen, denn deine Abstimmung ist deine Sache. params.schema.example.json wird als Ausgangspunkt mitgeliefert.

Lass deinen Prozess die Überschreibungsdatei beim Start lesen und bei jedem Zyklus, wenn du willst, dass Änderungen ohne Neustart greifen:

overrides = read_json(PARAMS_FILE) or {}
poll_interval = overrides.get("poll_interval_seconds", POLL_INTERVAL_DEFAULT)

Beispielsitzung

> is it running?

  Process RUNNING

  PID:      31882
  Uptime:   14h 22m (51720s)
  CPU:      0.6%
  Memory:   84.3 MB
  Disk:     212M

  Last log: 2026-08-18 22:03:11 cycle complete, 2 proposals queued

> anything waiting on me?

  2 proposal(s) awaiting approval

  --- Proposal #0 ------------------------------
    id:           job-1042
    label:        reindex shard 7
    action:       reindex
    cost:         6.00
    created_at:   2026-08-18T22:14:07Z

  --- Proposal #1 ------------------------------
    id:           job-1043
    label:        reindex shard 12
    action:       reindex
    cost:         6.00
    created_at:   2026-08-18T22:14:07Z

  Use approve(index) or reject(index) to decide.

> approve 0, reject 1

  Approved and queued for execution: reindex shard 7
  Rejected and removed: reindex shard 12

Die Ausgabe oben ist illustrativ.

Hinweise zur Sicherheit

  • run_command führt beliebige Shell-Befehle auf dem entfernten Host aus. Es existiert, weil die Alternative sowieso das Öffnen eines Terminals ist, aber es ist das gefährlichste Werkzeug hier. Beschränke den SSH-Benutzer auf das, was er tatsächlich braucht, anstatt alles als Root auszuführen.

  • wallet_balance ist schreibgeschützt und berührt nie einen Schlüssel. Wenn du es nicht konfigurierst, existiert es nicht.

  • Nichts in diesem Repository speichert Anmeldedaten. RPC-URLs tragen Anbieterschlüssel im Pfad. Bewahre EVM_RPC_URL also in der Umgebung und außerhalb deiner Konfigurationsdateien auf.

  • StrictHostKeyChecking ist auf accept-new gesetzt: Unbekannte Hosts werden bei der ersten Verbindung vertraut, geänderte Hostschlüssel schlagen weiterhin fehl. Setze es auf yes und befüllle known_hosts vorab, wenn du das strengere Verhalten willst.

Lizenz

MIT

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.

  • A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready

  • A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r

View all MCP Connectors

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/WillyV347/approval-gate-mcp'

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