Skip to main content
Glama
jigonyoo

mcp-permission-server

by jigonyoo

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           0

NAIVE 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 alone
chain:  OK - the chain is intact
replay: 17/17 entries recompute to the verdict they record
secrets in the log: none

Exit-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

fs.read /data/reports-private/salaries.csv

ein anderes Verzeichnis, das mit denselben Zeichen beginnt

Tool ✓ Zweck ✓ Ablauf ✓

fs.read /data/reports/../reports-private/salaries.csv

dasselbe Verzeichnis, erreicht über das gewährte

Tool ✓ Zweck ✓ Ablauf ✓

fs.read /data/reports/q4.csv at t=140

die Gewährung ist vor vierzig Ticks abgelaufen. An dem Aufruf ist nichts falsch

Tool ✓ Geltungsbereich ✓ Zweck ✓

der dritte fs.write gegen eine Gewährung, die für zwei gut ist

eine Gewährung ist ein Budget sowohl als auch eine Berechtigung

Tool ✓ Geltungsbereich ✓ Zweck ✓

fs.read /data/reports/q3.csv für marketing-export

identisch mit dem ersten Aufruf in der Sitzung, außer warum er gemacht wird

Tool ✓ Geltungsbereich ✓ Ablauf ✓

render_template /templates/leak.md

das Template zieht /etc/service-token herein, für das der Aufrufer keine Gewährung hat und das er nie genannt hat

Tool ✓ Geltungsbereich ✓ Zweck ✓ Ablauf ✓

secrets.get DB_ADMIN_PASSWORD

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 nothing

Der 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 record

Bei 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 edited

Geheimnisse 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 unnoticed
python3 ablate.py

Eine 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.

  • purpose wird 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_template parst 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 tests

Ausfü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 tests

Docker, mit ausgeschaltetem Netzwerk:

docker compose run --rm gate

Tests

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.

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
    Policy 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.
    2
    MIT
  • A
    license
    C
    quality
    D
    maintenance
    Enables 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.
    4
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    An 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
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enforces 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

View all related MCP servers

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

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/jigonyoo/mcp-permission-server'

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