Capability Governance
Prerequisites
Install MCP Fusion before following this guide: npm install @vinkius-core/mcp-fusion @modelcontextprotocol/sdk zod — or scaffold a project with npx fusion create.
- What the Protocol Cannot Answer
- Surface Drift Is Silent
- The Governance Stack
- Try It in 60 Seconds
- How Contracts Materialize
- Observability Integration
- Where to Go Next
You review an MCP server. You trust its declared tools. You approve it for production.
A week later, a dependency update adds a shell_exec action to one of the tools. A Presenter loses its system rules. An input schema silently gains a new parameter. The MCP protocol has no mechanism to detect any of this — tools/list returns whatever is currently registered, and notifications/tools/list_changed says "something changed" without saying what, when, or how.
This is not an edge case. It is the default behavior of every MCP server in production today. For enterprise teams facing SOC2 Audits or strict CISO Compliance requirements, this invisible drift makes AI agent deployments fundamentally un-auditable.
What the Protocol Cannot Answer
The MCP lifecycle is simple: the client calls tools/list, the server responds with the current surface, and the client proceeds.
Client Server
│ │
│── tools/list ────────────────▶│
│◀──────────── [tool1, tool2] ──│
│ │
│ (time passes) │
│ │
│◀── notifications/tools/ │
│ list_changed ──────────────│
│ │
│── tools/list ────────────────▶│
│◀──────── [tool1, tool2, ???] ──│That lifecycle answers one question: "what tools exist right now?" It leaves six critical questions unanswered:
- Is this the same surface I trusted yesterday?
- What exactly changed since my last review?
- Did the behavioral contract change even though the schema didn't?
- Can I prove cryptographically that the surface hasn't been tampered with?
- Which tools can write to disk, even though they declare
readOnly? - Will this tool flood the context window and evict system rules?
These are not client UX bugs. They are missing inspection primitives at the protocol layer. Without them, you cannot build a secure AI Agent Sandbox. The governance stack fills every one of them, transforming MCP from a raw payload router into a cryptographically auditable boundary.
Surface Drift Is Silent
A tool named upload_file initially accepts { path }. After a deployment, it accepts { path, contents }. The tool name didn't change. The tool ID didn't change. The description is the same. But the behavioral surface expanded — the tool can now receive arbitrary file contents from the agent.
A more subtle case: the declared surface — schema, name, description — stays structurally identical while the handler's behavior changes. A read_config tool starts calling fs.writeFile. The annotation still says readOnlyHint: true. The protocol provides no mechanism to detect the contradiction because it only inspects declarations, not behavior.
The governance stack detects both scenarios. Structural changes are caught by Contract Diffing. Behavioral contradictions are caught by Blast Radius Analysis. Silent handler drift is caught by Semantic Probing.
The Governance Stack
Nine modules, each independently useful, each composable with the others:
┌──────────────────────────────────────────────────────────┐
│ Governance Stack │
│ │
│ CapabilityLockfile ← BehaviorDigest ← ToolContract │
│ │
│ ContractDiff CryptoAttestation EntitlementScanner │
│ TokenEconomics SemanticProbe SelfHealing │
│ │
│ CLI: fusion lock / fusion lock --check │
└──────────────────────────────────────────────────────────┘Every module is a pure function. Side-effectful I/O (disk, network) is clearly separated. When governance is not configured, no cryptographic operations execute — the server startup path is identical to the default.
Try It in 60 Seconds
npx fusion lock --server ./src/server.tsThis generates mcp-fusion.lock — a deterministic, git-diffable artifact that captures every tool's behavioral surface. Schemas, system rules, middleware chains, entitlements, token economics — all of it, in a single committed file.
npx fusion lock --check --server ./src/server.tsThis gates your CI build. If anyone changes a tool's behavioral surface without updating the lockfile, the build fails. The pull request diff shows exactly what changed:
"invoices": {
- "integrityDigest": "sha256:f6e5d4c3b2a1...",
+ "integrityDigest": "sha256:9a8b7c6d5e4f...",
"surface": {
"actions": ["create", "list", "void"],
},
"behavior": {
- "systemRulesFingerprint": "static:abc",
+ "systemRulesFingerprint": "dynamic",
"destructiveActions": ["void"],
}
}The reviewer sees that the system rules changed from static to dynamic — and can assess the AI-facing impact before merge. Without the lockfile, this change is invisible at the protocol level.
How Contracts Materialize
You don't write contracts. They materialize from what you've already declared — tool builders, Presenters, middleware, system rules. The compileContracts() function reads all of that metadata and produces a ToolContract for each tool:
import { compileContracts } from '@vinkius-core/mcp-fusion/introspection';
const contracts = compileContracts(registry.getBuilders());Each ToolContract captures four sections:
interface ToolContract {
readonly surface: ToolSurface; // name, description, actions, schema, tags
readonly behavior: ToolBehavior; // egress, rules, guardrails, middleware, affordances
readonly tokenEconomics: TokenEconomicsProfile; // field count, inflation risk
readonly entitlements: HandlerEntitlements; // filesystem, network, subprocess, crypto
}This is the input to every governance module. The lockfile snapshots it. The digest fingerprints it. The diff engine compares it. The attestation module signs it. Zero ceremony — the developer never writes governance-specific code beyond one function call.
Observability Integration
All governance operations emit structured events through the same DebugObserverFn pipeline used by the tool execution layer:
import { createGovernanceObserver } from '@vinkius-core/mcp-fusion/introspection';
import { createDebugObserver } from '@vinkius-core/mcp-fusion';
const observer = createGovernanceObserver({
debug: createDebugObserver(),
tracer: myOtelTracer, // optional
});
const lockfile = observer.observe(
'lockfile.generate',
'Generate lockfile for payments-api',
() => generateLockfile('payments-api', contracts, version),
);[mcp-fusion] gov lockfile.generate ✓ Generate lockfile for payments-api 4.2ms
[mcp-fusion] gov attestation.sign ✓ Sign server digest 1.1msWhen observability is not configured, createNoopObserver() provides a zero-overhead passthrough.
Where to Go Next
Each module has a dedicated page with full code examples:
- Capability Lockfile —
mcp-fusion.lockgeneration, verification, CI gates - Surface Integrity — SHA-256 behavioral fingerprinting
- Contract Diffing — semantic delta engine with severity classification
- Zero-Trust Attestation — HMAC-SHA256 signing, runtime verification
- Blast Radius Analysis — entitlement scanning with evasion detection
- Token Economics — cognitive overload profiling
- Semantic Probing — LLM-as-a-Judge for behavioral drift
- Self-Healing Context — contract delta injection into validation errors
- CLI Reference —
fusion lockcommand-line interface