Proposal: Standard audit context for AI-initiated MCP tool invocations #2704
Replies: 32 comments 2 replies
-
|
As an implementation data point, TadpoleDBHub has already implemented a server-specific version of this audit context. Current behavior:
Operational lessons:
Based on this experience, |
Beta Was this translation helpful? Give feedback.
-
|
This proposal maps closely to what I would want from an operational "agent run record" around MCP calls. A few fields I would consider separating explicitly:
I agree strongly that One thing I would avoid is making
From an ops perspective, the real value is being able to answer later:
That is also the direction we are experimenting with in Armorer: local/self-hosted agent runs need an inspectable record of tools, approvals, files/data touched, and final artifacts. MCP standardizing even a small optional |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @armorer-labs — this is a helpful framing, and I agree with the broader operational direction. The full "agent run record" is valuable, but I would like to keep this initial proposal narrower. The immediate interoperability gap is that MCP servers currently have no standard place to receive the audit context for an AI-initiated request:
This came from an implementation problem in practice: servers can add custom tool arguments such as A standard I agree strongly on On the additional fields:
So I think the clean split is:
That would solve the immediate interoperability problem while keeping the first proposal small enough to standardize. |
Beta Was this translation helpful? Give feedback.
-
|
Implementation data point from a non-MCP-native runtime that already records this shape — agent-guard emits per-tool-call audit context for Bash / WriteFile / HttpRequest / Custom tools. Two operational refinements worth contributing back: 1. A single user turn in a coding agent regularly produces a tree of N retries inside one tool invocation, plus K cascading tool calls. With only 2. The proposal as written is input audit (what the AI claimed it was doing). It pairs with — but doesn't replace — output audit (what was allowed and by which rule).
On the proposal's specific questions:
|
Beta Was this translation helpful? Give feedback.
-
|
Thanks @XuebinMa — this is a useful implementation data point, especially from a non-MCP-native runtime. I agree with the distinction between input audit and server-side decision/output audit. The intent of this proposal is the input side: what the AI/client asked for and why:
The server-side decision record you described — I also agree that On the specific refinements:
So my current split would be:
That keeps the first step focused while preserving the stronger audit model you are pointing to. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @hangum — the split lands well. Keeping SEP-0 to client-asserted input audit (plus the optional turnId response echo) and pushing the server-side decision record into follow-up is the right ordering; mixing client-asserted "why I asked" with server-authoritative "what I allowed" in the same SEP would have made both harder to standardize. Two small things for the record on the follow-up:
On the |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @XuebinMa — both points are useful and I think we can fold both in cleanly. 1. Forward-compatibility line in
That preserves the seam without committing to any specific follow-up shape. 2. Reference implementation for the server-side decision record. Noted, and thanks for flagging it ahead of time. Having a concrete working shape ( On Next step from my side: prepare the SEP-0 draft for the input-audit |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the quick turnaround. The forward-compat line and the cross-reference offer are both very appreciated. Since you explicitly asked for input on field shape before the SEP-0 draft, here's some from the implementation side — agent-guard has been chewing on these for a while: 1. In practice we needed both: a machine-readable invocationReason: {
kind: "user_request" | "agent_chain" | "scheduled" | "retry" | "replay" | "tool_chain",
text?: string
}Policy engines can branch on 2. We've hit cases where model: {
name: string,
provider?: string,
version?: string
}Common case stays cheap ( 3. Echoing the earlier privacy note: even when optional, implementations end up logging either the raw text, a truncated version, or a hash. Worth defining the shape rather than letting everyone reinvent it: userIntent: {
text?: string,
hash?: string, // e.g., sha256 of original
redacted?: boolean // text was modified/truncated
}If you prefer the simpler-string shape, at least call out a recommended max length and a redaction convention in the SEP — otherwise interop suffers. 4. No strong opinion on format, but worth stating it's an opaque string clients MUST NOT parse, with a non-binding recommendation (UUIDv4 / ULID). That keeps validators honest about format assumptions. Reference implementation: once SEP-0 lands as a draft, I'll publish a field mapping showing how these flow through agent-guard's existing |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @XuebinMa — this is very helpful implementation feedback. I agree with the general direction: the fields that are likely to grow should probably be structured objects rather than bare strings. A few reactions:
The one place I would be cautious is I agree that pure free-form text is hard to filter in SIEM/policy pipelines. But if SEP-0 starts by standardizing too much taxonomy, it may turn into a broader policy/audit ontology discussion and make the first step harder to land. My current preference would be: "invocationReason": {
"kind": "user_request",
"text": "Need to inspect table schema before generating SQL"
}with So the shape I am leaning toward for the SEP-0 draft is roughly: {
"_meta": {
"invocationReason": {
"kind": "user_request",
"text": "Need to inspect table schema before generating SQL"
},
"model": {
"name": "example-model",
"provider": "example-provider"
},
"userIntent": {
"text": "Show me 10 employees",
"redacted": false
},
"turnId": "opaque-client-generated-id"
}
}All fields optional. All client-asserted. Servers may ignore, redact, transform, or store them according to policy. Servers must not use That keeps SEP-0 focused on the interoperability gap — a standard place to carry AI/client input-audit context — while leaving room for richer policy, sequencing, and server-side decision records in follow-up SEPs. |
Beta Was this translation helpful? Give feedback.
-
|
Agreed on all of this — the draft shape looks right, and your caution on One low-cost hook worth a sentence in the SEP-0 text: state explicitly that Otherwise this looks ready to draft — happy to review once SEP-0 is up. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @XuebinMa — agreed. I will include that explicitly. For SEP-0, That keeps the first proposal focused on the transport location and field shape, while leaving taxonomy expansion to future SEPs or implementation-specific policy. |
Beta Was this translation helpful? Give feedback.
-
|
+1 to the structured 1. 2.
3. On 4. On |
Beta Was this translation helpful? Give feedback.
-
|
Thanks — this is useful implementation feedback. I agree that absent
For For I am less sure about standardizing |
Beta Was this translation helpful? Give feedback.
-
|
@hangum the open-vocabulary @Zawwarsami16 the agent-run vs. user-turn join-key distinction matches what we ended up with in agent-guard: the |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @XuebinMa — agreed. It is useful to see another implementation converge on the same separation between user-turn correlation and longer-lived agent/session correlation. I will keep SEP-0 focused on the minimum input-audit context and leave agent-run/session correlation for follow-up work. |
Beta Was this translation helpful? Give feedback.
This comment was marked as spam.
This comment was marked as spam.
-
|
Thanks for sharing the implementation data point. I agree this belongs to the follow-up server-side decision-record layer rather than SEP-0. The content-addressed For SEP-0 I will keep the scope limited to client-asserted input-audit context ( |
Beta Was this translation helpful? Give feedback.
-
|
The split in this thread feels right to me: client-asserted input audit should stay separate from the server-authoritative decision record.
We have a small synthetic local proof of that pattern here: https://github.com/neurarelay/relay-action-card/blob/main/docs/mcp-risk-gate.md No real MCP server, no downstream execution, no provider claim. Just a concrete data point for the follow-up decision/output-audit layer. Open question: should that future decision record link to input audit through |
Beta Was this translation helpful? Give feedback.
This comment was marked as spam.
This comment was marked as spam.
-
|
Thanks @rpelevin and @chopmob-cloud — both are useful follow-up data points. For SEP-0 I would avoid defining the server-authoritative decision record. The linkage question is important, but I think it belongs in the follow-up SEP: whether a decision record directly references My current leaning is to keep SEP-0 forward-compatible by defining An implementation pass against live or prototype MCP server paths would be very helpful once the SEP-0 draft is open. The feedback I would most want is whether the client-asserted input-audit field semantics ( |
Beta Was this translation helpful? Give feedback.
-
|
Thanks everyone for the feedback on this discussion. I opened the SEP draft as PR #2817: The PR currently defines the minimum client-asserted input-audit context we discussed:
It keeps server-side decision records, stable tool-call identity, agent/session correlation, approval lifecycle, and taxonomy work out of scope for follow-up SEPs. Tagging the main participants from this thread for visibility: @armorer-labs @XuebinMa @Zawwarsami16 @chopmob-cloud @rpelevin If you have time, review on the PR would be very helpful — especially whether the field semantics are clear enough to implement consistently. |
Beta Was this translation helpful? Give feedback.
-
|
Answering the implementability question directly, from wiring these four fields into a non-MCP-native runtime (agent-guard): the shape is implementable as-is. The spots where an implementer currently has to guess are below — all small, each fixable with roughly one sentence of spec text.
On the linkage question @rpelevin raised — agreed it's follow-up scope. Defining Happy to do an implementation pass against the SEP-0 draft once it's posted. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @XuebinMa — this is exactly the kind of implementability feedback I was hoping for. A few points are already reflected in PR #2817:
The remaining clarifications you called out all seem reasonable and small enough to add to the PR text:
I will add those as small clarifying edits to #2817 rather than expanding the scope. The boundary remains the same: SEP-0 defines client-asserted input-audit context; ordering, stable tool-call identity, retry chains, and server-side decision records remain follow-up work. |
Beta Was this translation helpful? Give feedback.
This comment was marked as spam.
This comment was marked as spam.
-
|
Thanks @chopmob-cloud — this is a useful implementation data point. I agree with that split: That keeps the SEP-0 boundary clean:
The |
Beta Was this translation helpful? Give feedback.
This comment was marked as spam.
This comment was marked as spam.
-
|
Thanks @chopmob-cloud — that reference is helpful. I will keep SEP-2817 focused on the client-asserted input-audit context, and treat the Looking forward to your PR review. |
Beta Was this translation helpful? Give feedback.
-
|
The split crystallizing here looks right: turnId as client-asserted user-turn correlation in SEP-2817, and stable server-owned invocation identity as follow-up work. One suggestion for that follow-up SEP. The action_ref approach mentioned upthread already hashes an agent_id into the decision record, which is the right instinct. The open question is what agent_id is. If it is an opaque string the server cannot verify it, but if it is a DID the server (or a later auditor) can resolve it and check that the invocation was actually signed by that agent's key. That turns the audit record from self-reported into independently verifiable, which is the property compliance paths actually need. This stays method-agnostic, any DID works. We have been building did:aip, an on-chain agent DID method on Solana, if a concrete resolver is useful for the follow-up SEP. The general point holds regardless of method: the stable invocation identity should be a resolvable, signature-checkable identifier rather than a bare string. |
Beta Was this translation helpful? Give feedback.
This comment was marked as spam.
This comment was marked as spam.
-
|
The follow-up that came out of this thread, a server-side signed record of what the tool call actually did, is what I have been building as an open SEP (2828). It is a signed, hash-chained record the server emits per tool call, with the outcome bound back to the decision that authorized it: an instance anchor (Check A) plus a content digest over the signed decision (Check B). Check B adopts the outcome-to-decision-digest idea XuebinMa raised here, so the two efforts line up rather than fork. For an audit standard, the property that counts is that the record is verifiable without trusting the emitter. The conformance vectors are published, and a second independent implementation (Assay, by Rul1an) reproduced them from a clean checkout with no shared code. There is a stdlib-only checker in the repo so anyone can run them. SEP-2828: #2828 I would value review from people here, especially on the pairing rules and the supersession tie-break. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal: Standard audit context for AI-initiated MCP tool invocations
Problem
AI models and MCP hosts can issue tool calls that perform security-sensitive or operationally important actions, such as database queries, file access, administrative operations, or workflow automation.
For audit, debugging, and operational traceability, the most important missing context is why the AI invoked a tool and which model produced that invocation. Servers often need to understand:
Today there is no standard place to carry this information. Implementations may invent their own tool arguments such as:
user_queryreasoninvocation_reasonmodelai_modelrequest_idmcp_request_idcorrelation_idThis fragments interoperability and makes audit logs inconsistent across MCP servers.
Example
A user asks:
An MCP host/client might issue multiple tool calls. Each call has a different reason, but all calls belong to the same user turn and were produced by the same model.
{ "method": "tools/call", "params": { "name": "list_tables", "arguments": { "database_id": "123" }, "_meta": { "turnId": "2f4f0c9e-8d72-4c66-9c6f-3f7f3e6a1c9f", "userIntent": "Show me 10 employees.", "invocationReason": "The user asked for employee records, but the client does not yet know the available table names.", "model": { "name": "example-model" } } } }{ "method": "tools/call", "params": { "name": "execute_query", "arguments": { "database_id": "123", "query": "SELECT * FROM employees LIMIT 10" }, "_meta": { "turnId": "2f4f0c9e-8d72-4c66-9c6f-3f7f3e6a1c9f", "userIntent": "Show me 10 employees.", "invocationReason": "The employees table has been identified, so the client is executing the requested limited SELECT query.", "model": { "name": "example-model" } } } }Proposal direction
Define optional audit context metadata for AI-initiated MCP requests, likely under request
_meta.Core fields:
_meta.invocationReason: why the AI/client is invoking this specific MCP request_meta.model.name: best-effort model name that produced the invocation_meta.userIntent: the user's original request, if the client can safely provide it_meta.turnId: groups multiple MCP requests caused by the same user turnAll fields should be optional.
Servers may store them, ignore them, redact them, or echo selected fields back in response
_metafor client-side log correlation.For JSON-RPC batch requests, each request element can carry the same
_meta.turnIdif the requests belong to the same user turn.Semantics
A user turn means one user input that may produce multiple MCP client-to-server requests.
The MCP host/client should generate the
turnIdonce at the start of the user turn and reuse it for all MCP requests caused by that turn.invocationReasonis per request. It explains why this specific tool/request is being made, not just what the user asked.userIntentandinvocationReasonare different:userIntent: what the user askedinvocationReason: why this specific MCP request is being madeTrust and security
This is not an authorization mechanism. It is audit and traceability metadata.
In particular:
userIntentmay contain sensitive or personal data.invocationReasonis AI/client-generated and may be incomplete or inaccurate.model.nameis client-asserted and may be spoofed.Servers should not use these fields as the sole basis for authorization decisions.
Servers that persist these fields should consider redaction, tokenization, retention limits, and role-based access to audit logs.
Clients should be able to omit sensitive fields in private/sensitive modes.
Relationship to
progressTokenprogressTokenandturnIdhave different cardinality and purpose.progressToken: tracks progress within one long-running request.(1 request -> N progress updates)turnId: groups multiple requests caused by one user turn.(1 turn -> N requests)They can both live under
_metawithout representing the same thing.Naming
I used
turnId,userIntent, andinvocationReasonhere to make the distinction explicit.correlationIdmay also be viable for the first field. I would avoidtraceIdbecause it overlaps with W3C Trace Context / OpenTelemetry terminology.Security framework alignment
This proposal is not claiming that OWASP or NIST requires these exact MCP fields.
It is meant to provide protocol-level support for controls that AI security guidance already encourages at the application and operational layers:
invocationReason,model.name,userIntent, andturnIdwould not solve those risks by themselves, but they would give MCP servers a standard way to record the context needed for audit, monitoring, incident review, and policy enforcement.Motivation
This is not because GDPR or similar laws require MCP-specific fields. The motivation is operational traceability and auditability for AI/tool systems.
AI security guidance often recommends audit logs, abnormal access detection, and operational traceability, but it does not define how an agent/tool protocol should carry user intent, per-invocation rationale, model attribution, or turn correlation.
A small optional
_metaconvention could reduce server-specific custom arguments and make MCP implementations easier to audit consistently.Questions
_metathe right location for this kind of AI tool-invocation audit context?invocationReasonandmodel.namethe right names and semantics for the core fields?userIntentbe included in the same proposal, or separated because of privacy concerns?turnIdbe included as supporting correlation metadata for multi-call user turns?turnIdin response_meta?Beta Was this translation helpful? Give feedback.
All reactions