feat: usage audit for the mcp surface #26

Merged
TimCane merged 4 commits from feat/usage-audit into main 2026-07-20 21:56:34 +01:00
TimCane commented 2026-07-20 21:41:52 +01:00 (Migrated from github.com)

Summary

  • record every tool and prompt call in audit.tool_call, one audit.session row per MCP session
  • capture once via the SDK's call-tool and get-prompt filters, not per tool; completions stay unlogged
  • writes go through a bounded channel to a background writer, so a slow or broken audit path drops rows rather than failing or delaying a call
  • identity is semi-anonymous by construction: session id, client info, and an address hash salted with a daily key that is never stored, which is what makes storing args verbatim acceptable
  • daily sweep drops rows past 90 days; schema is created idempotently at startup alongside the views
  • fixed-window rate limit of 120 requests a minute per address, on the forwarded client address

Test plan

  • dotnet test - 229 pass
  • new integration tests drive the real server and read the rows back: one session row across many calls, zero-result searches land as result_count 0, errors keep their kind, and dropping the audit schema under the writer never reaches the caller
  • new unit tests cover salt rotation across days and drop-on-full queue behaviour
## Summary - record every tool and prompt call in `audit.tool_call`, one `audit.session` row per MCP session - capture once via the SDK's call-tool and get-prompt filters, not per tool; completions stay unlogged - writes go through a bounded channel to a background writer, so a slow or broken audit path drops rows rather than failing or delaying a call - identity is semi-anonymous by construction: session id, client info, and an address hash salted with a daily key that is never stored, which is what makes storing args verbatim acceptable - daily sweep drops rows past 90 days; schema is created idempotently at startup alongside the views - fixed-window rate limit of 120 requests a minute per address, on the forwarded client address ## Test plan - `dotnet test` - 229 pass - new integration tests drive the real server and read the rows back: one session row across many calls, zero-result searches land as `result_count` 0, errors keep their kind, and dropping the audit schema under the writer never reaches the caller - new unit tests cover salt rotation across days and drop-on-full queue behaviour
Sign in to join this conversation.
No description provided.