-
Notifications
You must be signed in to change notification settings - Fork 1
Audit Trail
db-mcp includes a built-in JSONL audit trail with per-call token estimates, OAuth identity, timing, and outcome. Write/admin tools are always logged; read-scoped tools can be opted in via --audit-reads. Size-based log rotation prevents unbounded growth.
CLI flags:
node dist/cli.js --audit-log /var/log/audit.jsonl --sqlite-native ./database.db
# Omit tool arguments from entries
node dist/cli.js --audit-log /var/log/audit.jsonl --audit-no-redact --sqlite-native ./database.dbEnvironment variables:
| Variable | Default | Description |
|---|---|---|
AUDIT_LOG |
— | File path or stderr to enable audit logging |
AUDIT_REDACT |
true |
Redact tool arguments from entries (default: on) |
AUDIT_READS |
false |
Log read-scoped tool calls (compact entries) |
Docker:
docker run --rm -p 3000:3000 \
-v ./data:/app/data \
writenotenow/db-mcp:latest \
--transport http --port 3000 --server-host 0.0.0.0 \
--audit-log /var/log/audit.jsonl \
--sqlite-native /app/data/database.dbFor Docker, Kubernetes, and orchestrated environments, route audit entries directly to the container log stream:
--audit-log stderr
# or
AUDIT_LOG=stderrThe orchestrator (Docker log driver, Kubernetes Fluentd/Fluentbit, CloudWatch Logs, etc.) captures stderr natively — no volume mounts or log rotation needed.
Each line is a self-contained JSON object:
{
"timestamp": "2026-05-30T12:00:00.000Z",
"requestId": "75e9f60f-aad0-4519-81db-e0a79a57dd0e",
"tool": "sqlite_write_query",
"category": "write",
"scope": "write",
"user": "jane@example.com",
"scopes": ["read", "write"],
"durationMs": 3,
"success": true,
"args": {},
"tokenEstimate": 42
}| Field | Type | Description |
|---|---|---|
timestamp |
ISO 8601 string | UTC timestamp of the invocation |
requestId |
UUID string | Correlation ID for the MCP request |
tool |
string | MCP tool name (e.g., sqlite_write_query) |
category |
read/write/admin
|
Derived from the tool's OAuth scope group |
scope |
string | Required OAuth scope for this tool |
user |
string or null | OAuth sub claim (null for reads and no-OAuth) |
scopes |
string[] | OAuth scopes granted to the caller |
durationMs |
number | Execution time in milliseconds |
success |
boolean | Whether the tool completed without error |
error |
string? | Error message (present only on failure) |
args |
object? | Tool input arguments (omitted when redacted) |
tokenEstimate |
number? | Estimated token count (~4 bytes per token) |
Write and admin tools are always logged. Read-scoped tools are logged only when --audit-reads (or AUDIT_READS=true) is enabled.
| Scope | Groups / Tools | Logged? |
|---|---|---|
read |
core (read-only), json, text, stats, vector, geo, introspection | ⚡ Opt-in (--audit-reads) |
write |
migration, core write tools (write_query, upsert, batch_insert) |
✅ Always |
admin |
admin, codemode, core destructive (drop_table, truncate) |
✅ Always |
Read entries are compact — args, user, and scopes are omitted to keep per-entry size small.
The sqlite://audit resource exposes recent audit entries with a session summary to AI agents:
{
"summary": {
"totalTokenEstimate": 14200,
"callCount": 47,
"topToolsByTokens": [
{ "tool": "sqlite_read_query", "calls": 12, "tokens": 8400 },
{ "tool": "sqlite_execute_code", "calls": 3, "tokens": 3100 }
],
"note": "Last 47 tool calls consumed ~14,200 tokens"
},
"entries": [{ "tool": "sqlite_read_query", "tokenEstimate": 420, "..." }],
"total": 47
}The summary block gives agents session-level token consumption visibility. When audit logging is disabled, the resource returns an empty array with a status message.
The audit log rotates automatically when it exceeds the configured max size (default: 10MB). On rotation, the current file cascades down a 5-tiered rotation chain (.1 through .5). The oldest archive is deleted when a new rotation occurs.
For container deployments using --audit-log stderr, rotation is unnecessary — the orchestrator handles log management.
Pre-mutation DDL snapshots automatically capture the state of database objects before destructive operations. This enables point-in-time recovery and schema drift detection.
# Enable audit log + backup snapshots
node dist/cli.js --audit-log /var/log/audit.jsonl --audit-backup --sqlite-native ./database.db
# Also capture sample data
node dist/cli.js --audit-log /var/log/audit.jsonl --audit-backup --audit-backup-data --sqlite-native ./database.db| Variable | Default | Description |
|---|---|---|
AUDIT_BACKUP |
false |
Enable pre-mutation snapshots |
AUDIT_BACKUP_DATA |
false |
Include sample data rows in snapshots |
Snapshots are triggered by destructive tools:
| Tool | Snapshot Type |
|---|---|
sqlite_drop_table |
Table DDL (+data) |
sqlite_drop_index |
Object DDL |
sqlite_truncate |
Table DDL (+data) |
sqlite_vacuum |
Table DDL |
sqlite_drop_view |
View DDL |
sqlite_drop_virtual_table |
Virtual table DDL |
sqlite_migration_apply |
Migration marker |
sqlite_migration_rollback |
Migration marker |
Five MCP tools provide agent access to backup snapshots:
| Tool | Description |
|---|---|
sqlite_audit_list_backups |
List all available schema audit snapshots |
sqlite_audit_get_backup |
Retrieve the contents of a specific snapshot |
sqlite_audit_diff_backup |
Compare a snapshot against the live schema |
sqlite_audit_restore_backup |
Restore schema from a snapshot (supports dry-run) |
sqlite_audit_cleanup |
Enforce retention policy and remove expired snapshots |
sqlite_audit_search |
Search and filter structured audit logs |
Snapshots are cleaned up automatically based on age and count limits. The oldest snapshots exceeding either limit are deleted first.
JSONL format is compatible with standard log aggregation platforms:
| Platform | Method |
|---|---|
| Datadog | File tailing agent or stderr → Docker log driver |
| Grafana Loki | Promtail file/journal source |
| Elastic/ELK | Filebeat JSONL input |
| Splunk | Universal Forwarder or HEC (JSON) |
| CloudWatch Logs |
awslogs Docker log driver (stderr mode) |
| Fluentd/Fluentbit |
tail plugin with JSON parser |
For container deployments, --audit-log stderr is the recommended approach.
When OAuth is enabled with audit logging, write/admin audit entries capture the authenticated user (claims.sub) and granted scopes — providing a forensic trail linking mutations to identities.
- OAuth & Security — Scope definitions and access control
-
Resources & Prompts —
sqlite://auditresource - Code Mode — Admin scope requirements
- Tool Reference — Full tool list with scope groups