Skip to main content
Not every agent is a Python program you can add the SDK to. Many speak the Model Context Protocol instead: an MCP host (Claude Desktop, Cursor, an agent framework) launches tool servers and calls their tools. The sakshi-mcp package governs those agents two ways, neither of which requires touching the agent’s code.
Both surfaces are clients of the Sakshi HTTP API, so every call rides the same tokenization and hash-chain path as any other ingest. Sakshi never sees a raw identifier here either.

sakshi-mcp server

Adds three governance tools to any MCP host. Opt-in: the agent chooses to call them. Evidence plus advisory enforcement.

sakshi-mcp-proxy

Sits transparently between the agent and its real MCP server. Witnesses every tool call, and can enforce in the tool path. The agent cannot opt out.
Configure the endpoint for both with two environment variables: SAKSHI_API_URL (defaults to http://localhost:8000) and SAKSHI_MCP_API_KEY, a Sakshi ingest key (falls back to SAKSHI_API_KEY).

Sakshi as an MCP server

sakshi-mcp exposes Sakshi governance as MCP tools. Any MCP-capable host gains them without integrating the SDK. Because the agent chooses when to call them, this is opt-in: evidence plus advisory enforcement. Register it in an MCP host by pointing a server entry at the sakshi-mcp command:
The transport is stdio by default (how MCP hosts launch a local server). Set SAKSHI_MCP_TRANSPORT=streamable-http to serve it over HTTP instead:
The server enforces before an action and witnesses after it, but only when the agent calls the tools. For agents you do not control, or where opting out is not acceptable, use the proxy below.

The interception proxy

sakshi-mcp-proxy sits between an agent and its real MCP server and relays every JSON-RPC message verbatim:
Capability negotiation, resources, prompts, sampling, and notifications all pass through untouched, so the proxy is transport-faithful and future-proof. It only taps the messages it governs: tools/call (witnessed with a bounded argument and result preview, arguments tokenized at ingest) and tools/list (the tool manifest is hashed). Point the agent’s MCP host at the proxy command instead of the real server:
Everything after -- is the real downstream server command.

Transparent witnessing

By default the proxy is transparent: it observes and witnesses, it does not block. Every tool call the agent makes lands on the chain, attributed to --agent-id, with argument values tokenized so raw identifiers never reach the record. Witnessing is best-effort: a capture failure never breaks or delays a relayed message, and anything the proxy cannot parse is forwarded verbatim.

Tool-poisoning detection

The proxy hashes the tool manifest per tool. A tool whose description or schema changes mid-session is the tool-poisoning vector: a malicious server can rewrite a tool’s description after the agent first trusted it, to inject instructions (the 2025 incident class; OWASP MCP Top 10). When that happens, the proxy lands an mcp_manifest_changed finding on the chain, attributed to the specific tool. The poisoning becomes evidence, not a silent success.

Enforcement in the tool path

Set SAKSHI_MCP_ENFORCE=on to route each tools/call through the agent’s autonomy envelope before it reaches the tool. An auto-approved call is forwarded and witnessed; anything else is stopped and the agent gets a “parked for review” reply, never the tool. Under enforcement, a call to a tool poisoned mid-session is blocked outright, ahead of exemptions and the envelope.
SAKSHI_MCP_ENFORCE
on | off
default:"off"
Enable tool-path blocking. Off is transparent observe-and-witness.
SAKSHI_MCP_BLOCK_POISONED
on | off
Block calls to a tool poisoned mid-session. Defaults to on whenever enforcement is on.
SAKSHI_MCP_EXEMPT_TOOLS
comma-list
Tools to skip evaluation for (for example read-only tools). They are still forwarded and witnessed.
SAKSHI_MCP_FAILCLOSED_STAKES
float
Fail-static threshold. If Sakshi is unreachable, block calls whose stakes are at or above this value; below it, forward. Unset means always fail-open on an unreachable platform.
SAKSHI_MCP_BLOCK_STYLE
result | error
default:"result"
How a blocked call is returned to the agent: a structured tool result flagged isError with block details, or a JSON-RPC error.
SAKSHI_MCP_STAKES_FIELDS
comma-list
Argument keys to read the stakes signal from (defaults include amount, amount_inr, value, stakes, sum, total).
SAKSHI_MCP_CONFIDENCE_FIELDS
comma-list
Argument keys to read the confidence signal from (defaults include confidence, conf, score).

Remote downstream

The downstream MCP server can be remote over streamable-http instead of a local subprocess. The agent still speaks stdio to the proxy:
--header is repeatable. The governance decision is identical on both transports; the streamable-http path relays parsed JSON-RPC messages, so un-parseable agent input is dropped rather than forwarded verbatim.
Enforcement fails static, not simply open or closed. On an unreachable platform the outcome depends on SAKSHI_MCP_FAILCLOSED_STAKES: high-stakes calls block, lower-stakes calls forward. Set the threshold deliberately for your risk posture.

Which to use

Server

You control the agent or host and want governance tools it can call, or you want a readiness check available to the agent. Advisory: the agent must honour the outcome.

Proxy

You need every tool call witnessed whether the agent cooperates or not, or you want hard enforcement in the tool path and tool-poisoning detection.

MCP governance guide

A walkthrough of proxying an agent, witnessing its tools, and enabling enforcement.

watch_mcp middleware

Instrument an in-process MCP client session from Python with the SDK middleware instead.

Autonomy envelopes

The policy the proxy evaluates each tool call against.

Python SDK

The full client reference behind every governance decision.