Govern any MCP server
MCP servers let agents act through tools — but most ship with no authorisation boundary and no record of what an agent actually did. This is a drop-in fix: every tool call is authorised against a deny-by-default policy and fails closed, and each call leaves a signed, hash-chained receipt that rolls up into an independently-verifiable evidence bundle.
The boundary, in four steps
- 1Authorise every call. 100% of invocations hit the OAA tool-boundary guard, evaluated against a deny-by-default policy: allow, deny, charge, or review.
- 2Fail closed. Any non-allow verdict stops before execution — the tool handler runs on 0% of denied calls.
- 3Signed receipt before execution. An ed25519-signed, hash-chained receipt is written first, so the audit trail can’t be backfilled or quietly altered.
- 4Verifiable evidence bundle. Receipts roll up into an immutable bundle anyone can re-verify offline — no actions removed, reordered, or forged.
What changes when you govern an MCP call?
| Ungoverned MCP tool call | Governed with OAA | |
|---|---|---|
| Authorisation | None — the tool handler runs on request. | Deny-by-default policy returns 1 of 4 verdicts: allow, deny, charge, review. |
| On a denied call | No concept of denial. | Fails closed — the handler never runs. |
| Record | No record of what the agent did. | ed25519 (256-bit) signed, hash-chained receipt, written before execution. |
| Audit | Not independently verifiable. | Immutable evidence bundle, re-verifiable offline by anyone. |
Source: the OAA tool-boundary guard and evidence bundle in oaa-mcp-governance (Apache-2.0).
Drop it into your MCP server
Register your tools; the guard, receipts, and evidence bundle come with it. A sub-30-minute quickstart:
import { GovernedMcpServer } from '@kirkelabs/oaa-mcp-governance'
import { createReceiptSigningKeyPair } from '@kirkelabs/open-agent-access-core'
const server = new GovernedMcpServer(tools, {
policy, // deny-by-default
signing: createReceiptSigningKeyPair(), // ed25519 signed receipts
})
const r = await server.call('read_record', input, agent)
if (!r.ok) return mcpError(r.reason) // denied → handler never ran
// every call → a signed, chained receipt → a verifiable evidence bundleFull quickstart and runnable demos in the reference repo: github.com/KirkeLabs/oaa-mcp-governance. Built on the published @kirkelabs Open Agent Access packages (Apache-2.0), with an OAA v0.1 conformance runner and 2 runnable demos.
Why now
MCP adoption is moving fast and its security practices are still immature. Security research on MCP servers keeps surfacing the same gaps — over-privileged tokens, missing authorisation, and no consistent record of tool calls. The MCP specification added an OAuth 2.1 authorisation model in 2025, but it governs access, not a verifiable record of every action a tool takes. According to the MCP security best-practices guidance, end-to-end auditability of agent actions is a named requirement for safe enterprise MCP — one existing AI-governance frameworks don’t yet cover.
The architecture here is deliberately conventional: a deny-by-default boundary with 4 verdicts (allow, deny, charge, review), plus tamper-evident, hash-chained logs in the lineage of RFC 6962 Certificate Transparency — so a downstream party can verify that nothing was removed, reordered, or forged. Each receipt is an ed25519 (256-bit) signature written before execution. According to the EU AI Act (in force since 2024), Article 12 sets a record-keeping duty for high-risk AI — a tailwind, not the trigger.
