Most agent stacks already log plenty: prompts, completions, tool calls, latency, token counts. That's useful for debugging. After an incident, though, a security reviewer will ask something the traces can't answer: was this action allowed, for this agent, on behalf of this person, against this record, at this time?
If an agent can change things in systems that matter, each decision should record roughly this:
- The person who delegated or started the action.
- Which agent acted, down to the client or instance. If all agent traffic runs through one shared service account, you can't tell them apart later.
- The task or workflow context, when you have it. Capture it, but don't enforce on declared intent alone.
- The tool, MCP server, connector or API action that was called.
- The target resource, tenant or data class.
- The policy decision: allow or deny, with the policy ID or version and the reason.
- Whether approval was required, and who gave it.
- Timestamps and correlation IDs, so you can join the user request, the agent run, the decision, the tool call and whatever happened downstream.
The simplest place to produce that record is where enforcement happens, at the point where the agent crosses into a real tool. A successful login shows the person authenticated. It doesn't show that the agent may export a file or call a privileged MCP tool ten minutes later. So check each action there, block or allow before the tool runs, and emit the audit event from that same decision. Working out afterwards from a transcript whether something was allowed is much harder to defend.
For a read-only assistant that can't change anything, you can skip most of this.
Disclosure: I work at Permit.io. This is a short version of a post by our CEO, Or Weis, which also covers where an MCP gateway fits as the enforcement point and what NIST's NCCoE concept paper says about access delegation:
Top comments (1)
One field I would add for agents that call metered tools: what the user was shown before approving. In my setup the enforcement point is the client's pre-tool hook, which is also where the record is cheapest to emit, exactly as you say. For a paid call the record carries the count the agent reported, the sample size and its hit rates, the extrapolated charge, and the approval token (a file the user creates, consumed by the first paid call). Without those, "approval was required and who gave it" is true but unreviewable: a reviewer cannot tell whether the person approved a 100-row sample or a 25,000-row pull, because the two approvals look identical in the log. Hash the arguments if they can hold secrets, but keep the numbers the approval was based on in the clear; they are the part a reviewer actually needs.