How DCP Works: The Permission Layer Between AI Agents and Your Secrets
How DCP works, explained from the code: the permission layer between AI agents and your keys, credentials, and money. What tools agents get over MCP, how budgets and approvals are enforced, and how remote agents pair with your desktop.
AI agents need access to real things: API keys, credentials, personal data, and money.
The standard advice is to never hand them raw secrets. Good advice. But almost nobody explains what the alternative actually looks like at the protocol level.
This post does. It is a full walkthrough of how DCP works under the hood: where secrets live, how the encryption works, what tools agents get, how budgets and approvals are enforced, and how remote agents connect. DCP is open source, so if you want to verify anything in this post, the code is public.
The short version:
DCP is a permission layer that sits between AI agents and your sensitive resources. Your secrets live in an encrypted vault on your own machine. Agents connect over MCP and request actions. DCP checks the agent's permissions, budget, and your approval policy, then performs the action itself. Secrets are decrypted in memory for milliseconds, used, and wiped. The agent only ever sees the result.
Now the long version.
What Is DCP?
DCP (Delegated Custody Protocol) is an open source permission layer for AI agents. It stores your credentials, API keys, personal data, and wallet in one encrypted local vault, and lets agents request specific actions instead of holding raw secrets themselves.
The core contract:
Agents get capabilities. Users keep custody.
DCP ships as a desktop app plus a set of open source packages:
- @dcprotocol/core handles types, crypto, storage, and the budget engine
- @dcprotocol/vault is the local vault server and policy engine, bound to
127.0.0.1:8421, localhost only - @dcprotocol/agent is the MCP server agents connect to, over stdio or HTTP, plus remote pairing
- @dcprotocol/relay is an encrypted message bus that connects cloud agents to your desktop vault
- @dcprotocol/telegram adds optional approval notifications with Approve and Deny buttons in Telegram
Here is the whole system in one picture:
Local agents Remote agents
(Claude, Cursor, VS Code) (VPS, OpenClaw, workers)
| |
| MCP (stdio / HTTP, | end-to-end encrypted
| localhost only) | relay envelopes
v v
+--------------------------------------------------+
| DCP Vault (127.0.0.1) |
| |
| auth -> scopes -> budgets -> consent -> act |
| |
| encrypted storage: keys, credentials, data |
+--------------------------------------------------+
|
| approval requests
v
Desktop popup / Telegram Approve / Deny
One design decision matters more than all the others: the vault server only binds to localhost. It is never exposed to the network. Remote agents reach it through an encrypted relay, never directly.
How Is the Vault Encrypted?
The vault uses envelope encryption with modern, well audited primitives.
- Cipher: XChaCha20-Poly1305 authenticated encryption, 256-bit keys, a fresh 192-bit random nonce per encryption
- Key derivation: Argon2id with a 64 MB memory cost and 3 iterations, deliberately expensive so brute forcing a passphrase stays slow even on GPUs
- Recovery: a 12-word BIP-39 phrase, shown once at setup and never stored in the vault
Every record gets its own random 256-bit data encryption key (DEK). That DEK is then wrapped by a master key that lives outside the database:
your data
| encrypted with a per-record DEK
v
ciphertext ------------------> stored in SQLite
per-record DEK
| wrapped with the master key
v
wrapped DEK ------------------> stored next to the record
master key ------------------> OS keychain
(hardware-backed on macOS,
0600-permission file fallback)
Why two layers? The master key never touches the database, one compromised record exposes nothing else, and key rotation does not require re-encrypting the whole vault.
Where do the most sensitive keys live?
Wallet keys, passports, and API credentials are just encrypted records like everything else, tagged with a sensitivity level of critical or sensitive. When an approved operation needs one, the vault:
- Unwraps the record's DEK with the master key
- Decrypts the secret in memory
- Performs the operation, for example producing a signature
- Immediately wipes the secret with
sodium_memzero(), a zeroization call the compiler cannot optimize away
The decrypted secret exists for a few milliseconds. It is never written to disk unencrypted, never logged, never sent over any connection, and never returned to an agent through any code path.
What Tools Do Agents Actually Get?
Agents connect to DCP through MCP, the same protocol Claude Desktop, Cursor, VS Code, and OpenClaw use for tools. The tool surface comes in three tiers, sorted by how much damage each tier could do.
Read-only tools, no approval needed:
vault_get_addressreturns the wallet's public addressvault_get_balancesreturns current wallet balancesvault_get_tx_statuschecks a transaction by signaturevault_get_tx_historyreturns recent transaction historyvault_search_tokenssearches the token list by symbol, name, or mintvault_budget_checkanswers whether an amount would pass the limitsvault_scope_guidereturns the canonical list of data scope names
Data tools, governed by per-agent scopes:
vault_readreads scoped personal data, like an API key or a shipping addressvault_writestores scoped data, and always requires consent
Wallet and payment tools, governed by budgets and approval thresholds:
vault_sign_txsigns a transaction with the vault walletvault_sign_messagesigns a wallet messagevault_sign_x402signs an x402 payment payload for pay-per-request APIsvault_transferbuilds, signs, submits, and confirms a transfervault_swapexecutes a token swap
Notice the shape of this API. An agent can check anything freely: its address, balances, whether an amount fits the budget. The moment it wants to act, it crosses into policy territory. That split is intentional. Agents plan without friction and act only with permission.
How Do Scopes and Per-Agent Permissions Work?
Everything in the vault lives under a hierarchical scope name:
identity.email
address.shipping
credentials.api.openai
credentials.api.github
crypto.wallet.*
preferences.diet
Each connected agent has its own list of permitted scopes, and wildcards are supported:
identity.*grants all identity dataread:*grants every read operation and no writes*grants everything, which you almost never want
So your coding agent can have credentials.api.github and nothing else. Your shopping agent can have address.shipping and preferences.*. Your payments agent can have signing access with a tight budget. Same vault, different keys to different doors.
Every scope also carries a sensitivity level: standard, sensitive, or critical. The policy engine treats a passport differently from a T-shirt size.
One more detail that matters. The vault's policy database is the single source of truth. Permissions are not baked into tokens the agent holds. When you revoke an agent, revocation is immediate, because there is no token floating around that still works.
What Happens When an Agent Asks to Act?
This is the heart of DCP. Say an agent calls vault_transfer for 5 USDC. Every request goes through the same pipeline:
agent request
|
v
1. verify request signature (Ed25519) ---- invalid? -> rejected
|
v
2. scope check ---------------------- not granted? -> denied + logged
|
v
3. budget check
| per-transaction limit ------ too big? -> BUDGET_EXCEEDED_TX
| rolling daily limit -------- over cap? -> BUDGET_EXCEEDED_DAILY
v
4. approval threshold
| below threshold -> proceed
| above threshold -> pending consent
| desktop popup or Telegram
| expires in 5 minutes if ignored
v
5. execute inside the vault
| decrypt key, act, zeroize
v
6. immutable audit log
GRANT / READ / EXECUTE / DENY / REVOKE
Some real defaults from the code: 1 USDC per transaction, 5 USDC per rolling day, all configurable per currency and per agent. While a consent is pending, the agent polls every 2 seconds for the outcome. No answer within 5 minutes means no.
There is also a rate limiter on top of all of this: 5 executions per minute per agent session, and 5 failed unlock attempts trigger a 5 minute lockout on the vault itself.
Does auto-approve defeat the purpose?
No, because of what it is allowed to cover.
You can grant an agent a standing approval for specific data scopes, say credentials.api.openai for your coding agent, so it is not prompting you forty times a day. Standing grants last 90 days and are listed, reviewable, and revocable.
Signing and payments are deliberately excluded. There is no blanket switch that always approves spending. Money movement is always bounded by the budget engine and the approval threshold. Small amounts inside your limits flow without friction. Anything above the line asks a human. That is the whole design philosophy in one rule.
How Do Remote Agents Connect Without Exposing the Vault?
Local agents talk to the vault over localhost. Easy.
But real agent workloads increasingly run on a VPS: a personal OpenClaw agent, a monitoring bot, an automation worker. Those machines cannot reach localhost on your laptop, and you should never port-forward a vault to the public internet.
DCP solves this with a relay and a pairing ceremony:
Desktop Relay VPS agent
| | |
|-- 1. generate invite ------------------------------>|
| (vault id, relay URL, |
| vault public key, expiry) |
| | 2. agent generates |
| | its own keypair |
| |<-- 3. signed claim -------|
|<-- 4. claim arrives ----|--- 5-word phrase -------->|
| | |
| 5. both screens show the same 5-word phrase |
| user compares, then approves on desktop |
| | |
|-- 6. approval --------->|--- agent_id ------------->|
| | |
|<========= end-to-end encrypted requests ===========>|
The 5-word verification phrase is the anti-phishing step. If the words on your desktop match the words on the server, you know you are approving that machine and not an attacker who intercepted an invite. Cheap for humans, expensive for phishers.
After approval, every request the remote agent makes is signed with its own keypair and checked against its own scopes and budgets. A remote agent gets no special powers over a local one.
And the part I like most: the relay cannot read any of it. Agent traffic is end-to-end encrypted with HPKE (X25519) using the vault's public key from the invite. The relay routes opaque encrypted envelopes. It cannot see scopes, amounts, or data. It also pins each vault ID to its key on first use, so a different key claiming your vault ID gets rejected. Even a fully compromised relay cannot impersonate your vault or read your traffic.
How Do Agent Payments Work?
Agents are starting to pay for things: metered APIs, data access, services priced per request. The x402 standard handles this over plain HTTP, and DCP gives it a permission boundary.
vault_sign_x402 takes a base64-encoded payment payload plus display metadata (amount, currency, recipient, purpose), runs it through the same budget and approval pipeline as every other spending operation, and returns a signature the agent attaches to its request.
Two properties are worth calling out:
- The payload is immutable. The vault signs exactly the bytes it receives. If anything rewrites the payload along the way, the signature simply fails to verify on the other end. There is no code path where the vault edits a payment.
- The vault does not submit the payment. It signs. The agent handles the network request. Signing authority and network activity stay separated.
This is what makes agent payments workable in practice. Your agent can pay a metered API forty times a day inside a small budget without asking you once, and the forty-first request that crosses the line becomes an approval on your phone instead of a surprise on your statement.
Real Use Cases
Theory is nice. Here is what people actually do with this.
The coding agent with scoped credentials
Claude Code or Cursor needs your GitHub token and an OpenAI key. Instead of pasting them into config files across five projects, they live in the vault under credentials.api.github and credentials.api.openai. The agent reads them through vault_read, covered by a standing grant. Every read is logged. If the agent misbehaves or your laptop policy changes, you revoke once, because the credentials were never scattered in the first place.
The API-paying research agent
A research agent pays per request for a data API through vault_sign_x402. Each payment is tiny and flows automatically under the approval threshold, hard capped by the daily budget. If a prompt injection convinces the agent to send a large payment to a malicious endpoint, the budget engine rejects it before any human needs to notice, and the attempt lands in the audit log.
The remote personal agent
An OpenClaw agent runs around the clock on a VPS, handling tasks that need your context: addresses, preferences, small payments. It paired via invite and verification phrase, talks to your desktop vault through the encrypted relay, and holds zero secrets on the server. If the VPS is ever compromised, the attacker gets a revocable agent keypair. Not your keys, not your data.
The spending agent on a leash
An agent automates purchases or transfers through vault_transfer. Per-transaction and daily caps keep it bounded. Anything above threshold pings your phone with an approval request, and you tap Approve or Deny in Telegram. The agent gets speed inside the box. You hold the box.
Many agents, one vault
The end state is not one agent. It is five or ten: reasoning, coding, research, payments, automation. With DCP that is one vault, one place to look, and a different scope list and budget per agent. Adding an agent is a pairing, not another copy of your secrets. Removing one is a revoke, not a key-rotation weekend.
Threat Model, Honestly
No system removes risk. Good systems bound it.
| Threat | Raw secrets in configs | With DCP |
|---|---|---|
| Prompt injection | Agent acts immediately, no limit | Budget caps, approval threshold, audit trail |
| Agent bug or bad tool call | Unlimited blast radius | Bounded by per-transaction and daily limits |
| Compromised VPS | Secrets are stolen | Only a revocable agent keypair is stolen |
| Compromised relay | Not applicable, vault exposed instead | Sees only encrypted envelopes, key pinning blocks impersonation |
| Secret sprawl | Keys copied into N config files | Secrets live in one encrypted vault |
| No visibility | No record of agent actions | Immutable audit log |
What DCP does not protect against: an attacker who has your unlock passphrase and physical control of your unlocked machine, or approvals you tap without reading. The human gate only works if the human reads the prompt. That will stay true of every approval system ever built.
FAQ
Does the AI agent ever see my private keys or credentials?
Keys, no, never. There is no tool or code path that returns key material to an agent. Credentials are different: an agent with an approved scope can read the credentials you granted it, and every read is logged and revocable. Signing keys stay inside the vault permanently.
What encryption does DCP use?
XChaCha20-Poly1305 authenticated encryption with envelope encryption, a random 256-bit key per record wrapped by a master key in the OS keychain, Argon2id for passphrase derivation, Ed25519 for request signatures, and X25519 HPKE for relay traffic.
Can agents spend without my approval?
Only inside limits you set. Per-transaction caps, rolling daily caps, and an approval threshold are enforced per currency on every spending operation. Above the threshold, a human must approve. There is no way to auto-approve spending wholesale.
Does DCP work with Claude Desktop, Cursor, and OpenClaw?
Yes. Anything that speaks MCP, over stdio or HTTP, can connect: Claude Desktop, Cursor, VS Code, OpenClaw, and custom clients. Remote agents on a VPS connect through the encrypted relay after pairing.
Is the relay a custodian?
No. The relay routes end-to-end encrypted envelopes it cannot decrypt. Keys and policy decisions never leave your machine. If the relay disappeared tomorrow, local agents would be unaffected and remote agents would reconnect through another relay.
Which chains does the wallet support?
Wallet signing currently supports Solana, and the vault, scopes, budgets, and approval system are chain-agnostic by design. A dedicated deep dive on the wallet side is coming next.
Is DCP open source?
Yes. The protocol, vault, agent, relay, and Telegram packages are all open source. You can verify every claim in this post in the code: github.com/1lystore/dcp.
The Bottom Line
The gap between agents that chat and agents that work is trust infrastructure.
Not better models. Not more tools. A boundary you can actually reason about: encrypted custody, scoped permissions, hard budgets, human approval above the line, and a log of everything.
That is what DCP is. Not a cage for agents, but the thing that makes it reasonable to hand them real work.
Give AI agents permissions. Not your keys.
Download DCP Desktop at dcpagent.com, or start with the getting started guide and the architecture docs.
Ready to secure your AI agents?
DCP gives agents permissions, not keys. Download free and open source.
Download DCP