Skip to content

MCP Audit Log

The MCP audit log records everything that happens through the MCP server: every client registration, sign-in, consent and token, every session a client starts, every tool call, every guide or help page read and every prompt used, every confirmation a person answers, and every message body or log text returned. Each event is written twice, as a row in the mcp_audit_entry table and as one line in mcp-audit.log. The table is the record QIE reads; the file is the copy that outlives the table's retention and can be shipped to another system.

An entry holds identifiers. It names the user, the client, the address and the object, but it never holds a token, an authorization code, a password, a message body or a system variable value. Secret fields, sample message bodies and variable values are left out of an entry entirely. Two kinds of entry can hold text that came from the client: a refused call keeps its arguments while Return message content is on, with credentials masked, and identify_session keeps the task the model reported. An export leaves both out (see Exporting the log).

Viewing the log

Administrators read the log in the console. On the Model Context Protocol (MCP) page in System Administration, click View Entries in the Audit Log section to open the MCP Audit Log dialog. The dialog shows the newest entries first, a page holding as many entries as the list shows without scrolling, and the paging bar under the list moves between pages and shows how many entries match. The dialog opens showing nine entries; resizing or maximizing it changes how many entries a page holds.

The Filters section narrows the list, and Search applies it:

Filter Matches
From and To Entries from the start of the From day to the end of the To day. Either may be left empty.
User The QIE user id, exactly.
Outcome One outcome, or Any.
Client Id The client id, exactly.
Client Name Client names that contain the text, in any case.
Session The session id, exactly.
Tool The tool name, exactly, such as save_object.

Clear empties every filter and shows the newest entries again.

The list shows the Audit Id, time, event, outcome, user, client name, tool, target, duration and the start of the error text of each entry. The client id and version, session, request id, source address, access and scope columns are hidden; show them from any column's menu. The columns keep their widths, and a scroll bar appears when they are wider than the dialog. The Audit Id is the number an error returned to a client names.

Double-click an entry to open it in the MCP Audit Entry window, which shows every field of the entry, the whole error text, and the details as indented JSON that can be selected and copied.

When an entry is written

A call that changes QIE, or returns message content, does not run until its entry is written. QIE first writes the entry with the outcome STARTED, then runs the call, then updates the entry with how it ended and how long it took. An entry still marked STARTED therefore marks a call that never finished, for example because the engine stopped.

If QIE cannot write that first entry, it refuses the call, logs a warning and raises the audit failure alert described in Alerts. The client is told that the call did not run.

Each entry is committed on its own, so a change that fails and is rolled back still leaves its entry. Events that do not wait on their entry, such as sign-in events, session starts, reads of object lists, guide and help page reads and prompts, are written once they finish.

Fields

Field Holds
Id The entry's number. Errors returned to a client name it, so an administrator can find the entry.
Timestamp When the event started.
Event type What happened, from the list below.
Outcome STARTED, SUCCEEDED, REFUSED (refused before it ran), FAILED (ran and failed) or DECLINED (the person declined a confirmation).
Duration Milliseconds from start to finish.
User The QIE user id.
Client id, name and version The registered client and what it calls itself.
Token The number of the token record, never the token. Empty for a call through the Hub, which has no token at the engine.
Source address Where the request came from.
Session and request The client's session id and the request id, when there are any.
Tool, access and scope The tool called, whether it read or wrote, and the token's scope.
Target The zone, object type and object id the call acted on.
Result size Bytes returned.
Content returned Whether message content was returned.
Content edited For a resubmit, whether the message was edited first.
Approved revision For a confirmation, the version of the object the person approved.
Error text Why a call was refused or failed, up to 4,000 characters.
Details Further identifiers for the event, such as the channel and message for a message read. See What the details hold.

Event types

Event type Written when
CLIENT_REGISTERED, CLIENT_REGISTRATION_REJECTED A client registered, or a registration was refused.
CLIENT_METADATA_FETCHED, CLIENT_METADATA_REJECTED A client metadata document was fetched, or refused.
AUTHORIZATION_REFUSED A sign-in was refused before consent.
HUB_OR_LOOPBACK_REFUSED A sign-in came through a Hub or from the engine's own host and was refused.
CONSENT_GRANTED, CONSENT_DENIED The person approved or declined the client.
TOKEN_ISSUED, TOKEN_REFRESHED, TOKEN_REQUEST_REJECTED A token was issued, renewed or refused.
CODE_REUSE_DETECTED, REFRESH_REUSE_DETECTED An authorization code or refresh token was used a second time; the tokens issued from it are revoked.
TOKEN_REVOKED, TOKENS_REVOKED_FOR_USER, TOKENS_REVOKED_ALL, CLIENT_REVOKED, CLIENTS_REVOKED_ALL Tokens or clients were revoked, with what triggered it and how many.
REQUEST_REJECTED The listener refused a request.
RATE_LIMIT_BREACH A client kept exceeding a limit, or a person calling through the Hub went over one.
SESSION_STARTED A client started a session.
TOOL_CALL Any tool was called.
RESOURCE_READ A guide, the Code Wizard reference or a help page was read. The entry names it, never its text.
PROMPT_USED A prompt was used to start a task. The entry names the prompt, never what the person filled in.
CONFIRMATION_REQUESTED, CONFIRMATION_ANSWERED A person was asked to confirm an action, and answered.
REPORT_SENT A report about the session was sent to Qvera support. The entry names the report's kind and sizes, never its text.
CONTENT_READ A message body, log text, cache value or sample message was returned.
TAMPERED_REVISION A change arrived with a revision token that failed its check.
AUDIT_PURGED The nightly retention run, with its cutoff and how many entries it deleted.
RECORDS_CLEANED The nightly cleanup of expired tokens, codes and registrations.

What the details hold

Entry Details
SESSION_STARTED The protocol version, the client's User-Agent, and the client information and capabilities the client declared. The session id is the one the server gave the session, so every later entry of the session carries it.
TOOL_CALL The id the client gave the call, when it sends one. For a check or a test that ran, what its result reported: whether it was valid, how many problems it found, or why a test run ended, never the text. For a call that did not succeed, its error code. For a refused call while Return message content is on, its arguments, with credentials masked and a certificate, key or configuration file recorded only by its length, up to 4,000 characters.
TOOL_CALL of identify_session The model, effort level and task the model reported. The server instructions ask the model to call identify_session at the start of a session; QIE records what it reports and checks none of it.
RESOURCE_READ, PROMPT_USED The address of the resource, or the name of the prompt.
REPORT_SENT The report's kind, the length of the model's text and of the person's comment, whether the person approved it through a form or through the model, whether a name and an email were given, which entries it carried and how many, and the size of the zipped export.

Calls Through the Hub

An engine that accepts MCP calls through its Hub records them in this log as it records calls to its own MCP server, with these differences (see MCP Calls Through the Hub):

  • The client id is hub: followed by the Hub's id for the AI client, and the client name and version are the ones the AI client gave the Hub.
  • The session is the Hub's MCP session, the request id is the id of the statement the Hub signed for the call, and the source address is the address the Hub saw the client call from.
  • No token is recorded.
  • An action the person must confirm writes CONFIRMATION_REQUESTED when the first call stops with the question, and CONFIRMATION_ANSWERED when the second call brings the answer.
  • A RATE_LIMIT_BREACH entry for a person over a limit has the client id hub, and its details name the statement.

A Hub keeps a log of its own for its MCP server, with the same fields. Its entry for a call to a site names the site's label as site, or the tag as tag, and the statements it signed as statementIds in the details, so it can be matched with the site's entry (see The MCP Server on a Hub).

Exporting the log

To send the log to Qvera support, click Export in the MCP Audit Log dialog. In the Export MCP Audit Log dialog, choose Export one session and enter the Session, or Export a date and time range and enter the From and To. When an entry is selected, the dialog opens on its session; otherwise it opens on the dialog's dates, or on today. Export downloads a ZIP file holding one JSON Lines file, mcp-audit-log-<date>-<time>.jsonl.

The first line of the file describes the export: the engine's name and version, when it was exported and by whom, and the session or range. Each line after it is one entry, oldest first, with the same fields as a line of mcp-audit.log.

The export leaves out what can hold message content, whatever Return message content is set to now or was set to when the entry was written:

  • a refused call's arguments
  • the task identify_session reported
  • the error text of every entry that did not fail, because a refusal can quote what was sent

Each is replaced by {"$omitted": <name>, "length": <characters>}, so the reader can see that it was there. A failed entry keeps its error text, which QIE writes itself: the exception's type and code locations without its message, or a fixed sentence. One export holds at most 50,000 entries; for more, export a shorter range.

The send_report tool sends the same export of its own session with a report, after the person approves it (see Sending a report to Qvera).

The log file

mcp-audit.log is in the logs folder of the QIE home directory. Each line is one JSON object with the same fields as the table row, so a line can be matched to its row by id. A call that is written before it runs appears twice: once when it starts and once when it ends. The file rolls over at 50 MB and keeps twenty files.

In a container, the same lines also go to standard output, each carrying the logger name mcp-audit, so the platform's log collector picks them up.

Retention

Each night QIE deletes table entries older than the Audit Retention (days) setting on the Model Context Protocol (MCP) page, 365 days by default, and writes one AUDIT_PURGED entry naming the cutoff and the count. A setting of 0 keeps every entry. In a cluster, one node runs the deletion. On a Hub, the deletion runs with the Hub's daily cleanup (see The MCP Server on a Hub). The log files are not affected by retention.

There is no way to delete entries by hand, the message purge does not touch them, and they are never part of a configuration export.