mcp-permission-server
mcp-permission-server
MCP 도구 앞에 놓이는 권한 계층, 그리고 자신이 내린 결정을 증명할 수 있는 로그.
모든 감사 추적(audit trail)은 무슨 일이 일어났는지 기록한다. 그러나 왜 허용되었는지를 다시 계산할 수 있을 만큼 충분히 기록하는 경우는 거의 없고, 대부분 성공한 것만 기록한다. 그래서 누군가 "에이전트가 어떻게 그 파일에 도달했는가"라고 물으면 로그는 답할 수 없다. 결정이 내려졌다는 주장을 반복할 수 있을 뿐이다.
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는 권한이 핵심이 아니었을 때 MCP 서버가 기본으로 갖는 권한 모델이다: 허용된 도구 이름 목록과 성공한 것들의 로그. 이 세션의 모든 호출 중 하나를 제외하고는 모두 이 모델을 통과한다.
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: none종료 코드: 0 모두 허용됨, 1 무언가 거부됨, 2 로그가 검증되지 않음.
허가(grant)는 동시에 네 가지다
이는 살아 있는 허가가 여전히 호출을 커버하지 못하는 네 가지 별개의 이유이며, *"이 호출자가 이 도구에 대한 권한이 있는가"*가 잘못된 질문인 이유이기도 하다.
{"id": "G1", "tool": "fs.read", "scope": "/data/reports",
"purpose": "q3-report", "expires_at": 100, "max_uses": 10}호출 | 무엇이 잘못되었는가 | 무엇이 있었다면 허용되었을까 |
| 같은 문자들로 시작하는 다른 디렉터리 | 도구 ✓ 목적 ✓ 만료 ✓ |
| 허가된 디렉터리를 통해 도달한 같은 디렉터리 | 도구 ✓ 목적 ✓ 만료 ✓ |
| 허가가 40틱 전에 만료되었다. 호출 자체에는 아무 문제가 없다 | 도구 ✓ 범위 ✓ 목적 ✓ |
2회 허용된 허가에 대한 세 번째 | 허가는 권한이면서 동시에 예산이다 | 도구 ✓ 범위 ✓ 목적 ✓ |
| 세션의 첫 번째 호출과 완전히 동일하지만, 왜 수행되는지가 다르다 | 도구 ✓ 범위 ✓ 만료 ✓ |
| 템플릿이 | 도구 ✓ 범위 ✓ 목적 ✓ 만료 ✓ |
| 하나의 키에 대한 허가를 가진 것은 키링(keyring)을 가진 것이 아니다 | 도구 ✓ 목적 ✓ 만료 ✓ |
각각에 대해, 이름이 명시된 그 검사만 끄고 호출이 통과해야 함을 요구하는 테스트가 있다. 여러 검사가 함께 잡아내는 거부는 그중 어느 하나에 대해서도 아무것도 증명하지 못한다.
Related MCP server: MCP Airlock
혼란스러운 대리인(confused deputy)
render_template은 허가되어 있다. /templates/leak.md는 허가된 범위 안에 있다. 템플릿은 {{include:/etc/service-token}}을 포함한다.
서버는 호출자가 갖지 못한 권리를 보유하고 있으며, 호출자가 결코 이름을 지정하지 않은 리소스에 그 권리를 사용하도록 요청받고 있다. 인자 안의 리소스를 검사하는 권한 계층은 정확히 그것이 중요한 도구들에 대해 잘못된 것을 검사하는 것이다.
그래서 검사는 호출이 도달하는 것을, 도달하기 전에 살펴본다 — 그리고 나서 /data/reports/q3.csv에 도달하는 /templates/report.md에는 여전히 yes라고 말하는데, 이 호출자는 그 파일에 대한 허가를 실제로 보유하고 있다. 권한 검사의 절반은 yes이다. 템플릿이 무언가를 포함할 수 있기 때문에 모든 템플릿을 차단하는 규칙은 규칙이 아니다.
경로 포함 관계(path containment), 보통 여기서 틀린다
두 실수 모두 한 줄짜리다.
path.startswith(scope) # /data/reports-private is "inside" /data/reports
".." in path # and this breaks ordinary callers to catch nothing두 번째 실수는 그 자체로 사례가 될 만하다. /data/reports/../reports/q3.csv는 허가된 범위 안으로 다시 해석(resolve)되며, 허용되어야 하는 호출로 말뭉치에 포함되어 있다. 문자를 금지하는 것은 싸구려 수정이다; 경로를 해석하는 것은 금지가 잡는 모든 것을 잡으면서, 금지가 잡지 못할 것은 아무것도 잡지 않는다.
여기서의 해석은 어휘적(lexical)이며 파일시스템에 절대 닿지 않는다 — realpath, os.stat, open(을 grep하는 테스트가 있다. 결정은 호출자가 제공한 경로에 대해, 호출 이전에 실행되며, 무엇이 존재하는지에 따라 답이 달라져서는 안 된다.
로그가 곧 제품이다
두 가지 속성이 로그를 일기장이 아니라 증거로 만든다.
거부를 기록한다. 성공한 것만 기록하는 로그는 "에이전트가 무엇을 시도했는가"라는, 나중에 누구나 실제로 묻는 질문에 답할 수 없다. 여기서는 열일곱 개 항목 중 여덟 개가 거부이며, 각각 그것을 만든 검사와 평이한 영어로 된 이유가 함께 있다.
재생(replay)할 수 있다. 모든 항목은 결정이 내려진 허가와 정책 버전을 담고 있어, 결정을 로그만으로 다시 계산하고 기록된 판정과 비교할 수 있다:
python3 gate.py --verify audit.json
replay: 17/17 entries recompute to the verdict they recordreplay 필드가 꺼져 있으면 그 숫자는 0/17이다 — 항목들은 여전히 무엇이 결정되었는지 말하지만, 아무도 그것을 검증할 방법이 없다.
그리고 항목들은 해시 체인으로 연결되어 있어, 제거되거나 편집된 항목이 드러난다:
entry 6 does not follow the one before it -- something was removed or edited비밀은 절대 들어가지 않는다. 비밀을 담은 감사 추적은 비밀의 두 번째 사본을, 더 많은 사람이 읽을 수 있는 파일에 만드는 것이다. secrets.get은 이 세션에서 허용되며 그 값은 로그 어디에도 나타나지 않는다; naive 로그에는 두 개가 들어 있다.
아홉 가지 검사, 그리고 각각이 자리할 자격이 있음을 증명하는 것
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.py기록할 가치가 있는 한 가지 수정 사항: scope 제거(ablation)의 첫 버전은 검사를 끄지 않았다 — 문자열 접두사 비교로 대체했는데, 이는 검사의 부재가 아니라 다른 검사였고, 검사가 필요함을 증명하기 위해 존재하는 호출을 조용히 계속 거부했다. 검사를 끈다는 것은 정말로 꺼야 한다는 뜻이다, 그렇지 않으면 제거는 교체를 측정하는 것이다.
같은 세션은 또한 마지막 호출이 커버하지 않는 키를 지정해서가 아니라 한 번 더 사용해서 거부된, 그렇게 크기가 정해진 허가를 드러냈다. 그것은 잘못된 검사를 테스트하면서 통과하고 있었다. 수정은 픽스처(fixture)에 있었고, 그것을 발견한 테스트는 각 거부가 자신의 검사를 격리하도록 요구하는 테스트다.
알려진 한계, 숨기지 않고 명시함
이것은 결정 계층이지 전송(transport)이 아니다. 결정을 내리고, 프로세스 내(in-process) 도구 테이블에 대해 실행하며, 로그를 남긴다. 실제 MCP 전송에 연결하는 것은 평범한 작업이다; 여기 있는 것은 보통 빠져 있는 부분이며, 네트워크도 키도 없이 실행된다.
허가는 이끌어내는 것이 아니라 기록된다. 실제 배포에서는 사람에게 묻고 답을 저장한다. 그 답이 포함해야 하는 것 — 도구, 범위, 목적, 만료, 사용 횟수 — 이 이 문서가 주장하는 부분이다.
purpose는 호출자가 선언하고 액면 그대로 받아들여진다. 목적에 대해 거짓말하는 호출자는 검사를 무력화한다. 그래도 실질적인 무언가를 얻는다: 선언된 목적이 로그에 있으므로 거짓말은 기록에 남고, 허가의 범위가 그것을 수용하기 위해 넓어지지도 않는다.대리인 검사는 한 도구의 도달 범위를 안다.
render_template은 자신의 include를 파싱한다. 서버가 도달 범위를 계산할 수 없는 도구는 이런 방식으로 검사할 수 없으며, 그러한 도구에 대한 정직한 답은 더 넓은 검사가 아니라 더 좁은 허가다.체인은 순서와 무결성을 증명하지, 보관(custody)을 증명하지 않는다. 전체 파일을 다시 쓸 수 있는 사람은 전체 체인도 다시 쓸 수 있다. 이는 선택적 편집을 보이게 만드는데, 그것이 현실적인 위협이다; 추가 전용 저장소나 외부 앵커가 나머지를 보이게 만드는 것이며, 그것은 배포 작업이다.
구조
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실행
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, 네트워크를 끈 상태로:
docker compose run --rm gate테스트
하나는 허용 목록이 거의 모든 것을 여전히 통과시킨다고 주장한다. 하나는 모든 기록된 결정을 재생하고 같은 판정을 요구한다. 하나는 각 거부가 이름이 명시된 검사 때문에만 살아남도록 요구하여, 제거 숫자가 말하는 바를 의미하게 한다. 하나는 경로 해석기에서 파일시스템 호출을 grep한다.
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