mcp-permission-server
mcp-permission-server
Eine Berechtigungsebene vor MCP-Tools und ein Log, das beweisen kann, was es entschieden hat.
Jeder Audit-Trail zeichnet auf, was passiert ist. Fast keiner zeichnet genug auf, um neu zu berechnen, warum es erlaubt wurde, und die meisten zeichnen nur auf, was erfolgreich war – wenn also jemand fragt: „Wie hat der Agent diese Datei erreicht?“, kann das Log keine Antwort geben. Es kann nur die Behauptung wiederholen, dass eine Entscheidung getroffen wurde.
NAIVE GUARDED
calls in the session 17 17
calls that must be denied 8 8
EXECUTED WITHOUT A GRANT 7 0
LEGITIMATE CALLS REFUSED 0 0 ← no over-blocking
DECISIONS THAT CANNOT BE 16 0 ← the number nobody reports
RECONSTRUCTED FROM THE LOG
denials that left no trace 1 0
secrets sitting in the log 2 0
entry removable unnoticed 1 0NAIVE ist das Berechtigungsmodell, das ein MCP-Server mitbringt, wenn Berechtigungen nicht der Punkt waren: eine Liste von Toolnamen, die erlaubt sind, und ein Log dessen, was erfolgreich war. Jeder Aufruf in dieser Sitzung bis auf einen besteht es.
python3 demo.py
python3 gate.py --log audit.json # run the session
python3 gate.py --verify audit.json # re-decide every entry from the log alonechain: OK - the chain is intact
replay: 17/17 entries recompute to the verdict they record
secrets in the log: noneExit-Code: 0 alles erlaubt, 1 etwas verweigert, 2 das Log verifiziert nicht.
Eine Gewährung ist vier Dinge zugleich
Das sind vier getrennte Arten, wie eine aktive Gewährung einen Aufruf immer noch nicht abdecken kann – und der Grund, warum „Hat dieser Aufrufer eine Berechtigung für dieses Tool?“ die falsche Frage ist.
{"id": "G1", "tool": "fs.read", "scope": "/data/reports",
"purpose": "q3-report", "expires_at": 100, "max_uses": 10}der Aufruf | was daran falsch ist | was es sonst erlaubt hätte |
| ein anderes Verzeichnis, das mit denselben Zeichen beginnt | Tool ✓ Zweck ✓ Ablauf ✓ |
| dasselbe Verzeichnis, erreicht über das gewährte | Tool ✓ Zweck ✓ Ablauf ✓ |
| die Gewährung ist vor vierzig Ticks abgelaufen. An dem Aufruf ist nichts falsch | Tool ✓ Geltungsbereich ✓ Zweck ✓ |
der dritte | eine Gewährung ist ein Budget sowohl als auch eine Berechtigung | Tool ✓ Geltungsbereich ✓ Zweck ✓ |
| identisch mit dem ersten Aufruf in der Sitzung, außer warum er gemacht wird | Tool ✓ Geltungsbereich ✓ Ablauf ✓ |
| das Template zieht | Tool ✓ Geltungsbereich ✓ Zweck ✓ Ablauf ✓ |
| eine Gewährung für einen Schlüssel zu halten ist nicht dasselbe wie den Schlüsselbund zu halten | Tool ✓ Zweck ✓ Ablauf ✓ |
Es gibt einen Test, der für jeden dieser Fälle nur die genannte Prüfung abschaltet und verlangt, dass der Aufruf durchkommt. Eine Verweigerung, die mehrere Prüfungen abfangen, ist eine Verweigerung, die nichts über eine von ihnen beweist.
Related MCP server: MCP Airlock
Der verwirrte Stellvertreter
render_template ist gewährt. /templates/leak.md liegt innerhalb des gewährten Geltungsbereichs. Das Template enthält {{include:/etc/service-token}}.
Der Server besitzt Rechte, die der Aufrufer nicht hat, und wird gebeten, sie für eine Ressource auszugeben, die der Aufrufer nie genannt hat. Eine Berechtigungsebene, die die Ressource in den Argumenten prüft, prüft genau bei den Tools das Falsche, wo es darauf ankommt.
Die Prüfung schaut also darauf, was ein Aufruf erreicht, bevor er es erreicht – und sagt dann trotzdem Ja zu /templates/report.md, das /data/reports/q3.csv erreicht, wofür dieser Aufrufer tatsächlich eine Gewährung besitzt. Die Hälfte einer Berechtigungsprüfung ist das Ja. Eine Regel, die jedes Template blockiert, weil Templates Dinge einbinden können, ist keine Regel.
Pfad-Eindämmung, wo das normalerweise falsch gemacht wird
Beide Fehler sind eine Zeile lang.
path.startswith(scope) # /data/reports-private is "inside" /data/reports
".." in path # and this breaks ordinary callers to catch nothingDer zweite verdient einen eigenen Fall. /data/reports/../reports/q3.csv löst sich zurück innerhalb des gewährten Geltungsbereichs auf und ist im Korpus als ein Aufruf enthalten, der erlaubt werden muss. Die Zeichen zu verbieten ist der billige Fix; den Pfad aufzulösen fängt alles, was das Verbot fangen würde, und nichts, was es nicht täte.
Die Auflösung ist hier lexikalisch und berührt nie ein Dateisystem – es gibt einen Test, der nach realpath, os.stat und open( grept. Die Entscheidung läuft vor dem Aufruf, auf einem Pfad, den der Aufrufer geliefert hat, und sie darf nicht unterschiedlich beantwortbar sein, je nachdem, was zufällig existiert.
Das Log ist das Produkt
Zwei Eigenschaften machen es zu einem Beweisstück statt zu einem Tagebuch.
Es zeichnet Verweigerungen auf. Ein Log dessen, was erfolgreich war, kann nicht beantworten, „was der Agent versucht hat“, was die Frage ist, die hinterher tatsächlich jeder stellt. Hier sind acht der siebzehn Einträge Ablehnungen, jeweils mit der Prüfung, die sie verursacht hat, und dem Grund in einfacher Sprache.
Es kann wiedergegeben werden. Jeder Eintrag trägt die Gewährung, unter der entschieden wurde, und die Richtlinienversion, sodass die Entscheidung allein aus dem Log neu berechnet und mit dem Urteil verglichen werden kann, das es aufzeichnet:
python3 gate.py --verify audit.json
replay: 17/17 entries recompute to the verdict they recordBei deaktiviertem replay-Feld ist diese Zahl 0/17 – die Einträge sagen immer noch, was entschieden wurde, und geben niemandem eine Möglichkeit, es zu überprüfen.
Und die Einträge sind hash-verkettet, sodass ein entfernter oder bearbeiteter sichtbar ist:
entry 6 does not follow the one before it -- something was removed or editedGeheimnisse gelangen nie hinein. Ein Audit-Trail, der das Geheimnis enthält, ist eine zweite Kopie des Geheimnisses in einer Datei, die mehr Menschen lesen können. secrets.get ist in dieser Sitzung erlaubt, und sein Wert erscheint nirgends im Log; das naive Log enthält zwei.
Die neun Prüfungen und der Beweis, dass jede ihren Platz verdient
check what turning it off lets through
grant 1 more unauthorised, 1 more unreconstructable, 1 more egress
scope 3 more unauthorised, 3 more unreconstructable
expiry 2 more unauthorised, 2 more unreconstructable
purpose 1 more unauthorised, 1 more unreconstructable
deputy 1 more unauthorised, 1 more unreconstructable
redact 1 more secret in the log
deny_log 8 more denials that left no trace
replay 17 more decisions that cannot be reconstructed
chain 1 more entry removable unnoticedpython3 ablate.pyEine Korrektur, die festgehalten zu werden verdient: Die erste Version der scope-Ablation schaltete die Prüfung nicht ab – sie ersetzte sie durch den String-Präfix-Vergleich, was eine andere Prüfung ist und nicht das Fehlen einer solchen, und sie verweigerte stillschweigend weiterhin einen Aufruf, der dazu da war zu beweisen, dass die Prüfung nötig ist. Eine Prüfung abzuschalten muss bedeuten, sie abzuschalten, sonst misst die Ablation einen Tausch.
Dieselbe Sitzung legte auch eine Gewährung offen, die so bemessen war, dass ihr letzter Aufruf verweigert wurde, weil er eine Nutzung zu viel war, statt weil er einen Schlüssel nannte, den sie nicht abdeckte. Sie testete die falsche Prüfung und bestand. Der Fix lag in der Fixture, und der Test, der es fand, ist der, der verlangt, dass jede Verweigerung ihre eigene Prüfung isoliert.
Bekannte Grenzen, ausgesprochen statt versteckt
Dies ist die Entscheidungsebene, kein Transport. Sie entscheidet, führt gegen eine prozessinterne Tool-Tabelle aus und protokolliert. Sie an einen echten MCP-Transport anzuschließen ist gewöhnliche Arbeit; was hier ist, ist der Teil, der normalerweise fehlt, und es läuft ohne Netzwerk und ohne Schlüssel.
Gewährungen werden aufgeschrieben, nicht abgefragt. Eine echte Bereitstellung fragt eine Person und speichert die Antwort. Was diese Antwort enthalten muss – Tool, Geltungsbereich, Zweck, Ablauf, Nutzungsanzahl – ist der Teil, um den es hier geht.
purposewird vom Aufrufer deklariert und für bare Münze genommen. Ein Aufrufer, der über seinen Zweck lügt, umgeht die Prüfung. Es bringt trotzdem etwas Reales: Der deklarierte Zweck steht im Log, also ist die Lüge aktenkundig, und der Geltungsbereich der Gewährung hat sich nicht erweitert, um sie aufzunehmen.Die Deputy-Prüfung kennt die Reichweite eines Tools.
render_templateparst seine Includes. Ein Tool, dessen Reichweite der Server nicht berechnen kann, kann auf diese Weise nicht geprüft werden, und die ehrliche Antwort für ein solches Tool ist eine engere Gewährung statt einer weiteren Prüfung.Die Kette beweist Reihenfolge und Integrität, nicht Verwahrung. Jeder, der die gesamte Datei neu schreiben kann, kann die gesamte Kette neu schreiben. Sie macht eine selektive Bearbeitung sichtbar, was die realistische Bedrohung ist; ein Append-only-Speicher oder ein externer Anker macht den Rest sichtbar, und das ist Bereitstellungsarbeit.
Aufbau
fixtures/spec.py the session, the grants, the world, and the answer key
build_fixtures.py renders session.json, policy.json, world.json, truth.json
mcpgate/scope.py is this path inside that scope
mcpgate/policy.py a grant is four things at once
mcpgate/tools.py the tool table, and what a call actually reaches
mcpgate/audit.py the hash-chained, redacted, replayable log
mcpgate/server.py naive() and guarded(), and replay()
gate.py the CLI: run a session, or verify a log
score.py every number above
ablate.py each check off, one at a time
tests/ 38 testsAusführen
python3 demo.py # both servers + ablation
python3 gate.py --log audit.json # the product
python3 gate.py --verify audit.json # the proof
python3 -m pytest tests -q # 38 testsDocker, mit ausgeschaltetem Netzwerk:
docker compose run --rm gateTests
Einer stellt fest, dass die Allowlist weiterhin fast alles durchlässt. Einer spielt jede protokollierte Entscheidung erneut ab und verlangt dasselbe Urteil. Einer verlangt, dass jede Verweigerung nur wegen der genannten Prüfung überlebt, damit die Ablationszahlen das bedeuten, was sie sagen. Einer grept den Pfadauflöser nach Dateisystemaufrufen.
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 gradedqualityCmaintenancePolicy enforcement gateway for MCP tool calls, evaluating every tool invocation against declarative YAML policies (allow/deny/escalate-to-human), generating cryptographic hash-chained audit receipts, and including built-in content safety scanning.2MIT- AlicenseCqualityDmaintenanceEnables secure, zero-trust access to MCP tools through short-lived, signed capability leases that bind tool execution to specific sessions, intents, and constraints. Prevents prompt injection attacks and privilege escalation with dynamic risk scoring, policy enforcement, and tamper-evident audit logging.41MIT
- AlicenseNot gradedqualityAmaintenanceAn authorizing reverse proxy for MCP servers that enforces per-call policy rules on tool arguments with audit logging, dry-run, and rate limiting.Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnforces identity-based access control and audit logging for MCP servers, letting you grant fine-grained tool permissions to users and systems while failing secure by default.MIT
Related MCP Connectors
Remote MCP for A2A caller identity, scope policy, verdict receipts, and audit history.
Runtime permission, approval, and audit layer for AI agent tool execution.
Remote MCP for Copilot CLI switch gate MCP, structured receipts, audit logs, and reviewer-ready evid
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/jigonyoo/mcp-permission-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server