MCP Audit Logging: What to Record When AI Queries Data
MCP audit logging for databases: which fields to record when an AI agent runs SQL, what never to log (result rows), and how long to keep the log.
On this page
- Why MCP changes what you need to log
- Fields worth logging, and fields to never log
- Log refusals, not only successes
- Who should be able to read the log
- Retention: keep it long enough, not forever by default
- A review routine that takes 15 minutes a week
- Database-native logging still matters
- How Datablare records agent queries
MCP audit logging means keeping a record of every request an AI agent makes through the Model Context Protocol. For database access, that record should answer: who asked, through which key or app, what they asked in plain words, the exact SQL that ran, whether a rule refused it, how many rows came back and how long it took. It should not contain the result rows. Those are the data you are trying to protect, and copying them into a log creates a second, weaker copy. This post lists the fields worth recording, the ones to leave out, and how to make the log useful rather than just large.
Why MCP changes what you need to log
Before AI agents, database access logs mostly answered “which application or analyst ran this query?” The SQL was written by a person or by code you reviewed.
With MCP, the SQL is written by a model, on behalf of a person, in response to a question typed in plain language. That adds two things a traditional log misses:
- The question. “Show me customers who churned last quarter” explains a query far better than 40 lines of generated SQL.
- The person behind a shared credential. Many MCP setups use one service login to the database. The database log then shows every query coming from
ai_reader, which tells you nothing about who asked.
There is also more volume. An agent may call several tools for one question: list the tables, read a schema, run a query, fix an error and run it again. A good log shows that sequence, including failures.
Fields worth logging, and fields to never log
| Field | Log it? | Why |
|---|---|---|
| Timestamp | Yes | The basis of every investigation |
| Person (user id) | Yes | Ties the query to someone accountable |
| Credential: which key or connected app | Yes | Shows which client was used; lets you revoke the right one |
| Organization, project, data source | Yes | Scopes the record; answers “which database?” |
| Tool name (list tables, query, etc.) | Yes | Shows the agent’s path to an answer |
| The question the agent says it is answering | Yes, with care | Explains intent; may contain personal data |
| Intent or short purpose | Yes | Useful for grouping and review |
| The exact SQL that ran | Yes | The core of the record |
| Outcome: allowed, refused or error | Yes | Refusals are often the most important rows |
| Rule that refused it, as a code | Yes | Lets you count refusals by cause |
| Error message | Yes, with quoted values removed | Database errors can quote the value they choked on |
| Row count | Yes | Size of what left the database |
| Response size in bytes | Yes | Closest measure of what the agent received |
| Duration | Yes | Spots slow or heavy queries |
| A one-line topic of the final answer | Optional | “Monthly revenue by region”, never the figures |
| Result rows | Never | A second copy of sensitive data |
| Full keys, tokens or passwords | Never | Store a fingerprint or hash at most |
| Database credentials | Never | Belong in an encrypted store, not a log |
| The agent’s full answer text | Avoid | Contains the figures and names from the results |
Two of these deserve a closer look.
Errors can leak values
A database error like invalid input syntax for type integer: "priya@example.com" quotes the value it failed on. If you log errors as they arrive, you log customer data. Strip quoted values from errors before storing them, but keep quoted names (column "emial" does not exist), because those are what the agent needs to fix its query.
Questions can contain personal data
People type names, phone numbers and order ids into questions. That makes the question field personal data, which affects who can read the log and how long you keep it. You can’t strip it out without losing the point of the record, so control access to it instead.
Log refusals, not only successes
A log that only records successful queries misses what security teams care about most: attempts that were stopped. Every refused call should be written with the rule that stopped it. Useful refusal causes to track:
- A write attempt (INSERT, UPDATE, DELETE, DROP)
- A table that isn’t exposed to agents
- A hidden column, including one pulled in by
SELECT * - A rate limit or daily limit
- A role that may view but not query
A rise in one cause tells you something. Many hidden-column refusals may mean the agent is missing context. A burst of write attempts from one key may mean a misconfigured agent, or something worse.
Who should be able to read the log
The audit log is sensitive in its own right: it holds questions and SQL, which reveal what people are interested in and sometimes who.
- People who query the data can reasonably read the questions and SQL for their project.
- Oversight roles such as a compliance lead may only need to see that calls happened: when, which tool, how long, how many rows. Not the text.
- People limited to some data sources should see calls on those sources only.
- Bulk export is a bigger act than reading a page, so hold it to managers.
Retention: keep it long enough, not forever by default
How long to keep MCP audit logs depends on your security policy, your sector and your incident response needs. Some points to weigh:
- Investigations often start weeks after the event. Seven days is enough for a trial, rarely enough for production.
- CERT-In’s 2022 directions require ICT system logs to be kept for 180 days within India. Check with your counsel how that applies to your systems.
- Under the DPDP Act, personal data shouldn’t be kept beyond its purpose. The questions in the log are personal data, so indefinite retention needs a reason.
- If your plan’s retention is shorter than you need, export the log regularly to your own archive.
A review routine that takes 15 minutes a week
Logs nobody reads are storage costs. A light routine:
- Look at refusals by cause. Anything new or rising?
- Look at the top people and keys by volume. Anything unexpected?
- Scan the largest responses by rows or bytes. Should that much data have left?
- Check for keys that haven’t been used in weeks, and revoke them.
- Spot-check a few questions against their SQL. Did the agent do what was asked?
Database-native logging still matters
Engine features such as PostgreSQL’s pgaudit, or audit settings in SQL Server, Oracle and Snowflake, give you an independent record that doesn’t depend on the gateway. Keep them where you have them. The MCP-level log adds what they can’t see: the person, the credential, the question and the refusals that never reached the database.
How Datablare records agent queries
Datablare writes an audit record for every tool call an agent makes, allowed or refused. Each record holds:
- When, the person, and which key or connected app made the call
- The project and data source
- The question the agent says it is answering, and its stated intent
- The SQL that ran
- Whether it was allowed, and the rule code if it was refused
- The error, with quoted values stripped
- Rows returned, response size and duration
- A one-line topic of the final answer, capped at 500 characters. The agent is asked to leave out figures and names.
Query results are never stored. They pass through to the agent and aren’t kept.
In the app, Audit → Usage shows totals, refusals by reason, who is asking, which databases and keys, and an Every call list you can filter by outcome, person or database, or search by question and SQL. Audit → Changes records edits to context and column visibility, with the old and new value.
Access follows project roles. Viewers see that calls happened, with counts and timings, but not the questions or SQL. Analysts limited to some data sources see calls on those sources. Managers can export the current filtered view as CSV on the Team plan and above.
Audit history is kept 7 days on Free, 30 days on Team, and for as long as the organization exists on Business and Enterprise. Older records are deleted every night.
One honest limit: Datablare stores the question as the agent reports it, so personal data people type into questions ends up in the audit record. Access to that text follows the roles above, and retention follows your plan.
See how audit fits with read-only enforcement and column controls on the security page, or create a free account and look at the Audit page after asking the sample dataset a few questions.
Frequently asked questions
What should an MCP audit log record for database queries?
At minimum: when the call happened, which person and which key or app made it, which project and data source, the question the agent says it is answering, the exact SQL, whether it was allowed and which rule refused it if not, the row count, response size and duration.
Should an MCP audit log store query results?
No. Storing result rows creates a second copy of your most sensitive data in a system built for reading, not protecting. Record the row count and response size instead, and re-run the logged SQL if you ever need to see what was returned.
Isn't database-native logging enough?
It helps, but when every AI query arrives through one service login, the database log shows the SQL without the person, the question or the reason. An MCP-level log ties each query to a named person, a credential and the question behind it.
How long should MCP audit logs be kept?
Long enough to investigate an incident and answer an auditor, and no longer than you need. Weigh your security policy, sector rules and the fact that the questions themselves can contain personal data. Datablare keeps audit history 7 days on Free, 30 days on Team and while the organization exists on Business and Enterprise.