MCPDBWizard

Documentation  ·  Operating

Setting up auditing

This page is an outline. What is here is accurate, but it is not yet the whole story — each section ends with a note on what is still to be written. For anything it does not answer, DEPLOYMENT.md and USING-MCP.md in the repository are the complete references.

Auditing is off unless a sink is named. MCP_AUDIT_SINK is the class name of a com.mcpdbwizard.pub.McpAuditSink; a mistyped one stops start-up rather than leaving the server silently unaudited.

VariableMeaning
MCP_AUDIT_SINKSink class. Unset means no auditing.
MCP_AUDIT_LEVELnames (default) or values.
MCP_AUDIT_MAX_BYTESCap on the recorded response, default 8192. 0 for no cap.

names is the default on purpose

At values the record carries argument values and the response body — production data, chosen by a model. That turns your sink into a store with retention, encryption and erasure obligations. Switch it on deliberately, not by accident.

A truncated response still carries its full byte size and a SHA-256 of the whole payload, with truncated: true. Truncation costs readability, not integrity.

Surviving an outage: the spool

MCP_AUDIT_SPOOL_DIR turns on a write-ahead spool. Every record goes to disk before any delivery attempt and is removed only once the sink confirms it, so records survive a sink outage and survive the server dying — the spool is read back and replayed on the next start.

VariableMeaning
MCP_AUDIT_SPOOL_DIRSpool directory. Unset means no spool. Put it on a persistent volume.
MCP_AUDIT_SPOOL_MAX_BYTESCap, default 100 MB.
MCP_AUDIT_SPOOL_ON_FULLdrop (default) or block.
MCP_AUDIT_SPOOL_FSYNCnever (default) or always.
MCP_AUDIT_SPOOL_KEY / _FILEEncrypts each spooled record (AES-256-GCM). Unset means plaintext.

Three sentences to read before relying on it.

Delivery is at-least-once. A crash between delivering a batch and deleting it replays that batch, so a consumer can see a record twice. Every record carries an iddedupe on it.

fsync=never survives the process, not the machine. Records live through a crash, an OOM kill or a container restart. They do not survive power loss. always covers that too, at a disk round trip per tool call.

A full spool refuses new records rather than discarding old ones. Watch for Audit record not spooled in the log — it means the trail has holes.

Expect a web/ subdirectory under the spool: the console records proxied requests while each generated server records its own tool calls, and a spool tolerates exactly one writer. That is the isolation working, not a stray directory.

Encrypting the spool

It protects the FILE, not the PROCESS. Anyone who can read the container’s environment or its memory has the key. It defends what outlives the process and travels: disk images, volume snapshots, backups.

Encrypting the volume is usually the better answer — no code, and it also covers the configs, the accounts and the runtime workspaces sitting in the same directory, which this does not.

Switching it on over an existing spool is safe. Switching it off, or changing the key, is not: those records can no longer be read, and an undecryptable segment is quarantined rather than retried or deleted. Drain the spool before rotating the key.

To write. The record’s field-by-field shape; writing your own sink against the SPI; the Kafka reference sink and its buffer-loss caveat; retention and erasure guidance for values mode.