Skip to main content

Obsigno

Open-source runtime governance for AI agents at the MCP tool-call layer.

Obsigno is a transparent stdio proxy between an MCP client and server. It evaluates each tools/call before execution, forwards allowed calls, returns MCP-compatible tool errors for denied calls, and writes every decision to an Ed25519-signed, hash-chained ledger.

It is the policy gate + flight recorder for tool-using agents:

  • Drop-in MCP enforcement — replace the server command; do not change client or server code.
  • Native policy options — built-in ordered JSON rules, OPA Data API, or Cedar via cedarpy.
  • Cross-server correlation — sign a shared agent-task trace ID and stable MCP server identity at every hop.
  • Tamper-evident, policy-bound evidence — hash arguments/results and exact local policy bytes, chain entries, and sign every record.
  • Portable trace evidence — export a trace with a derived manifest, full chain prefix, optional exact policy snapshots, and public key for offline verification.
  • Independent verification — detect edits, deletion, reordering, policy-reference changes, broken chains, or the wrong signer.
  • Live audit surface — FastAPI endpoints and a self-hosted dashboard.
  • One-command demo — Docker Compose launches a verified six-event cross-server agent trace.

Cryptography makes historical modification detectable. Put production ledgers on append-only/WORM or object-lock storage to make modification operationally difficult or impossible.

See COMPETITIVE.md for the evidence-backed competitor matrix and why Obsigno is positioned as the verifiable evidence layer for governed MCP actions, not another general MCP gateway.

Five-minute quickstart

Requires Docker with Compose.

docker compose up -d --build

Open http://localhost:8787. The quickstart runs six real tools/call requests through the stdio proxy and its demo upstream server, creates a persistent signing key, and records signed events across five server identities. The dashboard shows:

  • chain verification status;
  • allowed and denied agent actions;
  • policy reasons;
  • correlated task traces;
  • MCP server identities and event hashes.

Check it without the UI:

curl http://localhost:8787/api/health
# {"status":"ok","entries":6,"integrity":"verified","checked":6}

Stop the services while preserving the ledger:

docker compose down

Remove the demo ledger and keys as well:

docker compose down -v

Architecture

AI agent / MCP client
          |
          | JSON-RPC over stdio
          v
+-------------------------------+
|            Obsigno            |
|  1. intercept tools/call      |
|  2. evaluate JSON/OPA/Cedar   |
|  3. deny or forward           |
|  4. sign policy evidence      |
+-------------------------------+
          |
          v
      MCP server

             +--------------------------+
             | signed JSONL ledger      |
             | FastAPI + live dashboard |
             | offline public verifier  |
             +--------------------------+

Non-tools/call traffic—including initialization, discovery, resources, prompts, notifications, and unrelated responses—passes through transparently. Protocol stdout remains reserved for MCP JSON-RPC; diagnostics stay on stderr.

Install from source

Requires Python 3.10+.

python -m venv .venv

# Windows
.venv\Scripts\pip install -e ".[web,cedar,dev]"
.venv\Scripts\pytest -q

# macOS/Linux
.venv/bin/pip install -e ".[web,cedar,dev]"
.venv/bin/pytest -q

With uv:

uv venv
uv pip install -e ".[web,cedar,dev]"
uv run pytest -q

Available commands:

Command Purpose
obsigno-mcp Transparent stdio MCP policy/audit proxy
obsigno-verify Offline full-ledger chain and signature verifier
obsigno-evidence Export or verify a portable trace evidence bundle
obsigno-dashboard FastAPI audit API and live dashboard
obsigno-demo-proxy Exercise the real proxy and demo upstream for Compose

Put any stdio MCP server behind Obsigno

Everything after -- is the original MCP server command.

Audit-only adoption

Omit a policy to allow all tools while recording signed evidence:

obsigno-mcp \
  --server-id filesystem-mcp \
  -- npx -y @modelcontextprotocol/server-filesystem /safe/root

On first run Obsigno creates:

.obsigno/audit.jsonl
.obsigno/audit.jsonl.lock
.obsigno/private_key.pem
.obsigno/public_key.pem

Built-in ordered YAML or JSON policy

obsigno-mcp \
  --policy policies/demo.policy.yaml \
  --server-id filesystem-mcp \
  -- npx -y @modelcontextprotocol/server-filesystem /safe/root

Use .yaml/.yml for YAML or .json for JSON. The first matching rule wins, and supplying a policy enables default deny. For example, the equivalent JSON shape is:

{
  "default_reason": "no matching allow rule (default deny)",
  "rules": [
    {
      "id": "block-destructive",
      "effect": "deny",
      "tool": "delete_database",
      "reason": "destructive database operations are blocked"
    },
    {
      "id": "allow-reads",
      "effect": "allow",
      "tool": "read_file",
      "reason": "read-only file access is permitted"
    }
  ]
}

Rules may include an exact actor; "*" matches every actor or tool. Set the actor with --actor agent://name/session.

Native Cedar policy

Install the cedar extra, then use the included policy:

obsigno-mcp \
  --policy-backend cedar \
  --policy policies/policy.example.cedar \
  --server-id filesystem-mcp \
  -- npx -y @modelcontextprotocol/server-filesystem /safe/root

Obsigno maps the request to Cedar as:

principal = Agent::<actor>
action    = Action::<tool name>
resource  = MCPTool::<tool name>
context.arguments = tool arguments

Cedar evaluation is local. Forbid policy IDs, permit policy IDs, and reasons are included in the signed decision record. The optional dependency is pinned to cedarpy==4.8.7 for deterministic engine semantics; cedarpy is Rust-backed but community-maintained and is not an official AWS/Cedar Team binding.

Native OPA policy

Obsigno calls OPA's Data API and expects either a boolean result or this object:

{
  "result": {
    "allow": true,
    "reason": "read-only and research tools are allowed",
    "rule_id": "allow-read-research",
    "policy_ref": "opa:obsigno-example:v1"
  }
}

Start the pinned OPA 1.19.0 sidecar with the included Rego policy:

docker compose --profile opa up -d opa
curl http://127.0.0.1:8181/health

The development profile binds OPA only to loopback because its server also exposes policy-management APIs. Then point the proxy at the decision endpoint:

obsigno-mcp \
  --policy-backend opa \
  --opa-url http://127.0.0.1:8181/v1/data/obsigno/decision \
  --server-id filesystem-mcp \
  -- npx -y @modelcontextprotocol/server-filesystem /safe/root

OPA receives:

{
  "input": {
    "actor": "agent://researcher",
    "tool": "read_file",
    "arguments": {"path": "/safe/root/report.csv"}
  }
}

OPA network failures, malformed responses, responses without a boolean allow, and other backend errors fail closed. OPA can return policy_ref as a bundle revision, Git commit, or other deployment identifier; Obsigno signs that reference into the event. Built-in JSON and Cedar policies automatically use sha256:<digest> of the exact local policy bytes.

Correlate one agent task across MCP servers

Supply the same trace ID in MCP's extensible _meta object to every tool call in a task:

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "read_file",
    "arguments": {"path": "/workspace/brief.md"},
    "_meta": {
      "obsigno/trace_id": "task-research-2026-08-03"
    }
  }
}

Obsigno preserves that trace ID, adds obsigno/server_id, forwards the metadata, and signs both fields into the ledger. Configure each proxy with a distinct stable --server-id.

If the client does not provide a trace ID, Obsigno creates a UUID for that individual call. Task-level correlation therefore requires the client/orchestrator to propagate the same ID across calls. The dashboard groups signed records by trace ID and displays every server touched by that task.

The ledger serializes appends with both in-process and OS-level file locks, so separate proxy processes can safely extend one local chain. For distributed hosts, use a single append service or a storage backend that provides equivalent atomic ordering.

Dashboard and audit API

Run against local files:

obsigno-dashboard \
  --host 127.0.0.1 \
  --port 8787 \
  --ledger .obsigno/audit.jsonl \
  --private-key .obsigno/private_key.pem \
  --public-key .obsigno/public_key.pem

The CLI initializes missing keys and an empty ledger. API endpoints:

Endpoint Description
GET /api/health Service status, entry count, and live integrity result
GET /api/events Newest signed events; supports trace_id, decision, server_id, and limit
GET /api/traces Correlated trace summaries with servers and deny counts
GET /api/traces/{trace_id}/evidence Portable offline-verifiable trace bundle
GET /api/verify Full chain/signature verification details
GET / Auto-refreshing self-hosted dashboard

Example:

curl "http://localhost:8787/api/events?decision=deny&limit=20"
curl "http://localhost:8787/api/traces?limit=20"

Drop-in Claude Desktop-style configuration on Windows

Replace the original server command with obsigno-mcp.exe, then append the original command after --:

{
  "mcpServers": {
    "governed-filesystem": {
      "command": "C:\\path\\to\\obsigno\\.venv\\Scripts\\obsigno-mcp.exe",
      "args": [
        "--policy-backend",
        "cedar",
        "--policy",
        "C:\\path\\to\\obsigno\\policies\\policy.example.cedar",
        "--server-id",
        "filesystem-mcp",
        "--ledger",
        "C:\\path\\to\\obsigno\\.obsigno\\audit.jsonl",
        "--",
        "npx",
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "C:\\safe\\root"
      ]
    }
  }
}

Verify the evidence offline

obsigno-verify .obsigno/audit.jsonl .obsigno/public_key.pem
# OK  6 entries verified, chain + signatures intact

Export one trace as a portable evidence bundle and verify it without Obsigno running:

obsigno-evidence export \
  --ledger .obsigno/audit.jsonl \
  --public-key .obsigno/public_key.pem \
  --trace-id task-research-2026-08-03 \
  --policy-file policies/policy.example.cedar \
  --output task-research.evidence.json

obsigno-evidence verify task-research.evidence.json \
  --require-policy-snapshots

Repeat --policy-file when a trace used multiple local policies. Obsigno embeds only snapshots whose SHA-256 matches a signed policy_ref; strict verification fails if a required local snapshot is missing or changed. OPA references such as bundle revisions remain externally identified unless the exact policy bundle is supplied through a future attestation integration.

A linear hash chain needs every predecessor through the final selected event, so a trace bundle contains the complete ledger prefix up to that point plus trace_event_seqs. It does not contain raw arguments or results, but it can expose metadata for unrelated events in that prefix. Review that trade-off before sharing a bundle externally. Pin and compare the reported public-key fingerprint when the verifier receives the key through an untrusted channel.

Each signed record includes:

  • actor, action, tool, timestamp, and sequence;
  • trace ID and MCP server identity;
  • allow/deny decision, reason, matched rule ID, and policy version/hash reference;
  • SHA-256 hashes of arguments and results;
  • previous-entry hash, record hash, and Ed25519 signature.

Raw tool arguments and results are not written to the ledger. This reduces accidental retention of prompts, PII, secrets, and customer payloads while still proving whether supplied evidence matches the original event.

Python API

from obsigno import AuditLedger, Gateway, PolicyEngine, Rule, generate_keypair

policy = PolicyEngine([
    Rule(id="reads", effect="allow", tool="read_file", reason="reads allowed"),
])
ledger = AuditLedger("audit.jsonl", generate_keypair())
gateway = Gateway(policy, ledger)
result = gateway.call("agent://bot", "read_file", read_file, {"path": "/a.txt"})

Run python demo.py for a local allow/deny and tamper-detection demonstration.

Security boundary

Obsigno is unbypassable only when the MCP client can reach the target server exclusively through the proxy and cannot launch or connect to it separately.

For production:

  1. Keep the private signing key outside the agent's permissions.
  2. Restrict direct network/process access to governed MCP servers.
  3. Export signed ledgers to append-only/WORM or object-lock storage.
  4. Pin dependencies and container images.
  5. Authenticate and authorize access to the dashboard/API; the Stage-0 dashboard intentionally has no built-in identity layer.
  6. Monitor OPA availability; OPA decisions fail closed by design.

This repository provides tamper evidence, not absolute prevention of deletion. Loss of the only ledger copy is still loss of evidence.

Compliance positioning

Obsigno can supply technical logging evidence for governance programs such as EU AI Act Article 12 record-keeping, SOC 2 controls, and ISO/IEC 42001 processes. It does not make a system compliant by itself and is not legal advice.

Article 12 requires high-risk AI systems to technically allow automatic event recording over the system lifetime. The Act does not specifically mandate MCP logging, and “tamper-evident” is a defensible engineering practice rather than verbatim Article 12 language. Applicability, retention, and required fields depend on the organization's role and system classification.

Development

pytest -q
uv build
docker compose config
docker compose up -d --build

Repository layout:

src/obsigno/mcp_proxy.py       transparent MCP enforcement proxy
src/obsigno/demo_proxy.py      real proxied Compose demo and upstream
src/obsigno/policy_backends.py native Cedar and OPA adapters
src/obsigno/ledger.py          signed append-only ledger
src/obsigno/verify.py          offline full-ledger verifier
src/obsigno/evidence.py        portable trace evidence export/verifier
src/obsigno/web.py             FastAPI audit and evidence API
src/obsigno/static/            live dashboard
policies/                         Cedar and Rego examples
landing/                          product landing page
tests/                            unit and end-to-end tests

License

Apache-2.0 intended. The proxy, policy gate, ledger, verifier, API, and dashboard are designed to remain genuinely useful when self-hosted.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

obsigno-0.3.0.tar.gz (53.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

obsigno-0.3.0-py3-none-any.whl (38.1 kB view details)

Uploaded Python 3

File details

Details for the file obsigno-0.3.0.tar.gz.

File metadata

  • Download URL: obsigno-0.3.0.tar.gz
  • Upload date:
  • Size: 53.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36

File hashes

Hashes for obsigno-0.3.0.tar.gz
Algorithm Hash digest
SHA256 25ee480c0e81659ce8d0053c5e2e95bf366839d7fe280ba22c2eae7580cea614
MD5 9279d9ab067f8cdce2856bc96dc11f35
BLAKE2b-256 2d442b1ad945066093b3549686a3d7b6a17639b7d2d653f33577b5ee2e59e903

See more details on using hashes here.

File details

Details for the file obsigno-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: obsigno-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 38.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36

File hashes

Hashes for obsigno-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 587c8e2ebc859c38908aba49390d1ea79638529e50a6f01ffcf70b268335adfe
MD5 b54fe7e284acf2bbb817399fa24dd754
BLAKE2b-256 216bb12dfdadf9f5d1b697d0f228a7f28b501eb1862b91f401c2822663b262ee

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page