An AI agent on your team just deleted a customer record, moved a payment, or hit an internal API. It did it through an MCP tool, in a loop, with no human watching. The next morning, someone asks the only question that matters: which tool ran, whose access it used, and was it allowed. If the answer is a shrug, you do not have compliant agents. You have fast ones.
The morning after your agent moved money
Model Context Protocol turned chat models into actors. An agent no longer just talks. It calls tools, runs commands, reads files, and writes to real systems. That is the point of MCP, and it is also the problem.
Every one of those tool calls is an action with consequences, and most teams cannot reconstruct a single one after the fact. You can see that the agent used a tool. You cannot see which tool, on whose behalf, with what input, and whether a policy should have stopped it.
Auditors do not accept "the agent decided to." A SOC 2 review, an incident postmortem, a customer security questionnaire: they all ask the same thing. Show me the record.
The gap is not that agents are dangerous. It is that they are unaccountable by default.
Your logs have the conversation, not the action
Here is the mechanism that trips people up. Standard LLM logging records the request and response between your app and the model. You get the prompt, the completion, the tokens, the latency. What you do not get is the tool call the model set in motion.
When a model returns a tool call, that is a decision, not an execution. Something downstream still has to run delete_record or send_payment. If that execution happens inside your app code or a raw MCP client, it never touches the logging layer watching your model traffic. The action is invisible to the exact system you built to watch AI.
So you end up with two half-pictures. The model logs know the agent wanted to do something. Your database knows something happened. Nothing connects them.
Picture the incident. Your model logs show a completion that requested send_payment at 2am. Your ledger shows money left the account. Between those two facts sits the part you need and do not have: the call itself, its amount, the key it used, and whether anything checked it first. That missing middle is what an auditor circles.
Closing that gap means putting the tool execution itself behind something that records it. That is what an MCP gateway is for.
What a full MCP tool-call record looks like
I ran Bifrost locally to see exactly what it captures. It is an open-source AI gateway built by Maxim AI that also acts as an MCP gateway, so tool calls route through one place that logs them the same way it logs model calls.
You do not have to let the model auto-run anything. In the default flow, the model returns a tool call and your app decides whether to execute it by posting to one endpoint.
curl -X POST http://localhost:8080/v1/mcp/tool/execute \
-H "Content-Type: application/json" \
-d '{"id":"call_9f2","type":"function","function":{"name":"filesystem_list_directory","arguments":"{\"path\":\".\"}"}}'
The tool runs, returns its result, and the call lands in the log with everything an audit needs. Read it straight back from the logs API, filtered like any other request.
curl "http://localhost:8080/api/logs?status=success&content_search=filesystem_list_directory"
Each row carries the tool name, prefixed by its MCP client so filesystem_list_directory is unambiguous across servers, the input arguments, the result, the latency, the cost, the token counts, the timestamp in RFC3339, and the identity behind the call through selected_key_id. If the call failed over or rotated keys, an attempt_trail records every attempt in order. Logging runs on background workers and adds under 0.1ms per request, so you are not trading latency for the paper trail.
Line those fields up against the three questions from the incident and they answer cleanly. Which tool ran is the prefixed tool name. Whose access it used is selected_key_id. Whether it was allowed was decided before the call executed, at the key. One row, three answers, which is exactly what a reviewer wants and rarely gets.
This holds even when you let the agent run on its own. In agent mode Bifrost auto-executes tools in a loop up to a max_agent_depth of 10, and every step in that loop is logged the same way. Autonomy does not mean going dark.
For tracing across a whole run, Bifrost emits OpenTelemetry spans in the genai convention, and each tool call carries attributes like mcp.method.name and gen_ai.tool.name. A Prometheus metric, bifrost_mcp_client_operation_duration_seconds, breaks latency down by client, tool, and error type. Point it at the Grafana or Datadog you already run and MCP activity shows up next to everything else.
If the tool inputs are sensitive, set disable_content_logging. You keep the metadata that proves what ran, who ran it, and how long it took, while the request and response bodies are dropped.
One clarification saves a lot of confusion. Bifrost Enterprise has an Audit Logs tab, and it is easy to assume that is your tool-call record. It is not. That trail tracks configuration changes: who created a key, who changed a policy, who signed in. The record of what the agents actually did lives in the observability logs, which even get their own store. Look in the right place.
Tying every call to a real person
A log line is only useful if it points at a human. This is where identity matters, and Bifrost keeps it mechanical rather than manual.
A user signs in through your company identity provider over OIDC, and Bifrost provisions them from that directory or takes a SCIM push in real time. Their group or claim maps to a role. That role carries an access profile, which is a reusable policy template, and the moment the role applies, Bifrost clones the template into a per-user copy and issues a managed virtual key. The key carries exactly what the person is allowed to do, including which MCP tools, and it is write-protected so the holder cannot edit around it.
That last detail matters more than it sounds. A user who can edit keys still cannot widen their own tool access, because the profile owns the key, not the person. You change access in one place, on the role, and it flows down to everyone who holds it. No per-user key sprawl, no forgotten grants.
The offboarding half is the part security actually cares about. When the identity provider marks a user inactive, or a SCIM delete arrives, or the periodic reconciliation no longer finds them, Bifrost decommissions the user locally. Their key stops working at both model and tool-execution time. A departed employee's agent cannot keep acting on Monday, because the wiring that granted access is the same wiring that removes it.
So every tool-call record traces back to a provisioned person, and access has a real lifecycle instead of a spreadsheet of keys nobody revokes.
Three catches most people miss
The honest gotchas, because a compliance story with no caveats is a sales page.
First, the two ways to scope MCP tools behave in opposite directions. At the virtual key, filtering is deny-by-default. A key with no MCP config gets no tools at all.
curl -X POST http://localhost:8080/api/governance/virtual-keys \
-H "Content-Type: application/json" \
-d '{"name":"billing-agent","mcp_configs":[{"mcp_client_name":"billing","tools_to_execute":["check_status"]}]}'
MCP Tool Groups, the enterprise layer for reusing tool bundles across teams, do the reverse. If no group matches a request, the request falls through with all tools available. Mix the two mental models and you will believe an agent is locked down when it is wide open. Decide which layer is your source of truth and test the empty case.
Second, Bifrost records that a tool ran, but it does not record your human approve-or-deny decision. When you gate a tool behind a person clicking yes, that click is yours to capture. Send it to the same audit sink as the execution, or your trail shows the action without the authorization behind it.
Third, know the line between free and paid. The tool-call logging, the virtual-key filtering, the tracing, and the MCP gateway itself are open source and run today. Access profiles, tool groups, role-based access, directory provisioning, and signed exportable audit logs are Enterprise. Plan the rollout around that line, not around a screenshot.
Final Thoughts
Compliance-ready for agents is not a certification you buy. It is a plain capability: you can hand someone every tool call an agent made, tied to a real person, against a policy that says whether it was allowed.
Most of that is reachable now. Route your MCP tool calls through a gateway that logs them, scope them at the virtual key, and wire access to your identity provider so it lives and dies with employment. Add the enterprise layer when you need signed audit and provisioning at scale.
The teams that get burned this year will not be the ones whose agents did something wrong. They will be the ones who could not say what their agents did at all.
Resources & References
- Bifrost MCP documentation
- Bifrost observability and logging
- Bifrost governance and MCP tool filtering
- Bifrost on GitHub (open source)
Stay in Touch
Short takes and discussions on X
→ https://x.com/sebuzdugan
Practical AI / ML videos on YouTube
→ https://www.youtube.com/@sebuzdugan/
Partnerships & collabs
→ sebuzdugan@gmail.com
Originally published on Medium.




Top comments (0)