You have a personal AI assistant that can search the web, read documents, and send emails. It delegates research tasks to a cheaper sub-agent. How do you prevent that sub-agent from sending emails as you?
If your answer involves prompt engineering or "it just wouldn't do that," this tutorial is for you.
The problem
Multi-agent frameworks like CrewAI, AutoGen, and LangGraph handle orchestration well. MCP handles tool access. But none of them answer the delegation trust question: when Agent A hands a task to Agent B, what limits B's authority?
DelegateOS solves this with cryptographic delegation tokens. Let's build it step by step.
Setup
npm install delegateos
import {
generateKeypair,
createDCT,
attenuateDCT,
verifyDCT,
createMCPPlugin,
InMemoryRevocationList,
} from 'delegateos';
Step 1: Create identities
Every participant gets an Ed25519 keypair. This is their identity in the delegation system.
const you = generateKeypair(); // Root authority (you)
const assistant = generateKeypair(); // Your main AI assistant
const researcher = generateKeypair(); // Cheap research sub-agent
Step 2: Grant capabilities to your assistant
You create a root Delegation Capability Token (DCT) for your assistant. This token defines exactly what it can do.
const assistantToken = createDCT({
issuer: you,
delegatee: assistant.principal,
capabilities: [
{ namespace: 'web', action: 'search', resource: '*' },
{ namespace: 'docs', action: 'read', resource: '/home/me/**' },
{ namespace: 'email', action: 'send', resource: '*' },
],
contractId: 'ct_daily_tasks',
delegationId: 'del_001',
parentDelegationId: 'root',
chainDepth: 0,
maxChainDepth: 2,
maxBudgetMicrocents: 1_000_000, // $10
expiresAt: new Date(Date.now() + 86400_000).toISOString(), // 24 hours
});
Your assistant can search the web, read your docs, and send emails. With a $10 budget and 24-hour expiry.
Step 3: Delegate research with narrower scope
Here's where it gets interesting. Your assistant delegates to a research sub-agent, but attenuates the token. The sub-agent gets strictly less authority.
const researchToken = attenuateDCT({
token: assistantToken,
attenuator: assistant,
delegatee: researcher.principal,
delegationId: 'del_002',
contractId: 'ct_daily_tasks',
allowedCapabilities: [
{ namespace: 'web', action: 'search', resource: '*.edu/**' },
],
maxBudgetMicrocents: 50_000, // $0.50
expiresAt: new Date(Date.now() + 600_000).toISOString(), // 10 minutes
});
The researcher can only search .edu domains. No docs access. No email. $0.50 budget. 10-minute window. These aren't suggestions. They're cryptographically enforced.
Step 4: Verify at the point of use
When the researcher tries to use a tool, verify the token:
// Allowed: web search on an .edu domain
const allowed = verifyDCT(researchToken, {
resource: 'arxiv.org/search',
namespace: 'web',
operation: 'search',
now: new Date().toISOString(),
spentMicrocents: 0,
rootPublicKey: you.principal.id,
revocationIds: [],
});
console.log(allowed.ok); // true
// Denied: email was never delegated
const denied = verifyDCT(researchToken, {
resource: 'boss@company.com',
namespace: 'email',
operation: 'send',
now: new Date().toISOString(),
spentMicrocents: 0,
rootPublicKey: you.principal.id,
revocationIds: [],
});
console.log(denied.ok); // false
Step 5: Add MCP middleware
If you're using MCP, DelegateOS drops in as middleware:
const plugin = createMCPPlugin({
toolCapabilities: {
web_search: { namespace: 'web', action: 'search' },
read_file: {
namespace: 'docs',
action: 'read',
resourceExtractor: (args) => args.path as string,
},
send_email: { namespace: 'email', action: 'send' },
},
trustedRoots: [you.principal.id],
revocations: new InMemoryRevocationList(),
budgetTracker: { getSpent: () => 0, recordSpend: () => {} },
});
// Every tools/call request gets checked against the caller's DCT
const result = await plugin.handleRequest(mcpRequest);
The plugin also filters tools/list responses. The researcher would only see web_search in its available tools. read_file and send_email don't exist from its perspective.
Step 6: Revoke if needed
Something going wrong? Revoke the delegation instantly:
const revocationList = new InMemoryRevocationList();
revocationList.revoke('del_002'); // Single delegation
// or
revocationList.revokeCascade('del_001'); // Revoke assistant + all downstream
All subsequent verification checks will reject the revoked tokens.
What you get
Sub-agents with cryptographically scoped authority
Budget enforcement across delegation chains
Time-limited delegations with automatic expiry
Mid-flight revocation
MCP integration with zero changes to your existing tools
The full source, docs, and a PR review demo are at github.com/newtro/delegateos. MIT licensed, 374 tests passing.
Top comments (0)