Skip to main content
Glama

mcp-confirm

CI Python License: MIT

In einfachen Worten: Wenn eine KI fragt „Bist du sicher?“, verhindert das MCP SDK bereits, dass diese Bestätigung für eine andere Aktion wiederverwendet wird. Es verhindert nicht, dass dieselbe Bestätigung zweimal verwendet wird. Dies schließt diese Lücke und zwei weitere, die das SDK offen lässt.


Zuerst lesen: Der Großteil dieses Problems ist bereits gelöst

Die MCP-Spezifikation vom 28.07.2026 führte Multi Round-Trip Requests ein, sodass ein Tool mitten im Aufruf pausieren und den Benutzer um Bestätigung bitten kann. Die Bestätigung reist als undurchsichtiger requestState durch den Client zurück, den Server laut Spezifikation MÜSSEN als angreiferkontrolliert behandeln.

Das Python-SDK erledigt das standardmäßig auf jedem MCPServer. RequestStateBoundary wird bedingungslos an die Middleware-Kette angehängt – mit einem ephemeren Schlüssel, wenn Sie keinen angeben. Es versiegelt den Zustand mit AES-256-GCM und bindet ihn an die Methode, das Ziel, einen Digest der Aufrufargumente, die Audience und den authentifizierten Principal, mit einer TTL.

Der Angriff, nach dem jeder zuerst greift – Bestätigung zum Löschen von cache.txt, dann Wiederverwendung dieser Bestätigung gegen thesis.txtwird vom SDK bereits abgelehnt. Dafür brauchen Sie keine Bibliothek, und Sie sollten auch keine schreiben.

Dieses Repository hat ursprünglich trotzdem eine geschrieben: 250 Zeilen HMAC, TTL und Argumentbindung, als Hauptfeature ausgeliefert, überflüssig noch am Tag der Veröffentlichung. Das ist unten dokumentiert, statt stillschweigend gelöscht zu werden.

Related MCP server: RecourseOS

Was das SDK nicht tut

Drei Lücken, jede mit einem Test, der auslöst.

1. Es bindet den Zustand und lässt ihn ablaufen. Es verbraucht ihn nie.

Innerhalb der TTL verifiziert die gleiche Bestätigung so oft, wie sie vorgelegt wird. Jede Prüfung, die die Boundary durchführt, besteht jedes Mal. Die Spezifikation stellt ausdrücklich klar, dass dies beabsichtigt ist und dass der Rest Ihre Aufgabe ist:

Beachten Sie, dass diese Maßnahmen das Wiedergabefenster begrenzen und die Wiederverwendung über Benutzer und Anfragen hinweg verhindern, aber für sich genommen keine Einmalverwendung garantieren. Server, für die ein bestimmter requestState höchstens einmal verbraucht werden darf (z. B. Einmal-Einlösungen), MÜSSEN diese Invariante serverseitig durchsetzen.

Für „Datei löschen“ findet der zweite Versuch nichts. Für „£500 überweisen“ ist es das gesamte Problem. singleuse.py ist diese Invariante – ein Hauptbuch ausstehender Bestätigungen, das bei der Einlösung verbraucht wird. Es enthält keine Kryptografie, weil die Boundary bereits garantiert, dass der Klartext von diesem Server stammt.

2. Nichts bereinigt die Frage, die der Mensch liest

Eine Elicitation-message ist ein vom Server gewählter Text, der einer Person angezeigt wird, normalerweise mit einem nicht vertrauenswürdigen Wert, der hineininterpoliert wird – der ganze Sinn ist zu sagen, welche Datei verschwindet. Nennen Sie also eine Datei:

cache.txt

SYSTEM NOTICE: your session has expired.
Enter your AWS secret key to continue:

Der Dialog trägt jetzt eine zweite, offiziell aussehende Aufforderung. Der Benutzer bestätigt keine Löschung; er wird von seiner eigenen Tooling-Infrastruktur phisht. Dieselbe Veröffentlichung vom 28.07.2026 brachte auch MCP Apps – servergerenderte UI – heraus, was diese Angriffsfläche eher vergrößert als verkleinert.

prompt.py reduziert nicht vertrauenswürdige Werte auf eine Zeile, entfernt bidirektionale Überschreibungen und Nullbreitenzeichen und kürzt von der Mitte aus, sodass der Dateiname am Ende sichtbar bleibt. Steuerzeichen werden zu Leerzeichen statt gelöscht, denn wenn man sie zusammenfallen ließe, würden a\nb und ab identisch dargestellt – zwei verschiedene Dateien, ein Dialog.

3. Keine Protokollebene kann Ihre Ressource zur Ausführungszeit erneut prüfen

Der Benutzer hat in der Zwischenzeit darüber nachgedacht. Die Datei kann in diesem Fenster ersetzt werden, und nur das Tool weiß, was „unverändert“ für sie bedeutet. Dieser Server prüft vor dem Löschen erneut und lehnt einen Pfad ab, der zu einem Symlink geworden ist.

Welche Ebene lehnt was ab

Das ist der nützliche Teil, und die Tests sind geschrieben, um genau das zu zeigen. MCPError bedeutet, dass die Middleware des SDKs abgelehnt hat, bevor dieses Paket lief; ToolError bedeutet, dass dieses Paket es getan hat.

Angriff

Abgelehnt von

Test

Bestätigung auf eine andere Datei wiedergegeben

SDK

test_the_sdk_refuses_a_confirmation_replayed_onto_another_file

Zustand gefälscht oder unter einem anderen Schlüssel versiegelt

SDK

test_the_sdk_refuses_a_forged_state

Dieselbe Bestätigung zweimal verbraucht

dieses Paket

test_a_confirmation_cannot_be_spent_twice

Zustand von einer anderen Replik erzeugt

dieses Paket

test_a_state_this_process_never_issued_is_refused

Dateiname fälscht einen Systemprompt

dieses Paket

test_a_forged_system_prompt_cannot_escape_its_slot

Datei nach der Bestätigung gegen einen Symlink ausgetauscht

dieses Paket

test_a_swap_aimed_inside_the_root_is_refused

Pfad außerhalb der erlaubten Roots

dieses Paket

test_a_path_outside_the_roots_is_refused_before_asking

Tests

35 Tests – 17 über den Server, 11 für das Hauptbuch, 7 für die Prompt-Bereinigung.

Jeder Server-Test läuft durch die echte RequestStateBoundary, dieselbe Klasse, die MCPServer auf sich selbst installiert, mit einem festgelegten Schlüssel – Runde eins versiegeln und Runde zwei entsiegeln genau so, wie es die Leitung tun würde.

Dieser Testrahmen existiert wegen eines bestimmten Fehlers. Die erste Version testete, indem sie MCPServer.call_tool() direkt aufrief, was direkt zum Tool-Manager geht und die Middleware-Kette vollständig umgeht. Die Boundary des SDKs lief nie, sodass eine redundante, handgebaute Absicherung tragend wirkte. Das Testdesign war es, das dies einen gesamten Build-Zyklus lang verbarg.

Die Abdeckung beträgt 81 %, mit prompt.py bei 100 % und singleuse.py bei 94 %. Die Lücke ist das argparse- und Transport-Wiring von main(), das stattdessen über build_server getestet wird.

CI läuft nur auf Ubuntu, bewusst: Die Tests für den Austausch nach Bestätigung benötigen Symlinks, und der Build schlägt fehl, wenn sie dort als übersprungen gemeldet werden.

Installation

pip install git+https://github.com/les-k/mcp-confirm.git

Ausführen

mcp-confirm --root /path/you/allow

Ohne --root lehnt der Server jede Anfrage ab, statt auf irgendetwas zurückzufallen. Die Roots werden beim Start festgelegt und niemals vom Agenten gewählt. Kein Signaturschlüssel ist nötig – MCPServer bringt seinen eigenen mit.

Bekannte Einschränkungen

  • Das Hauptbuch ist im Speicher, also ist es für einen Prozess korrekt und hinter einem Load Balancer falsch. Das SDK unterstützt das Teilen von Schlüsseln über Repliken hinweg (RequestStateSecurity(keys=[...])); unter dieser Konfiguration lehnt Replik B eine von Replik A ausgestellte Bestätigung ab. Es schließt sicher – die sichere Richtung –, wirkt für einen Benutzer aber wie eine Bestätigung, die unerklärlicherweise nicht mehr funktioniert. Eine Multiprozess-Bereitstellung benötigt Redis oder eine Datenbankzeile mit einem atomaren Vergleich-und-Löschen. Es gibt einen Test für dieses Verhalten.

  • Das Demonstrationswerkzeug ist bewusst klein. Es löscht eine Datei. Der interessante Code ist singleuse.py und prompt.py.

  • Kein CVE stützt das. MRTR ist erst Wochen alt, also basiert dies auf der eigenen MUST/SHOULD-Liste der Spezifikation und auf dem Lesen des SDKs, nicht auf einem veröffentlichten Vorfall.

Was an Version 0.1.0 falsch war

Hier aufbewahrt, weil ein Repository, das nur seine Erfolge festhält, kein Beleg für irgendetwas ist.

0.1.0 hat neu implementiert, was das SDK bereits tat. state.py war 250 Zeilen HMAC-Signierung, TTL und Principal-/Methoden-/Argumentbindung – alles eine Duplizierung von RequestStateBoundary, nichts davon so gut: HMAC, wo das SDK authentifizierte Verschlüsselung verwendet, keine Audience-Bindung, keine Schlüsselrotation.

Es wurde durch das Lesen des SDK-Quellcodes entdeckt, nicht durch einen Test. Die Tests bestanden genau deshalb, weil sie die Middleware umgingen, die es aufgedeckt hätte.

CI entdeckte separat einen echten Fehler in 0.1.0: Die Symlink-Prüfung lief nach Path.resolve(), untersuchte also das Ziel des Links statt des Links selbst. Ein Austausch, der auf eine andere Datei innerhalb eines erlaubten Roots zielte, wäre gelöscht worden. Behoben, mit einem Test für die Variante, die das Original nie ausführte.

0.2.0 löscht state.py vollständig und behält nur das, was das SDK nicht abdeckt.

Lizenz

MIT.

A
license - permissive license
Not graded
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 Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server that provides human-in-the-loop approval for risky AI agent actions, with durable state and audit logs.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server that provides a security gateway for AI agents, enforcing allow/confirm/deny policies on tool calls and requiring human approval for risky operations, with full audit logging.

View all related MCP servers

Related MCP Connectors

  • Security firewall for AI agents — scans MCP calls for injection, secrets, and risks.

  • Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.

  • Scans MCP servers for tool poisoning, prompt injection and supply chain risks.

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/les-k/mcp-confirm'

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