Find and remove unused permissions from an AI agent
Replay recorded decisions to see which agent grants were never used, propose a smaller set, and preview what it would deny. Runnable TypeScript.
Agents collect permissions because widening a grant is easier than working out the narrow one, and nobody comes back to trim them. The audit log already knows what each agent used, so you can ask it.This tutorial gives one agent ten grants, sends it 498 calls, then reports which grants were never touched, proposes a smaller set, and checks the proposal against the recorded decisions. Nothing is changed for you. It runs in memory with no model and no API key.
Five of ten grants were never used, including the dangerous ones: tool:billing *, tool:db:users delete and tool:mail send. The two denied delete calls on repos do not count as use, which is why mcp:github:repos write stays in the unused list.The part to read carefully is newly denied: 3. The agent called query on tool:db:users three times, below the threshold of five, so the proposal drops it. You see that cost before you apply anything. If those calls are legitimate, lower minObservations (the default is 1, which keeps every grant that was ever used).
It proves past behavior only. A quarterly job or an incident runbook may fall outside your window and get proposed for removal. Widen since for agents with long cycles.
Matching covers action and resource. Rate limits, time windows and approvals depend on live state and are not re-evaluated in the replay.
Evidence is bounded by your audit retention, and by whether auditAll was on.
Overlapping grants follow authorize() order, first match wins, so a broad grant listed first takes the credit.