Skip to main content

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.search

Status: 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)

From a clone of this repository (not yet published to PyPI):

git clone <this repo>
cd custody
uv sync --extra dev
docker build -f docker/sandbox.Dockerfile -t custody-sandbox:duckdb .
uv run custody demo

custody 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.

Using it with Claude Code

Two integration modes:

  • MCP gateway (primary). Custody runs as an MCP server (custody serve) exposing its built-in tools. See examples/claude-code-mcp-config.json for the config snippet.
  • PreToolUse hook adapter (secondary). Routes Claude Code's own native tool calls (Bash, Write, Edit, WebFetch) through the same policy engine and audit log, as claude_code.bash / claude_code.write / claude_code.edit / claude_code.web_fetch in your policy. A require_approval decision here doesn't block the hook (a PreToolUse hook 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 export produces 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.yaml is still the one source of truth for which roles a principal holds. custody approvals approve/deny --as-token can verify an approver's identity against a real OIDC provider's signed token instead of trusting a bare --as string (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 custody/catalog.py this README
Policy engine custody/policy/ docs/policy-reference.md
Signed policy bundles custody/policy/bundle.py docs/policy-reference.md, custody policy sign/verify --help
OPA policy backend (optional, same policy.yaml) custody/policy/opa_backend.py docs/opa-policy-backend.md
Kubernetes deployment k8s/, docker/custody.Dockerfile docs/kubernetes.md
Approval broker custody/approvals/ this README, docs/threat-model.md
SSO/OIDC approver identity (optional, token verification only) custody/approvals/oidc.py docs/sso-oidc.md
Approval notifier (CLI, UI, webhook) custody/approvals/notifier.py docs/policy-reference.md, custody serve --help
Audit log custody/audit/ docs/audit-log.md
S3 Object Lock audit sink (optional, pip install custody-mcp[s3]) custody/audit/s3_sink.py docs/s3-object-lock-sink.md
Evidence-pack export custody/evidence/ docs/evidence-pack.md
Sandbox executor custody/sandbox/ docs/threat-model.md
Egress allowlist proxy custody/sandbox/egress_proxy.py docs/egress-proxy.md, docs/threat-model.md T9
Output guard custody/guard.py this README
Model routing custody/routing.py docs/threat-model.md
Gateway custody/gateway.py this README
Built-in tools custody/tools/ this README
FHIR connector (read-only, FHIR only not OMOP) custody/tools/fhir.py docs/fhir-connector.md
MCP server custody/mcp_server.py docs/integrations/claude-code.md
CLI custody/cli/ custody --help
Local approvals UI custody/approvals_ui.py this README
Claude Code hook custody/hooks/claude_code.py docs/integrations/claude-code.md
PyPI release workflow (Trusted Publishing) .github/workflows/publish.yml 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.

Metadata

Release files for custody-mcp 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for custody-mcp 0.2.0
File Size Uploaded Provenance
custody_mcp-0.2.0.tar.gz 255.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for custody-mcp 0.2.0
File Interpreter ABI Platform
custody_mcp-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 350.0 kB

Release files / custody_mcp-0.2.0.tar.gz

Download URL custody_mcp-0.2.0.tar.gz
Size 255.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5e562366c9825739ec262e914095532707098feea89de363fdf75313885b9383
BLAKE2b-256 checksum
How to use checksums
51a4f1b721d2df3abb5c8a7636a7052481d197be0ad9e2cd0d86375ae6c2646c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / custody_mcp-0.2.0-py3-none-any.whl

Download URL custody_mcp-0.2.0-py3-none-any.whl
Size 94.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
29fba5c40629986d8bb5fd1a6e44aaf5f7889a2365f35fa99bc9710bfa90580c
BLAKE2b-256 checksum
How to use checksums
28441d795f9535420d96524b92a3477a1811f4dd848686b458ebd6a0644e910e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for custody-mcp 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for custody_mcp-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

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