⭐ Star on GitHub

Summary: A concrete implementation of agent audit trails — MCP client-side structured logging, a 14-field log schema, and SIEM/SOAR routing. The operational answer to T8 Repudiation & Untraceability, and the vault’s first implementation-level detection source.

Sources: raw/Agentic/Security Monitoring for AI Agents and MCP.md

Last updated: 2026-07-30


Provenance

Realm Security blog, 2025-08-05, by Colin Jermain (source: Security Monitoring for AI Agents and MCP.md). Vendor content — Realm sells a Security Data Pipeline Platform and the post routes logs through it — but the technique is vendor-independent and the code uses only open-source components: FastMCP, python-json-logger, LangGraph, langchain_mcp_adapters.

This is a different kind of source from everything else in raw/Agentic/. The ASI document and MAESTRO name repudiation and untraceability as threats and stop at “maintain audit trails.” This source is the audit trail, in code.

The problem it names

An operational blind spot: “when an AI agent interacts with a suite of tools — accessing APIs, querying databases, or analyzing files — its decision-making process is often scattered across different systems or lost entirely. Traditional application logging methods fail to capture the agent’s chain of thought and action, making it very challenging to perform effective security monitoring or forensic analysis when something goes wrong.”

Two consequences, and the source is explicit that they are different problems: security monitoring (detecting an agent behaving anomalously) and compliance (producing a defensible record). The second is the one the AI Act’s logging requirements make non-optional for high-risk systems.

Client-side logging is the key move

MCP defines a mechanism for a server to send structured log messages to its client. The source uses it to invert where logs are assembled:

“Client-side logging allows us to centralize all records for the agent in one unified stream, instead of having to stitch the logs together after the fact.”

Each tool on the MCP server emits through the FastMCP Context object (await ctx.info(...), await ctx.error(...)), implementing the MCP specification’s server-utilities logging contract. The agent registers a logging_callback on the connection, receives those messages, and stamps them with agent-level identity before writing them out.

The security significance is the correlation, not the logging. A single event_correlation_id spans the agent’s own actions and every tool invocation across every MCP server it touched, so the record of what an agent did is one queryable stream rather than a reconstruction. Without it, attributing a tool call to the task and principal that caused it is post-hoc forensics — which is precisely the T8 failure.

The log schema

Nine core fields covering agent identity and correlation:

FieldTypePurpose
timestampISO 8601 stringUTC event time
log_levelstringINFO / WARNING / ERROR
messagestringHuman-readable summary
agent_idstringUnique per agent instance
agent_namestringFunctional name of the agent
model_idstringWhich model the agent ran on
principal_user_idstringThe user or service account that invoked the task
event_correlation_idstringUnique per agent task, spans all entries
event_actionstringThe specific action or tool used
source_mcp_serverstringWhich MCP server provided the tool

Plus five task-specific fields in the worked example: threat_indicator_type, threat_indicator_value, threat_verdict, threat_summary, threat_type.

Four of the nine carry the security weight:

  • principal_user_id — the source’s own gloss is “for accountability.” This is the field that answers on whose authority did the agent act, and it is the one an agent framework will not give you for free. Its absence is the confused deputy problem made unauditable: a tool call with no principal cannot be checked against that principal’s permissions after the fact.
  • event_correlation_id — makes the task the unit of investigation instead of the log line.
  • agent_id distinct from agent_name — instance versus role, so one misbehaving instance is separable from its fleet. Relevant to rogue agents, which are defined by operating outside monitoring boundaries.
  • source_mcp_server — attributes an action to the server that offered the tool. Directly useful against T16 and the ATLAS poisoned-MCP-tool case studies: if a tool’s behaviour changed, this field is what identifies which server served it.

What the schema omits is as informative. There is no field for the tool’s input arguments, no field for the model’s reasoning or the prompt, and no integrity protection on the log itself. Arguments and prompts are the payload an injection arrives in — a log recording that get_url_reputation was called, but not with what, cannot reconstruct an attack. The post calls the result “a complete, contextualized, and immutable audit trail”; immutability is asserted, never implemented. Nothing in the code signs, chains or write-protects the records. Treat the schema as a floor.

The worked example

An AI Phishing Triage Assistant — a ReAct agent over three MCP tools (extract_iocs_from_email, get_url_reputation, get_filehash_reputation), with threat-intel APIs mocked. Pydantic-constrained output (ThreatVerdict enum: benign / suspicious / malicious, plus a summary) so the verdict is machine-actionable rather than prose. Fed a phishing email, it returns malicious with a reasoned summary, and the resulting structured log is what triggers downstream SOAR action: alert the SOC, block the URL at the firewall, open a ticket.

Two deployment notes worth keeping:

  • The MCP server runs over Streamable HTTP rather than stdio, deliberately, “to simulate a realistic microservices architecture, where multiple agents consume tools over a network.” The source flags that this needs TLS and private networking (VPC) so tool access is restricted to trusted agents. That is the T16 surface appearing as an implementation detail — a network-exposed MCP server is reachable by anything that can route to it.
  • Logs are split by destination: the expensive subset to the SIEM, everything to a cheap archive for compliance and later forensics. A cost control with a security consequence — the retention that matters for investigation lives in the archive, so the archive is what an attacker who wants to erase a trail would target. Compare MAESTRO Layer 5, where poisoning observability data and hiding behaviour from monitoring are named threats.

This is the T8 page the ASI document could not support

T8 Repudiation & Untraceability was deliberately left without a page when this collection was created — the ASI source described it too abstractly to sustain one. This source supplies the missing half:

ASI / MAESTROThis source
T8 asA threat: actions that cannot be traced or attributedA schema that makes them attributable
Control stated as”Maintain audit trails”, “ensure traceability”14 fields, correlation IDs, a code path
GapNo definition of what an audit trail must containNo integrity, no arguments, no reasoning captured

T8 has no OWASP Top 10 counterpart — it is one of the seven unmapped agentic threats — and it is also STRIDE’s R, which conventional threat modelling has carried for decades. See threat-modeling-frameworks. The category was not new; the LLM taxonomies dropped it, because a system that only generates text has little to repudiate.

Detection, not just recording

The logs are meant to be monitored, and the source’s claim is that this turns “agents from a source of risk into a monitored asset.” What it does not do is say what to alert on. Reasonable detections the schema supports, as this wiki’s inference rather than the source’s:

  • A tool invoked with no principal_user_id, or with a principal that lacks rights to that tool’s effect.
  • One event_correlation_id fanning out to far more tool calls than the task profile expects — the observable signature of T2 and of T4 resource overload.
  • source_mcp_server appearing for a server not on the approved list, which is T17 in telemetry.
  • An agent_id whose action mix diverges from its fleet — rogue agent behaviour.

None of these are in the source. It builds the telemetry and leaves the detection content to the reader, which is the honest boundary of a post about logging.

Framework maturity, as of the source

Two named limitations, both real and both dated:

  1. FastMCP v2.10.6 required the client-side log message to be a str, so structured fields could not be sent from the server side. The author contributed **PR 1326**, adding extra support, released in FastMCP v2.11.0. Anyone reproducing this needs ≥ 2.11.0, or server-side logs will be message-only.
  2. No client-side analogue of Python’s logging.exception — so tracebacks, “critical for understanding the error in depth,” do not cross the MCP boundary.

Both are open-source plumbing gaps rather than design flaws, and the first is already closed. The general point stands: agent audit trails are being retrofitted into protocols that did not plan for them.