Custody
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Custodylist the oncology datasets I can query, then count lung cancer patients"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Custody
Custody sits between an AI agent and the tools it uses on oncology data, so the agent can work under controls a privacy or compliance officer can actually review: data-aware policy, approval gates for anything sensitive, a tamper-evident audit log, and isolated execution for every command.
Agent (Claude Code / Codex / OpenHands / Goose / any MCP client)
| MCP (stdio or streamable HTTP)
v
Custody Gateway
1. Identify principal + session
2. Classify request (tool, datasets, data class, egress, model target)
3. Policy engine -> allow | deny | require_approval
4. Approval broker -> wait for human decision (timeout = deny)
5. Executor -> sandboxed container
6. Output guard -> redact/summarize results by data class
7. Audit log -> hash-chained entry at every step
|
v
Custody's own tools: catalog.list, sql.query, shell.run, files.write,
files.export, approvals.status, fhir.searchStatus: v0.1.0 tagged and public (285 tests, 96% coverage on
src/custody, ruff and mypy --strict clean); main carries
several items since merged in from ROADMAP.md (signed policy bundles,
an OPA policy backend, a Kubernetes deployment, a FHIR connector, an
S3 Object Lock audit sink, an egress allowlist proxy, OIDC-verified
approver identity) -- see CHANGELOG.md's [Unreleased] section for
exactly what, and for what shipped in v0.1.0 itself. One scope note:
the architecture above describes a gateway that can also proxy a
downstream MCP server's tools, that proxying is not implemented,
every tool call this release handles goes through one of the
built-ins listed above (see custody/mcp_server.py's module
docstring).
Quickstart (under 5 minutes to the demo, Docker required)
custody-mcp is on PyPI
(pip install custody-mcp) for the CLI and the gateway itself. The
demo specifically needs a clone, though: it builds the sandbox's
DuckDB image from docker/sandbox.Dockerfile, which only a clone
carries.
git clone https://github.com/unmirihealth/custody
cd custody
uv sync --extra dev
docker build -f docker/sandbox.Dockerfile -t custody-sandbox:duckdb .
uv run custody democustody demo generates a synthetic oncology dataset with a fixed
seed, writes a sample policy/catalog/principals to disk, and walks
through: an allowed catalog listing, a de-identified cohort query
(not small-cell suppressed, that only applies at limited_data_set
and above), the same cohort breakdown re-run on identified data (held
for approval, then approved, this time suppressed), a two-person
export denied by one of the two required approvers, a blocked network
call from the sandbox, and custody audit verify catching a
deliberately tampered log entry. See docs/demo.md for a narrated
walkthrough of the output.
Once initialized (custody init in an empty directory, or after
custody demo), run custody serve --principal <your-agent-id> to
start the real MCP gateway (stdio), or custody ui for the local
approvals web UI.
Related MCP server: sentinel-mcp
Using it with Claude Code
Two integration modes:
MCP gateway (primary). Custody runs as an MCP server (
custody serve) exposing its built-in tools. Seeexamples/claude-code-mcp-config.jsonfor the config snippet.PreToolUsehook adapter (secondary). Routes Claude Code's own native tool calls (Bash, Write, Edit, WebFetch) through the same policy engine and audit log, asclaude_code.bash/claude_code.write/claude_code.edit/claude_code.web_fetchin your policy. Arequire_approvaldecision here doesn't block the hook (aPreToolUsehook has roughly 30 seconds, Custody's default approval timeout is 15 minutes); it records the pending approval and returns Claude Code's own"ask"decision instead.
See docs/integrations/claude-code.md for both, with exact config.
What Custody is not
Not a HIPAA certification. Installing Custody does not make anyone compliant. The accurate phrase is that Custody provides controls that can support HIPAA-aligned programs.
Not an audit or a SOC 2 report.
custody evidence exportproduces a mechanical summary of the audit log and policy, mapped to SOC 2 Common Criteria language, for a reviewer's convenience. It is not an attestation and does not substitute for an independent auditor. See docs/evidence-pack.md.Not a replacement for a business associate agreement, a risk assessment, or your institution's review process.
Tamper-evident, not tamper-proof. The audit log detects changes; it does not make them physically impossible. For long-term retention, ship checkpoints to write-once storage (see docs/audit-log.md).
Not a perfect sandbox. Docker isolation is one layer in a defense-in-depth design, not the whole design. See docs/threat-model.md for exactly what v0.1 defends against and what it does not.
Not a full SSO login flow.
principals.yamlis still the one source of truth for which roles a principal holds.custody approvals approve/deny --as-tokencan verify an approver's identity against a real OIDC provider's signed token instead of trusting a bare--asstring (see docs/sso-oidc.md), but there is no browser login flow, no session management, and the approvals web UI is unaffected (still its own startup-token gate).Not sandboxed with gVisor or Firecracker. Both require a Linux host with KVM; neither is buildable or verifiable on a macOS development machine, so neither is implemented here, see docs/threat-model.md T2 and ROADMAP.md.
Components
Component | Module | Docs |
Data catalog |
| this README |
Policy engine |
| docs/policy-reference.md |
Signed policy bundles |
| docs/policy-reference.md, |
OPA policy backend (optional, same policy.yaml) |
| docs/opa-policy-backend.md |
Kubernetes deployment |
| docs/kubernetes.md |
Approval broker |
| this README, docs/threat-model.md |
SSO/OIDC approver identity (optional, token verification only) |
| docs/sso-oidc.md |
Approval notifier (CLI, UI, webhook) |
| docs/policy-reference.md, |
Audit log |
| docs/audit-log.md |
S3 Object Lock audit sink (optional, |
| docs/s3-object-lock-sink.md |
Evidence-pack export |
| docs/evidence-pack.md |
Sandbox executor |
| docs/threat-model.md |
Egress allowlist proxy |
| docs/egress-proxy.md, docs/threat-model.md T9 |
Output guard |
| this README |
Model routing |
| docs/threat-model.md |
Gateway |
| this README |
Built-in tools |
| this README |
FHIR connector (read-only, FHIR only not OMOP) |
| docs/fhir-connector.md |
MCP server |
| docs/integrations/claude-code.md |
CLI |
|
|
Local approvals UI |
| this README |
Claude Code hook |
| docs/integrations/claude-code.md |
PyPI release workflow (Trusted Publishing) |
| docs/releasing.md |
Synthetic data only
Every example, fixture, and test in this repository uses generated oncology records. No real patient data belongs anywhere near this project, in an issue, a PR, or a commit. See CONTRIBUTING.md.
License
Apache 2.0. See LICENSE and NOTICE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Runtime permission, approval, and audit layer for AI agent tool execution.
Agent-native security, trust, reliability, data and procurement tools for AI workflows.
Security gateway for AI agents: policy, approval, and audited execution, no secrets shared.
Context and control for any AI. Agent identity, scoped access, and proof across tools.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables controlled AI-agent access to enterprise-shaped tools with a deny-by-default gated write path, human approval, dry-run execution, and append-only audit logging.1-
- AlicenseNot gradedqualityBmaintenanceEnables governed tool-calling agents with policy decisions, optional human approval, hash-chained audit logging, and deterministic evaluation.MIT
- AlicenseAqualityCmaintenanceEnables AI agents to run shell commands, perform sandboxed file operations, and make HTTP requests through zero-trust guards that block command injection, path traversal, and SSRF while redacting secrets from inputs and outputs. Circuit breakers, per-session rate limits, and an append-only audit ledger prevent runaway loops, excessive token spend, and provide post-hoc traceability.5MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to call backend tools under per-agent policy, deciding which tools each agent can see, what arguments it may pass, how often it may call, and which writes wait for human approval. It also redacts secrets and PII from tool results, fences untrusted output against injection, and records every call in a hash-chained audit log.25 npmMIT