MCP Audit Logging: Complete Security and Compliance Guide
MCP allows AI applications to access data and perform actions through external servers.
A single request may involve:
- a human user
- an AI host application
- an MCP client
- an Authorization Server
- an API gateway
- an MCP server
- a policy engine
- a credential broker
- a background task
- a database
- a third-party API
- an administrative approval
When an important action occurs, an organization must be able to answer:
Who initiated the action?
Which MCP client acted?
Which server and tool were used?
What resource or tenant was affected?
Which authorization and approval allowed it?
What data moved?
Which downstream system changed?
Did the operation succeed?
Without a connected audit trail, each system may expose only a fragment.
Identity Provider:
User logged in
Authorization Server:
Token issued
MCP Server:
Tool called
Downstream API:
Resource changed
None of those records alone explains the complete event.
MCP audit logging creates that connection.
User
│
▼
MCP Host and Client
│
▼
Authorization Server
│
▼
MCP Gateway
│
▼
MCP Server and Tool
│
▼
Downstream Service
│
▼
Correlated Audit Trail
NIST describes log management as the process of generating, transmitting, storing, accessing, and disposing of log data, supporting use cases such as cybersecurity incident identification, investigation, operational troubleshooting, and required retention.
Quick Answer
MCP audit logging is the authoritative recording of security-relevant events across the complete MCP execution chain. A useful audit record should preserve the verified user, OAuth client, workload, MCP resource, tool, target, tenant, authorization decision, approval state, downstream effect, and outcome. It must exclude reusable credentials, minimize sensitive prompt and data content, support correlation across systems, resist tampering, and remain searchable during incident response.
MCP Protocol Logging vs Audit Logging
MCP includes a structured logging utility.
In protocol revision 2025-11-25, a server can advertise:
{
"capabilities": {
"logging": {}
}
}
The client may request a minimum level using:
{
"jsonrpc": "2.0",
"id": 24,
"method": "logging/setLevel",
"params": {
"level": "warning"
}
}
The server can then send:
{
"jsonrpc": "2.0",
"method": "notifications/message",
"params": {
"level": "error",
"logger": "database",
"data": {
"message": "Connection failed"
}
}
}
The stable MCP schema defines the following levels:
debuginfonoticewarningerrorcriticalalertemergency
These levels map to the severity model from RFC 5424.
This protocol feature is primarily useful for:
- diagnostics
- progress visibility
- troubleshooting
- development feedback
- client-facing operational messages
It is not automatically a complete security audit system.
Why Protocol Logs Are Not an Audit Trail
MCP protocol logs may be:
- filtered by severity
- disabled
- ignored by the client
- displayed but not persisted
- controlled by the server being investigated
- disconnected from Authorization Server events
- missing downstream effects
- unavailable after a process exits
- incomplete during a compromise
Server sends log notification
│
▼
Client may display it
│
▼
Client may discard it
An audit trail should not depend on whether a user selected the debug, info, or warning level.
Security-relevant events must be recorded according to server-side policy even when no MCP logging capability was negotiated.
Audit Logs Must Be Independent
A secure architecture separates:
Diagnostic Logs
Help developers and operators understand technical behavior.
Security Logs
Record suspicious events, policy failures, token misuse, and attacks.
Audit Logs
Record authoritative actions and decisions for accountability.
Business Transaction Records
Record domain events such as a payment, deployment, document deletion, or permission change.
One MCP action
│
├── Diagnostic event
├── Security event
├── Audit event
└── Business transaction
These records may be sent to the same platform, but they have different purposes, schemas, access rules, and retention requirements.
Audit Logging Goals
An MCP audit system should support:
- accountability
- incident detection
- forensic investigation
- authorization review
- abuse detection
- user support
- compliance evidence
- operational reconstruction
- dispute resolution
- data-access reporting
A well-designed record should answer:
Who?
What?
When?
Where?
Through which client?
Against which MCP resource?
With which authorization?
Why was it allowed or denied?
What was the result?
What Audit Logging Cannot Prove Automatically
Logs are evidence, not absolute truth.
A record may be incomplete or misleading when:
- the application logs an unverified identity
- the clock is incorrect
- a compromised server fabricates records
- the real action bypasses the logging path
- logs are modified
- correlation IDs are reused
- downstream actions are asynchronous
- the user account is compromised
- the model summary does not match the actual arguments
Log says:
user-123 requested action
But:
user-123 session may have been stolen
Audit architecture should preserve verified facts and clearly distinguish them from untrusted assertions.
Authoritative vs Untrusted Audit Fields
Consider:
{
"tenant_id": "tenant-a",
"tool_arguments": {
"tenant_id": "tenant-b"
}
}
Which tenant should the audit record use?
The authoritative tenant should come from:
- validated token claims
- server-side session state
- policy engine context
- verified resource mapping
The tool argument should be recorded separately as requested input.
{
"actor_tenant_id": "tenant-a",
"requested_tenant_id": "tenant-b",
"authorization_decision": "deny",
"reason_code": "cross_tenant_request"
}
This distinction is critical during investigations.
The MCP Audit Event Model
A standardized event model makes searches and correlations easier.
A practical audit record may include:
{
"event_id": "evt_01JZ...",
"event_type": "mcp.tool.execution",
"event_version": "1.0",
"timestamp": "2026-07-20T15:42:18.613Z",
"correlation_id": "corr_01JZ...",
"request_id": "mcp-request-4821",
"session_id": "session-fingerprint",
"actor": {},
"client": {},
"authorization": {},
"resource": {},
"operation": {},
"approval": {},
"outcome": {},
"network": {},
"data": {},
"service": {}
}
Do not add every possible field to every event.
Use a consistent core combined with event-specific fields.
Core Event Fields
Every audit event should generally contain:
- unique event ID
- event type
- schema version
- timestamp
- producing service
- environment
- outcome
- correlation identifier
Example:
{
"event_id": "evt_c7d94c8b",
"event_type": "mcp.authorization.denied",
"event_version": "1.0",
"timestamp": "2026-07-20T15:42:18.613Z",
"service_name": "finance-mcp",
"service_version": "4.8.1",
"environment": "production",
"correlation_id": "corr_e3445a91",
"outcome": "denied"
}
Event Identifiers
Every event should have a unique identifier.
event_id = one log record
The identifier supports:
- deduplication
- references from alerts
- forensic notes
- evidence export
- replay detection
- ingestion troubleshooting
Do not use a user ID, request ID, or timestamp alone as the unique event identifier.
Event Types
Use stable, machine-readable event names.
Examples:
mcp.session.initialized
mcp.authorization.succeeded
mcp.authorization.denied
mcp.tool.requested
mcp.tool.approval.requested
mcp.tool.approval.granted
mcp.tool.execution.started
mcp.tool.execution.completed
mcp.tool.execution.failed
mcp.resource.read
mcp.prompt.retrieved
mcp.sampling.requested
mcp.elicitation.requested
mcp.server.configuration.changed
mcp.client.registration.created
mcp.security.token_rejected
Avoid using free-form English sentences as the only event classification.
Schema Version
Audit event schemas change over time.
Include:
{
"event_version": "1.2"
}
Schema versioning supports:
- parsers
- migrations
- dashboards
- backward compatibility
- evidence interpretation
- long-term retention
A stored event should remain understandable after the producing service has been upgraded.
Timestamps
Use a precise, unambiguous timestamp.
Recommended representation:
2026-07-20T15:42:18.613Z
Record timestamps in UTC.
Additional fields may include:
{
"timestamp": "2026-07-20T15:42:18.613Z",
"observed_timestamp": "2026-07-20T15:42:18.702Z",
"duration_ms": 89
}
Event Time
When the action occurred.
Observed Time
When the logging or collection system received it.
The difference can reveal:
- delayed delivery
- queue backlog
- clock problems
- offline processing
- replayed records
Clock Synchronization
A multi-system MCP workflow depends on reliable time.
Authorization Server:
15:42:18.100
MCP Gateway:
15:42:17.450
MCP Server:
15:42:19.900
Incorrect clocks can make events appear in the wrong order.
Systems should use authenticated and monitored time synchronization where practical.
Audit monitoring should detect:
- large clock drift
- timestamps from the future
- timestamps older than expected
- repeated timestamps
- sudden clock changes
Correlation IDs
A correlation ID connects events belonging to one logical workflow.
MCP Host
corr-123
│
▼
Authorization Server
corr-123
│
▼
Gateway
corr-123
│
▼
MCP Server
corr-123
│
▼
Downstream API
corr-123
Each system should also retain its own local identifiers.
Example:
{
"correlation_id": "corr-123",
"mcp_request_id": 42,
"gateway_request_id": "gw-789",
"downstream_request_id": "api-456"
}
Correlation IDs Are Not Authentication
A caller may supply:
X-Correlation-ID: administrator-approved
This value does not prove anything.
Correlation identifiers should be:
- generated by a trusted entry point
- validated for length and format
- replaced when invalid
- propagated in controlled fields
- excluded from authorization decisions
They help connect events.
They do not establish user, client, or approval identity.
Trace IDs and Span IDs
Distributed tracing may already provide:
- trace ID
- span ID
- parent span ID
{
"trace_id": "78f563...",
"span_id": "014ac9...",
"parent_span_id": "01d532..."
}
These can support audit correlation.
However, general tracing may:
- sample events
- omit denied requests
- retain data briefly
- expose detailed payloads
- allow developers broad access
- be disabled under load
Security audit logging should not depend exclusively on sampled traces.
User Identity
An audit record should capture the authenticated actor.
Example:
{
"actor": {
"type": "human",
"subject_id": "usr_8421",
"tenant_id": "tenant-a",
"authentication_context": "phishing_resistant_mfa"
}
}
Prefer stable internal identifiers.
Email addresses and display names may change and may contain personal data.
Where useful, store:
- stable user ID
- tenant or organization
- role at decision time
- authentication strength
- acting administrator
- effective user
Actor vs Subject
Some actions involve delegation or impersonation.
Actor:
support-admin-42
Subject:
customer-user-123
A correct record should preserve both.
{
"actor": {
"subject_id": "support-admin-42",
"type": "administrator"
},
"effective_subject": {
"subject_id": "customer-user-123"
},
"delegation": {
"type": "support_impersonation",
"reason_code": "case-9182"
}
}
Recording only the effective user would hide the administrator who actually acted.
MCP Client Identity
The same user may use several clients.
{
"client": {
"client_id": "enterprise-agent",
"client_name": "Enterprise AI Agent",
"registration_type": "preregistered",
"verification_status": "approved"
}
}
Useful fields include:
- OAuth
client_id - client registration type
- publisher or software ID
- software version
- verification status
- device or installation identifier where permitted
A client-provided display name should not replace the actual client_id.
Host and MCP Client Separation
MCP architecture distinguishes the host application from the individual client connection.
Host:
AI desktop application
Client:
Connection to Finance MCP
Client:
Connection to Documentation MCP
Audit records may preserve both:
{
"host": {
"application_id": "desktop-ai",
"version": "8.2.0"
},
"client": {
"connection_id": "conn-finance-739",
"oauth_client_id": "desktop-ai-prod"
}
}
This helps analyze multi-server workflows.
Workload Identity
For remote deployments, log the authenticated service identity.
{
"workload": {
"identity": "spiffe://example.com/ns/finance/sa/mcp",
"environment": "production",
"region": "eu-central",
"instance_id": "pod-7c8499",
"artifact_digest": "sha256:..."
}
}
Possible fields include:
- service account
- certificate identity
- cloud workload principal
- namespace
- cluster
- instance
- deployment version
- container image digest
Do not rely only on a source IP address.
MCP Resource Identity
Record the exact MCP Resource Server targeted by the token and request.
{
"resource": {
"resource_server": "https://finance-mcp.example.com",
"server_name": "finance-mcp",
"environment": "production"
}
}
This helps prove that authorization was bound to the intended resource.
A log entry containing only:
audience valid
is less useful than recording the validated resource identifier.
OAuth Authorization Context
An MCP audit record should preserve useful authorization facts without storing the token.
Example:
{
"authorization": {
"issuer": "https://auth.example.com",
"audience": "https://finance-mcp.example.com",
"scopes": [
"invoices:read",
"invoices:create"
],
"token_type": "Bearer",
"token_id": "jti-8c239",
"token_fingerprint": "sha256:7c5d...",
"expires_at": "2026-07-20T15:50:00Z"
}
}
Where available, useful values include:
- issuer
- audience
- scopes
- token identifier
- authentication context
- grant or delegation ID
- expiration
- client ID
- tenant
Never store the raw Access Token.
Token Fingerprints
A non-reversible token fingerprint can help correlate use of the same token.
Conceptually:
fingerprint =
HMAC(audit-specific secret, token)
Prefer a keyed construction rather than a plain hash when token entropy or implementation conditions might permit guessing.
The fingerprint should:
- not allow token recovery
- use an audit-specific key
- support rotation
- avoid becoming an authentication credential
- be accessible only where required
Do Not Log Authorization Headers
Unsafe:
Authorization: Bearer eyJhbGciOi...
Also unsafe:
{
"headers": {
"authorization": "Bearer ..."
}
}
HTTP middleware that logs every request header can silently expose:
- Access Tokens
- API keys
- cookies
- Basic credentials
- signed client assertions
Use explicit allowlists for logged headers rather than attempting to blacklist every sensitive header.
Sensitive OAuth Events to Audit
Relevant Authorization Server events include:
- authorization request received
- client validation succeeded or failed
- redirect URI rejected
- user authentication succeeded or failed
- consent granted or denied
- incremental scope requested
- authorization code issued
- authorization code redeemed
- token issued
- Refresh Token rotated
- Refresh Token replay detected
- token revoked
- client registration created
- registration metadata changed
- client suspended
- signing key changed
These events should correlate with the later MCP request where possible.
Tool Discovery Events
Audit relevant changes and access to the tool catalog.
Possible events:
mcp.tools.list.requested
mcp.tools.list.completed
mcp.tools.catalog.changed
mcp.tool.added
mcp.tool.removed
mcp.tool.schema.changed
Why tool discovery matters:
- a compromised server may expose new tools
- a software update may add destructive capability
- a client may enumerate tools it has never used
- a schema change may broaden permitted arguments
A catalog hash can help detect changes.
{
"tool_catalog": {
"tool_count": 18,
"schema_digest": "sha256:...",
"server_version": "4.8.1"
}
}
Tool Request Events
A tool request event should describe the requested action before execution.
Example:
{
"event_type": "mcp.tool.requested",
"operation": {
"tool_name": "create_invoice",
"operation_class": "write",
"risk_level": "high",
"target_type": "customer_account",
"target_id": "customer-456"
},
"authorization": {
"required_scopes": [
"invoices:create"
],
"granted_scopes": [
"invoices:create"
]
}
}
This event is different from execution success.
A request may later be:
- denied
- cancelled
- modified
- approved
- timed out
- executed unsuccessfully
Tool Arguments
Tool arguments may contain:
- credentials
- personal data
- confidential documents
- source code
- legal information
- payment data
- injected instructions
- large binary content
Do not log every argument automatically.
Use a field policy for each tool.
Example:
{
"argument_audit": {
"customer_id": "customer-456",
"currency": "EUR",
"amount_minor": 150000,
"description": "[REDACTED]",
"attachment": {
"logged": false,
"sha256": "..."
}
}
}
Tool-Specific Audit Schemas
Define allowed audit fields per tool.
Example:
Tool:
send_email
Log:
message ID
sender account
recipient domains
recipient count
attachment count
classification
approval ID
outcome
Do not log by default:
full subject
full body
attachment contents
authentication headers
Another example:
Tool:
read_file
Log:
normalized path category
approved root
file fingerprint
bytes returned
classification
Do not log by default:
full file contents
secret values
entire home-directory path
Normalized Targets
Raw arguments may represent the same resource in several forms.
./documents/report.pdf
/home/user/project/documents/report.pdf
documents/../documents/report.pdf
Audit the normalized target used by authorization and execution.
{
"requested_path": "documents/../documents/report.pdf",
"normalized_target": "/approved/project/documents/report.pdf",
"approved_root": "/approved/project"
}
This helps investigate path traversal attempts.
Record Requested and Executed Actions Separately
A model or intermediary may transform arguments.
Requested:
Delete staging database
Executed:
Delete production database
A secure audit chain should preserve both.
{
"requested_operation": {
"environment": "staging",
"resource_id": "db-test"
},
"executed_operation": {
"environment": "production",
"resource_id": "db-prod"
},
"arguments_changed": true
}
Unexpected differences should trigger an alert.
Authorization Decision Events
Record the decision before execution.
Example:
{
"event_type": "mcp.authorization.decision",
"decision": "deny",
"reason_code": "missing_scope",
"policy_id": "finance-tool-policy",
"policy_version": "19",
"required_scopes": [
"payments:create"
],
"granted_scopes": [
"payments:read"
]
}
Use stable reason codes.
Useful examples:
invalid_token
wrong_audience
untrusted_issuer
missing_scope
client_not_approved
tenant_mismatch
object_not_authorized
step_up_required
approval_required
policy_denied
rate_limited
data_transfer_prohibited
Policy Version
The authorization decision depends on the policy active at that time.
Store:
{
"policy": {
"policy_id": "production-deployment-policy",
"version": "42",
"decision": "allow"
}
}
Without the version, investigators may evaluate an old event against current rules and reach the wrong conclusion.
Approval Events
High-risk tool calls may require user or administrator approval.
Record:
- approval requested
- approval displayed
- approval granted or denied
- approver identity
- exact action digest
- expiration
- number of allowed uses
- execution linked to approval
Example:
{
"event_type": "mcp.tool.approval.granted",
"approval_id": "approval-9182",
"approver": {
"subject_id": "user-123"
},
"action_digest": "sha256:...",
"tool_name": "delete_resource",
"target_id": "resource-456",
"expires_at": "2026-07-20T15:44:00Z",
"max_uses": 1
}
Approval Display Evidence
A user can approve only what was meaningfully presented.
Where risk justifies it, preserve a sanitized representation of the approval screen:
{
"approval_display": {
"template_version": "3.2",
"summary": "Delete production resource resource-456",
"risk_label": "irreversible",
"destination": "production-eu",
"action_digest": "sha256:..."
}
}
Do not automatically store a full screenshot containing personal or secret data.
Bind Execution to Approval
Execution should reference the exact approval.
{
"event_type": "mcp.tool.execution.started",
"approval": {
"approval_id": "approval-9182",
"action_digest_match": true,
"approval_age_seconds": 22,
"use_number": 1
}
}
Alert when:
- approval is expired
- action digest differs
- approval was already used
- approver is not authorized
- tenant differs
- client differs
- tool differs
Tool Execution Events
Execution events should distinguish:
Requested
Authorized
Started
Completed
Failed
Cancelled
Timed out
Example:
{
"event_type": "mcp.tool.execution.completed",
"operation": {
"tool_name": "create_invoice",
"target_id": "invoice-789"
},
"outcome": {
"status": "success",
"duration_ms": 842,
"records_affected": 1
}
}
Do not record success merely because the MCP server returned HTTP 200.
The downstream operation may still have failed.
Partial Success
Some tools perform multiple actions.
Upload 10 files
8 succeeded
2 failed
Audit the partial result explicitly.
{
"outcome": {
"status": "partial_success",
"requested_items": 10,
"succeeded_items": 8,
"failed_items": 2
}
}
A generic success: true would hide important information.
Idempotency and Duplicate Execution
Retries can create duplicate actions.
Record:
- idempotency key
- retry count
- previous request reference
- duplicate detection result
- downstream transaction ID
{
"execution": {
"idempotency_key": "idem-9821",
"attempt": 2,
"duplicate_detected": true,
"original_event_id": "evt-original"
}
}
This is especially important for:
- payments
- email sending
- ticket creation
- deployments
- destructive actions
- durable tasks
MCP Resource Access Events
Resources may expose files, documents, database content, or generated context.
Audit events may include:
mcp.resource.listed
mcp.resource.read
mcp.resource.subscribed
mcp.resource.updated
A resource-read record may contain:
{
"event_type": "mcp.resource.read",
"resource": {
"uri": "document://customer-456/report",
"classification": "confidential",
"tenant_id": "tenant-a"
},
"outcome": {
"bytes_returned": 18422,
"records_returned": 1
}
}
Avoid placing the complete resource content in the audit log.
Prompt Access Events
MCP prompts are user-controlled templates, but they may still contain:
- internal instructions
- proprietary workflows
- user data
- generated variables
- sensitive context
Audit:
- prompt identifier
- prompt version
- requester
- argument names or sanitized values
- result size
- destination
- outcome
Example:
{
"event_type": "mcp.prompt.retrieved",
"prompt": {
"name": "customer-risk-review",
"version": "7",
"argument_names": [
"customer_id",
"review_type"
]
}
}
Do not automatically record the complete rendered prompt.
Sampling Events
Sampling allows an MCP server to request model generation through the client.
Relevant events include:
- sampling requested
- sampling approved
- sampling denied
- context inclusion selected
- model selected
- request sent
- response returned
- response shared with server
Useful fields include:
{
"event_type": "mcp.sampling.completed",
"sampling": {
"requesting_server": "analysis-mcp",
"model_provider": "approved-provider",
"model_id": "model-family",
"context_mode": "thisServer",
"input_classification": "internal",
"input_tokens": 2180,
"output_tokens": 612
}
}
Full prompts and model responses should require a separate data-retention decision.
Elicitation Events
Elicitation allows an MCP server to request additional user information.
Audit:
- requesting server
- requested field types
- whether sensitive fields were requested
- user approval
- validation result
- whether values were returned
- destination
Do not log submitted secrets or personal values by default.
Example:
{
"event_type": "mcp.elicitation.completed",
"elicitation": {
"field_names": [
"project_name",
"deployment_region"
],
"sensitive_fields_requested": false,
"user_submitted": true
}
}
Durable Task Audit Events
The 2025-11-25 MCP specification introduced experimental tasks for durable requests, polling, and deferred result retrieval.
Relevant events include:
mcp.task.created
mcp.task.status_changed
mcp.task.polled
mcp.task.cancel_requested
mcp.task.cancelled
mcp.task.completed
mcp.task.expired
mcp.task.result_retrieved
A task may outlive the original connection.
Its audit record should preserve:
- original user
- original client
- authorization context
- task owner
- creation time
- status transitions
- result retrieval
- cancellation actor
- expiration
Authorization for Long-Running Tasks
A task created under valid authorization may complete after:
- the token expires
- the user loses permission
- the client is revoked
- the tenant membership changes
The audit trail should show which policy applies:
{
"task_authorization": {
"mode": "authorization_snapshot_at_creation",
"original_decision_event_id": "evt-auth-123"
}
}
or:
{
"task_authorization": {
"mode": "continuous_reevaluation",
"last_reevaluated_at": "2026-07-20T16:00:00Z"
}
}
This behavior should be explicit rather than accidental.
Downstream API Events
The MCP server may call another service.
MCP Tool
│
▼
Credential Broker
│
▼
Downstream API
Audit enough information to connect the external effect:
{
"downstream": {
"service": "billing-api",
"operation": "POST /invoices",
"credential_identity": "finance-mcp-invoice-role",
"request_id": "billing-req-9182",
"resource_id": "invoice-789",
"status_code": 201
}
}
Do not log:
- upstream API token
- complete authorization headers
- secret request parameters
- full customer payload unless specifically justified
Credential Broker Events
Where a credential broker issues temporary access, audit:
- requesting workload
- user context
- tool
- downstream resource
- credential profile
- policy decision
- lifetime
- issuance success
- revocation
Example:
{
"event_type": "credential.issued",
"credential": {
"profile": "billing-invoice-create",
"audience": "billing-api",
"lifetime_seconds": 300,
"credential_fingerprint": "sha256:..."
}
}
The credential itself must remain outside the log.
Data Movement Events
An MCP workflow can move information between servers.
CRM MCP
│
Customer Data
│
▼
Model Context
│
▼
Email MCP
Audit the transfer as a distinct event.
{
"event_type": "mcp.data.transfer",
"source": {
"server": "crm-mcp",
"classification": "confidential",
"tenant_id": "tenant-a"
},
"destination": {
"server": "email-mcp",
"destination_class": "external_saas"
},
"data": {
"record_count": 24,
"fields": [
"customer_email",
"account_status"
],
"bytes": 8940
},
"decision": "allow_with_redaction"
}
Two individually permitted tool calls can still create an unauthorized combined transfer.
Data Classification
Audit records should preserve classification without copying the protected content.
Possible values:
public
internal
confidential
restricted
regulated
secret
Example:
{
"data": {
"classification": "restricted",
"contains_personal_data": true,
"contains_credentials": false,
"contains_source_code": false
}
}
This supports:
- DLP
- access control
- retention
- alerting
- incident prioritization
Data Volume
Record useful volume indicators.
Examples:
- records read
- records modified
- bytes returned
- files accessed
- recipients
- rows exported
- tokens sent to a model
{
"data_volume": {
"records_read": 10000,
"bytes_returned": 8240012
}
}
Volume anomalies can reveal:
- scraping
- exfiltration
- runaway agents
- broken pagination
- malicious automation
Audit High-Risk Denials
Denied operations are often as important as successful actions.
Audit:
- wrong audience
- invalid issuer
- missing scope
- cross-tenant request
- path traversal
- blocked destination
- approval mismatch
- rate-limit violation
- prohibited data transfer
- disabled user
- suspended client
{
"event_type": "mcp.security.request_denied",
"reason_code": "wrong_audience",
"expected_audience": "https://finance-mcp.example.com",
"presented_audience": "https://docs-mcp.example.com"
}
Do not include the raw rejected token.
Authentication Failures
Record enough information to detect attacks without enabling account enumeration.
Possible fields:
{
"event_type": "authentication.failed",
"reason_code": "invalid_credential",
"account_reference": "non_reversible_reference",
"client_id": "enterprise-agent",
"source": {
"network_zone": "external",
"ip_prefix": "203.0.113.0/24"
}
}
The user-facing response may remain generic while internal logs use a more specific reason.
Rate-Limit Events
Audit significant rate-limit actions:
{
"event_type": "mcp.rate_limit.exceeded",
"limit_policy": "tool-delete-10-per-hour",
"subject_id": "user-123",
"client_id": "enterprise-agent",
"tool_name": "delete_resource",
"observed_count": 14
}
Avoid logging every harmless throttled retry if that creates overwhelming noise.
Aggregate where appropriate.
Server Lifecycle Events
Audit:
- server startup
- server shutdown
- configuration loaded
- policy loaded
- tool catalog loaded
- artifact version
- network policy changed
- secret reference changed
- health degradation
- logging pipeline failure
Example:
{
"event_type": "mcp.server.started",
"service_name": "finance-mcp",
"service_version": "4.8.1",
"artifact_digest": "sha256:...",
"policy_version": "42",
"tool_catalog_digest": "sha256:..."
}
This helps identify which code and policy handled an event.
Configuration Changes
Configuration changes may alter:
- authorization
- tool availability
- allowed filesystem paths
- network destinations
- tenants
- credentials
- logging behavior
- retention
- redaction
Audit before and after values where safe.
{
"event_type": "mcp.configuration.changed",
"change": {
"field": "allowed_egress_domains",
"before_digest": "sha256:...",
"after_digest": "sha256:...",
"change_ticket": "SEC-9182"
},
"actor": {
"subject_id": "admin-42"
}
}
Do not store secret values in configuration diffs.
Tool Catalog Changes
Adding a tool can create new execution capability.
Audit:
- tool added
- tool removed
- schema changed
- annotation changed
- required scope changed
- risk classification changed
- approval requirement changed
{
"event_type": "mcp.tool.schema.changed",
"tool_name": "deploy_service",
"old_schema_digest": "sha256:...",
"new_schema_digest": "sha256:...",
"risk_change": {
"before": "medium",
"after": "high"
}
}
A changed tool description is also relevant because the model and user may rely on it.
Administrative Events
Audit administrative actions such as:
- client approval
- user suspension
- scope assignment
- policy override
- log export
- retention change
- alert suppression
- audit-record deletion request
- emergency access
- impersonation
Administrative records should include:
- administrator identity
- reason
- ticket or case
- affected object
- previous state
- new state
- approval chain
Break-Glass Access
Emergency access should generate enhanced audit records.
{
"event_type": "administration.break_glass_activated",
"actor": {
"subject_id": "admin-42"
},
"reason": "production incident INC-9182",
"scope": "deployment-mcp:admin",
"expires_at": "2026-07-20T17:00:00Z",
"approver_count": 2
}
Break-glass access should be:
- time-limited
- narrow
- highly visible
- reviewed afterward
- excluded from routine use
Audit Access Events
Audit logs themselves contain sensitive information.
Record:
- who searched logs
- which tenant or time range
- which fields were exported
- which case justified access
- whether raw payload evidence was viewed
- whether records were downloaded
{
"event_type": "audit.records.exported",
"actor": {
"subject_id": "security-analyst-17"
},
"query_scope": {
"tenant_id": "tenant-a",
"start": "2026-07-20T15:00:00Z",
"end": "2026-07-20T16:00:00Z"
},
"case_id": "INC-9182",
"record_count": 842
}
Access to audit evidence should itself be auditable.
What Must Never Be Logged
Do not write reusable secrets into MCP audit logs.
This includes:
- Access Tokens
- Refresh Tokens
- authorization codes
- Client Secrets
- Initial Access Tokens
- Registration Access Tokens
- private keys
- session cookies
- passwords
- one-time codes
- API keys
- database passwords
- full authentication headers
The MCP logging specification also warns against sending credentials, secrets, personally identifying information, or internal details that could aid attacks through server log notifications.
Data That Requires Careful Treatment
The following may sometimes be logged, but not by default in full:
- prompts
- model responses
- tool arguments
- tool results
- resource contents
- filenames
- URLs with query parameters
- email addresses
- IP addresses
- customer identifiers
- document titles
- database queries
- stack traces
- internal hostnames
- approval screenshots
Use:
- redaction
- hashing
- tokenization
- classification
- structured summaries
- controlled evidence vaults
- shorter retention
Redaction
Redaction should happen before data reaches the normal log pipeline.
Unsafe:
Application logs token
│
Collector later redacts it
The secret may already exist in:
- local files
- container output
- process buffers
- sidecar logs
- crash reports
- temporary queues
Safer:
Application constructs safe event
│
▼
Audit pipeline receives sanitized fields
Allowlist Logging
Prefer defining fields that may be logged.
Allowed:
tool name
target ID
record count
outcome
duration
Not included:
everything else
This is safer than attempting to detect every possible secret in arbitrary payloads.
Redaction Failure Detection
Automated scanners can detect patterns such as:
- Bearer Tokens
- private-key headers
- cloud-access keys
- authorization codes
- passwords in URLs
- session cookies
When detected:
- block or quarantine the event
- generate a security alert
- remove exposed data
- rotate affected credentials
- investigate the source
- verify downstream copies
Pattern detection is a safety net, not a replacement for safe event construction.
Log Injection
Untrusted values may contain:
- newline characters
- terminal escape sequences
- fake timestamps
- JSON fragments
- HTML
- spreadsheet formulas
- control characters
Example attacker input:
normal-value
2026-07-20 ALLOW administrator action
If written into unstructured logs, it may create fake entries.
Mitigations:
- structured JSON
- length limits
- control-character handling
- contextual output encoding
- safe terminal display
- safe CSV export
- no raw HTML rendering
Structured Logging
Structured logs are easier to validate and search.
Prefer:
{
"event_type": "mcp.tool.execution.failed",
"tool_name": "create_invoice",
"reason_code": "downstream_timeout",
"duration_ms": 30000
}
Instead of:
Invoice tool failed for some reason after waiting.
Free-form messages may still be included for humans, but machine-readable fields should carry the authoritative meaning.
Severity vs Audit Importance
MCP logging uses syslog-style severity levels.
Audit systems may additionally classify:
- security impact
- compliance relevance
- operational priority
- investigation urgency
Example:
{
"severity": "notice",
"security_priority": "high",
"event_type": "mcp.client.scope_expanded"
}
A normal administrative change may not be a technical error, but it can still be security-critical.
Suggested Severity Mapping
Debug
Detailed development diagnostics that should normally be disabled in production.
Info
Routine successful activity.
Notice
Important normal events such as client registration or configuration activation.
Warning
Suspicious, deprecated, or recoverable conditions.
Error
Failed operations requiring investigation.
Critical
Failure of an important security or service component.
Alert
Immediate response required.
Emergency
System-wide inability to operate securely.
The RFC 5424 severity model defines these levels from emergency through debug.
Audit Logging Failure
The application must decide what happens when the audit pipeline fails.
Possible strategies:
Fail Closed
Reject high-risk operations when authoritative auditing is unavailable.
Appropriate for:
- payments
- privilege changes
- production deletion
- regulated administration
- break-glass access
Buffered Operation
Write to a protected local queue and forward later.
Appropriate when temporary disconnection is expected and storage is reliable.
Continue With Alert
Permit lower-risk actions while raising an urgent operational alert.
The choice should depend on event risk.
Never Fail Silently
Unsafe:
Audit collector unavailable
│
▼
Application continues
│
▼
No alert
Safer:
Audit collector unavailable
│
├── Health signal
├── Local protected buffer
├── Operations alert
├── Capacity limit
└── Defined fail behavior
Audit-pipeline status should itself be monitored and recorded.
Audit Event Delivery
Possible delivery models include:
- synchronous API
- local append-only file
- system journal
- message queue
- event stream
- sidecar collector
- agent
- cloud logging service
A common design is:
MCP Application
│
Safe Structured Event
│
▼
Local Collector
│
▼
Durable Queue
│
▼
Central Audit Store
│
▼
SIEM and Archive
The application should not block indefinitely while sending logs.
Local Buffering
Local buffering protects against short outages.
The buffer should have:
- encryption
- disk quota
- restricted permissions
- ordered delivery
- retry
- duplicate handling
- corruption detection
- overflow policy
A full disk should not allow an attacker to silently disable future audit records.
Backpressure
An attacker may generate huge numbers of events.
Malicious requests
│
▼
Millions of audit records
│
▼
Logging pipeline overloaded
Controls include:
- rate limits
- aggregation
- priority queues
- separate security channels
- capacity reservations
- bounded diagnostic logging
- preserving high-value audit events
Do not sample away critical authorization failures or destructive actions merely because volume is high.
Duplicate Events
At-least-once delivery may create duplicates.
Use:
- unique event IDs
- producer sequence numbers
- idempotent ingestion
- deduplication windows
- source identifiers
Do not assume two similar events are duplicates merely because their timestamps and tool names match.
Missing Events and Sequence Gaps
A producer may maintain a monotonic sequence:
{
"producer_id": "finance-mcp-instance-7",
"sequence": 9182
}
The collector can detect:
9180
9181
9183
Missing 9182 may indicate:
- delivery failure
- process crash
- tampering
- queue corruption
Sequence numbers require careful handling across restarts and multiple instances.
Audit Log Integrity
An attacker who compromises an MCP server may try to:
- delete records
- alter outcomes
- change user identities
- remove failed requests
- fabricate approvals
- hide data exports
Audit records should leave the application environment quickly.
MCP Server
│
▼
Separate Audit Domain
The server should not have permission to modify or delete previously stored central events.
Append-Oriented Storage
Audit stores should prefer append-oriented behavior.
The producing service may:
Create new event
but should not:
Update historical event
Delete historical event
Corrections should be represented as new events referencing the original record.
{
"event_type": "audit.correction",
"original_event_id": "evt-123",
"reason": "downstream status reconciled",
"corrected_outcome": "partial_success"
}
Cryptographic Integrity
Possible integrity controls include:
- event hashes
- hash chains
- digital signatures
- signed batches
- Merkle trees
- immutable storage
- external timestamping
Conceptual hash chain:
Event 1 hash
│
▼
Event 2 includes previous hash
│
▼
Event 3 includes previous hash
A gap or modification becomes detectable.
Cryptographic integrity does not prevent deletion unless external checkpoints or independent copies exist.
Signing Audit Events
A producer may sign events using a workload-specific key.
{
"event_id": "evt-123",
"payload_digest": "sha256:...",
"signature": "...",
"signing_identity": "finance-mcp-prod"
}
Key management must ensure:
- private keys are protected
- keys are rotated
- verification keys are retained
- compromise times are known
- algorithms are restricted
- signing does not expose application secrets
A compromised workload with access to its signing key can still sign false events.
Independent collection and runtime telemetry remain important.
Separation of Duties
The people who operate the MCP service should not automatically have unrestricted power over its audit evidence.
Separate roles may include:
- MCP service operator
- audit platform administrator
- security analyst
- compliance reviewer
- privacy officer
- retention administrator
Service Operator:
Can run MCP service
Audit Administrator:
Can manage storage
Security Analyst:
Can search approved events
No single role:
Can alter service and erase evidence
Encryption
Protect audit data:
In Transit
Use authenticated encrypted transport between:
- application and collector
- collector and queue
- queue and storage
- storage and analysis tools
At Rest
Encrypt:
- local buffers
- central indexes
- archives
- backups
- evidence exports
Encryption keys should be separated from ordinary application credentials.
Audit Log Access Control
Audit records may reveal:
- customer activity
- internal resource names
- employee behavior
- security incidents
- system architecture
- privileged actions
Use fine-grained access controls based on:
- role
- tenant
- investigation case
- data classification
- time range
- field sensitivity
- purpose
A developer debugging one MCP server should not automatically see every tenant's complete audit history.
Field-Level Access
Some users may see:
event type
time
tool
outcome
duration
while only authorized investigators see:
user identity
target identifier
network details
sanitized argument evidence
Field-level controls reduce unnecessary exposure.
Multi-Tenant Audit Isolation
Every event should contain authoritative tenant context.
{
"tenant": {
"tenant_id": "tenant-a",
"source": "validated_authorization_context"
}
}
Audit queries must enforce tenant isolation.
Unsafe:
tenant filter supplied only by UI
Safer:
tenant access enforced by backend policy
and storage controls
A compromised tenant administrator must not retrieve another tenant's records by changing a query parameter.
Shared Infrastructure Events
Some events may relate to multiple tenants or no single tenant.
Examples:
- Authorization Server signing-key rotation
- global policy change
- shared MCP server outage
- audit pipeline failure
Use explicit scope:
{
"tenant_scope": "global"
}
Do not assign shared events to an arbitrary customer tenant.
Privacy and Data Minimization
Audit logging creates a new collection of data.
The log system should not become an uncontrolled copy of:
- prompts
- customer documents
- model outputs
- email bodies
- source repositories
- personal information
- credentials
Record only what is necessary for defined purposes.
NIST log-management guidance treats retention, access, storage, analysis, and disposal as parts of the log lifecycle rather than treating collection as the only concern.
Purpose Limitation
Define why each category is collected.
Example:
| Field | Purpose |
|---|---|
| User ID | Accountability and investigation |
| Client ID | Client abuse detection |
| Tool name | Action reconstruction |
| Target ID | Resource impact analysis |
| Record count | Exfiltration detection |
| Full prompt | Not collected by default |
Fields without a clear purpose should be challenged.
Pseudonymization
Some audit use cases may not require directly identifiable user information.
Possible design:
{
"actor_reference": "hmac:8ac9..."
}
A separate controlled service may resolve the reference during an authorized investigation.
Pseudonymization reduces routine exposure but does not make the data anonymous when reidentification remains possible.
IP Addresses
IP addresses can support:
- attack detection
- geographic anomaly analysis
- network investigation
- abuse prevention
They may also be personal or sensitive data.
Possible minimization includes:
- prefix truncation
- regional classification
- shorter retention
- separate restricted fields
- storing only where risk justifies it
Security requirements and privacy obligations must be balanced deliberately.
Retention
There is no universal retention period for MCP audit logs.
Different categories may have different periods.
Example:
High-risk administrative actions:
Longer retention
Verbose diagnostic logs:
Short retention
Raw sensitive evidence:
Very short, case-controlled retention
Aggregated security metrics:
Longer retention
Retention should consider:
- incident detection window
- regulatory obligations
- customer contracts
- legal holds
- privacy requirements
- storage cost
- data sensitivity
- usefulness of old records
Retention Tiers
A tiered model may use:
Hot
Fast searchable storage for recent events.
Warm
Lower-cost searchable storage.
Cold
Long-term archive.
Evidence Vault
Restricted storage for selected incident evidence.
Recent Events
│
Hot
│
Warm
│
Cold Archive
Moving an event between tiers should preserve integrity and schema information.
Disposal
Expired audit data should be disposed of according to policy.
Disposal should include:
- primary storage
- replicas
- indexes
- caches
- local buffers
- exports
- backups where applicable
Deletion events may themselves require records.
{
"event_type": "audit.retention.disposal_completed",
"policy_id": "audit-retention-v7",
"period_end": "2025-07-01",
"records_affected": 482102
}
Do not include the deleted sensitive records in the disposal event.
Legal Holds
A legal or investigation hold may suspend normal deletion.
The hold should be:
- authorized
- narrowly scoped
- documented
- reviewed
- removed when no longer needed
{
"event_type": "audit.legal_hold.applied",
"case_id": "CASE-9182",
"scope": {
"tenant_id": "tenant-a",
"start": "2026-07-01T00:00:00Z",
"end": "2026-07-20T23:59:59Z"
}
}
Audit Search Requirements
Investigators should be able to search by:
- event ID
- correlation ID
- user
- client ID
- MCP server
- tool
- resource
- tenant
- token fingerprint
- approval ID
- downstream request ID
- time range
- outcome
- reason code
- data classification
A log archive that cannot be searched during an incident provides limited value.
Audit Timeline Reconstruction
A timeline may show:
15:42:18.100
User authenticated
15:42:18.320
Authorization granted
15:42:18.560
Tool requested
15:42:18.590
Policy allowed
15:42:25.200
User approved
15:42:25.310
Credential issued
15:42:25.450
Downstream request sent
15:42:26.118
Invoice created
The timeline should preserve both system-local IDs and shared correlation.
Expected MCP Audit Architecture
A production architecture may look like:
Identity Provider
│
Authorization Server
│
MCP Host and Client
│
Gateway
│
Policy Engine
│
MCP Server
│
Credential Broker
│
Downstream APIs
│
└──────────────┐
▼
Local Collectors
│
▼
Durable Queue
│
▼
Central Audit Store
│
┌──────┴──────┐
▼ ▼
SIEM Immutable Archive
Each component emits the events for which it is authoritative.
Do Not Trust One Producer for Everything
The MCP server may report:
Tool allowed
Tool executed
Downstream succeeded
Independent systems should contribute their own evidence.
Policy engine:
Decision allowed
Credential broker:
Credential issued
Downstream API:
Resource created
Audit collector:
Events received
This reduces reliance on one potentially compromised component.
First Implementation Priorities
A practical first implementation should:
- Define a stable audit-event schema.
- Generate unique event and correlation IDs.
- Record verified user, client, resource, tenant, tool, decision, and outcome.
- Create tool-specific argument allowlists.
- remove tokens, secrets, and complete prompts from logs.
- record authorization and approval decisions separately from execution.
- correlate downstream effects.
- send events to storage outside the MCP process.
- alert on logging failure.
- test whether investigators can reconstruct one complete high-risk action.
A small, reliable audit trail is better than an enormous unsafe dump of every prompt and payload.
SIEM Integration
An audit trail becomes significantly more valuable when events from multiple systems are analyzed together.
A Security Information and Event Management (SIEM) platform can combine events from:
- Identity Provider
- Authorization Server
- MCP Host
- MCP Client
- MCP Gateway
- Policy Engine
- MCP Server
- Credential Broker
- Kubernetes
- Service Mesh
- Cloud Platform
- Downstream APIs
- Endpoint Detection
- Firewall
- DNS
- Email Security
Identity
│
Authorization
│
MCP
│
Runtime
│
Network
│
Cloud
│
▼
SIEM
A single MCP event may appear harmless.
Multiple correlated events may reveal an active compromise.
Correlation Rules
Rather than evaluating events independently, a SIEM should connect related activities.
Example:
Authentication
↓
Token Issued
↓
New MCP Client
↓
High-Risk Tool
↓
Large Export
↓
Unknown Destination
Individually:
All events appear valid.
Combined:
Possible data exfiltration.
Multi-Stage Attack Detection
Example sequence:
User Login
↓
Client Registration
↓
Tool Discovery
↓
Privilege Escalation Attempt
↓
Resource Enumeration
↓
Bulk Export
↓
External Transfer
The individual events may span:
- several servers
- several minutes
- multiple identities
- several network zones
Only correlation exposes the complete attack.
Impossible Travel
If authentication events contain geographic information:
09:00
Warsaw
09:18
Singapore
the SIEM may detect:
- impossible travel
- stolen session
- proxy abuse
- credential theft
Geographic detection should account for:
- VPN usage
- corporate proxies
- cloud egress
- remote workers
Unusual Client Behavior
Normal usage:
Documentation Client
↓
Reads Documentation
↓
Occasional Search
Unexpected:
Documentation Client
↓
Finance Tools
↓
Admin Tools
↓
Mass Export
Even with valid tokens, behavior may indicate compromise.
First-Time Events
Alert when something happens for the first time.
Examples:
- new client
- new tool
- new destination
- new tenant combination
- new country
- new workload
- new cloud region
- new administrator
- new approval pattern
Baseline awareness often detects attacks earlier than signature-based rules.
Behavioral Baselines
For every MCP server establish:
- expected users
- expected tools
- expected request frequency
- expected data volume
- expected destinations
- expected working hours
- expected tenants
- expected approval frequency
Example:
Typical:
40 invoice reads/day
Observed:
18,000 invoice reads
That difference deserves investigation.
Tool Frequency Monitoring
Record typical invocation frequency.
delete_document
Normal:
2/day
Observed:
900/hour
Possible causes include:
- automation bug
- compromised agent
- malicious workflow
- infinite retry
- prompt injection
High-Risk Tool Monitoring
Assign a risk level to every tool.
Example:
Low
- read documentation
- search knowledge base
Medium
- create ticket
- update record
High
- delete resource
- deploy production
- transfer money
- rotate secrets
- create administrator
High-risk tools deserve:
- richer audit records
- stronger alerts
- longer retention
- more approvals
Risk Scoring
Multiple small signals can become significant together.
New Device
+15
New Client
+20
Admin Tool
+30
Large Export
+35
Unknown Destination
+40
Total:
140
Instead of alerting on every event individually, organizations may alert when the cumulative risk exceeds a threshold.
Prompt Injection Telemetry
Prompt injection attempts often produce unusual behavior.
Possible indicators:
- repeated tool discovery
- attempts to bypass approval
- requests for secrets
- hidden instructions
- repeated authorization failures
- unusual argument combinations
- privilege escalation attempts
Record the behavior rather than storing the complete malicious prompt.
Example:
{
"event_type": "security.prompt_injection_detected",
"classification": "possible",
"signals": [
"tool_enumeration",
"approval_bypass_attempt",
"credential_request"
]
}
Repeated Authorization Failures
One denied request is normal.
Thousands may indicate reconnaissance.
Wrong Scope
↓
Wrong Audience
↓
Different Tool
↓
Different Tenant
↓
Different Resource
This resembles automated privilege discovery.
Tenant Enumeration
Alert when one identity attempts:
tenant-a
tenant-b
tenant-c
tenant-d
even if every request is denied.
Enumeration attempts often precede exploitation.
Resource Enumeration
Repeated requests for:
- sequential IDs
- predictable paths
- hidden tools
- internal resources
may indicate reconnaissance.
customer-001
customer-002
customer-003
customer-004
Large numbers of failures deserve attention.
Large Data Exports
Watch for:
- unusually large responses
- many downloads
- bulk resource reads
- many files
- unusual token counts
- excessive API responses
Example:
Normal:
25 documents
Observed:
48,000 documents
New Destinations
Unexpected outbound destinations may indicate:
- exfiltration
- malware
- configuration drift
- compromised server
Known:
storage.internal
Observed:
unknown-example.xyz
Network monitoring should correlate with audit records.
Secret Access Monitoring
Audit whenever protected secrets are accessed.
Examples:
- vault read
- credential issuance
- signing key usage
- certificate request
- API key retrieval
Example:
{
"event_type": "credential.accessed",
"credential_profile": "billing-api",
"workload": "finance-mcp",
"reason": "invoice_creation"
}
Unexpected Process Activity
Runtime monitoring should detect:
- shell launches
- new binaries
- unexpected child processes
- package installation
- filesystem scans
- network scanners
These events may never appear in normal MCP protocol logs.
OpenTelemetry Integration
Many organizations already deploy OpenTelemetry.
Audit events may include:
{
"trace_id": "3baf...",
"span_id": "8d92...",
"correlation_id": "corr-9182"
}
OpenTelemetry provides:
- traces
- metrics
- logs
Audit records should remain authoritative while optionally linking to traces for investigation.
Audit Dashboards
Useful dashboards include:
Authentication
- logins
- failures
- MFA
- client registrations
Authorization
- allow vs deny
- reason codes
- scope failures
- audience failures
Tools
- most-used tools
- high-risk tools
- failed tools
- destructive tools
Tenants
- cross-tenant attempts
- exports
- approvals
Security
- suspicious behavior
- anomalous clients
- prompt injection
- DLP events
Investigation Workflow
A typical investigation may begin with:
Alert
↓
Correlation ID
↓
Timeline
↓
Affected User
↓
Affected Client
↓
Affected MCP Server
↓
Tool
↓
Downstream Changes
↓
Root Cause
The investigator should not need to manually combine dozens of unrelated log files.
Immutable Storage
Audit evidence should survive:
- ransomware
- administrator mistakes
- compromised workloads
- accidental deletion
Possible approaches include:
- append-only storage
- object lock
- WORM storage
- immutable snapshots
- cryptographic verification
- offline archive
No single mechanism provides complete protection.
Evidence Packages
During an incident, investigators often export:
- timeline
- affected events
- hashes
- signatures
- policy versions
- approval records
- downstream transaction IDs
An evidence package should remain verifiable even after export.
Compliance Mapping
Different frameworks require different evidence.
Audit records may support:
- ISO/IEC 27001
- SOC 2
- PCI DSS
- HIPAA
- GDPR
- NIST Cybersecurity Framework
- NIST SP 800-53
- internal governance
One audit architecture can satisfy multiple reporting requirements if events are structured consistently.
Performance Considerations
Logging should not become a bottleneck.
Strategies include:
- asynchronous delivery
- batching
- compression
- durable queues
- structured events
- bounded payload sizes
- efficient indexing
Avoid blocking production requests while waiting for slow audit storage.
Cost Management
Verbose logging increases storage costs.
Consider retaining:
Always:
- authorization decisions
- approvals
- administrative actions
- destructive operations
- policy changes
- security events
Sometimes:
- complete payloads
- prompts
- model outputs
- verbose diagnostics
Retention should reflect investigative value rather than convenience.
Testing Audit Logging
Test that:
- every important action creates an event
- denied requests are logged
- approvals correlate correctly
- correlation IDs propagate
- timestamps remain ordered
- secrets never appear
- redaction works
- failures trigger alerts
- duplicate handling functions correctly
- evidence survives service restarts
Security testing should verify the audit system itself.
MCP Audit Logging Checklist
Event Quality
- Stable event types
- Unique event IDs
- UTC timestamps
- Schema version
- Correlation IDs
- Consistent structure
Identity
- Verified user
- Client ID
- Workload identity
- Tenant
- Authentication strength
Authorization
- Issuer
- Audience
- Scope
- Policy version
- Decision
- Reason code
Tool Activity
- Tool name
- Target
- Risk level
- Requested action
- Executed action
- Outcome
Data
- Classification
- Record count
- Bytes transferred
- Destination
- Redaction
Security
- No tokens
- No secrets
- No passwords
- No private keys
- Structured logging
- Log injection protection
Infrastructure
- Durable delivery
- Independent storage
- Immutable archive
- Access controls
- Encryption
- Monitoring
Detection
- Correlation rules
- Baselines
- Anomaly detection
- Prompt injection telemetry
- Cross-tenant monitoring
- DLP monitoring
Incident Response
- Timeline reconstruction
- Evidence export
- Policy history
- Approval history
- Downstream correlation
- Integrity verification
Common Audit Logging Mistakes
Logging Every Request Body
Large payloads increase cost, expose confidential information, and make investigations harder.
Storing Access Tokens
A compromised audit database should never become a credential vault.
Mixing Debug Logs With Audit Logs
Developers and investigators have different requirements.
Missing Correlation IDs
Without correlation, distributed investigations become slow and error-prone.
Trusting Client-Supplied Fields
Audit records should prioritize verified server-side values.
Ignoring Denied Requests
Repeated failures often reveal attacks before successful compromise.
Allowing Applications to Delete Their Own Logs
A compromised workload should not be able to erase evidence.
Logging Without Monitoring
Collecting millions of events without detection rules rarely improves security.
Want to analyze your API security?
Import your OpenAPI spec and generate a Security Report automatically.
Conclusion
Audit logging is one of the most important security capabilities in an MCP deployment.
Unlike ordinary diagnostic logs, an audit trail must create an authoritative history of identity, authorization, tool execution, approvals, data movement, and downstream effects.
An effective design:
- records verified facts rather than assumptions
- correlates events across every MCP component
- protects credentials and sensitive content
- preserves integrity through independent storage
- supports rapid investigations
- enables compliance reporting
- detects attacks before they become incidents
The strongest audit architecture is not the one that stores the most data.
It is the one that reliably records the right security events, protects their integrity, minimizes unnecessary sensitive information, and allows investigators to reconstruct exactly what happened when every minute matters.
Continue learning: