Get started
Pick the path that matches what you already run. Each one ends with a test that proves the refusals work, because a permission layer you have not seen refuse something is not one you can rely on.
npm install @aroha-sdk/core @aroha-sdk/credentialspip install "aroha>=2"A
Wrap an MCP server
Anyone using MCP tools in an assistant such as Claude Code, Cursor or Claude Desktop.
A config change, no code.
Path A in the integration guidemcp-guard sits between the assistant and the server. Matching tools are refused, wait for a person to approve, or stop after a set number of calls. List the server's real tool names first: rules match names, and every server names things its own way.
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@aroha-sdk/mcp-guard",
"--name", "github",
"--block", "*delete*,*remove*",
"--gate", "merge_*,push_*,create_*,update_*",
"--limit", "*:50",
"--",
"npx", "-y", "@modelcontextprotocol/server-github"]
}
}
}B
Verify mandates in a handler
Teams whose API or tool server agents call.
About 10 lines.
Path B in the integration guideOne call checks the agent's proof over this exact request, the chain back to the customer, every limit on every link, and charges the running total, all or nothing.
import { verifyHttpSpendRequest, enrolledDid, httpRevocationCheck } from "@aroha-sdk/credentials";
const r = await verifyHttpSpendRequest(req.headers["aroha-mandate"], {
audience: "https://invoices.example.com",
method: req.method, url: req.url, body: rawBody, // the exact bytes received
expectedRoot: await enrolledDid(enrollments, customerId),
isRevoked: httpRevocationCheck(REGISTRY_URL),
amountUsd: invoice.amountUsd, currency: "USD",
nonces, ledger,
});
if (!r.ok) return reply(res, r.status, { error: r.code }); // nothing was chargedfrom aroha import verify_http_spend_request
from aroha.enrollment import enrolled_did
r = verify_http_spend_request(
request.headers.get("aroha-mandate"),
audience="https://api.example.com", method=request.method, url=url, body=raw,
expected_root=enrolled_did(ENROLLMENTS, invoice["customerId"]),
is_revoked=None, # or a revocation check; you must choose
amount_usd=invoice["amountUsd"], currency="USD",
nonces=NONCES, ledger=LEDGER,
)
if not r.ok:
return JSONResponse({"error": r.code}, status_code=r.status)A person grants, an agent narrows, and the narrower token travels with every call the next agent makes.
import { generateKeyPair, generateDid } from "@aroha-sdk/core";
import { issueIntentMandate, attenuateToPayment } from "@aroha-sdk/credentials";
// The person grants their assistant $500 for airline fares, for one hour.
const intent = await issueIntentMandate(
personDid, assistantDid,
{ spendLimitUsd: 500, merchantCategory: "4511" },
person.privateKey, 3_600_000,
);
// The assistant passes $300 of it to the flight agent: any agent can narrow what it was given.
const payment = await attenuateToPayment(
intent, flightAgentDid,
{ spendLimitUsd: 300, merchantCategory: "4511" },
assistant.privateKey,
);D
Run the Aroha runtime
A person's own assistant, on their own machine.
Not yet released.
What the runtime supportsThe runtime is a desktop assistant built on Aroha: tools are denied until a person allows them, approvals become signed, revocable permissions, and actions leave receipts. It is not yet available as a download. Paths A to C work today.
E
Connect a hosted assistant
People using ChatGPT and dots, Claude and Duet, or Muse.
Coming soon.
The remote connectorThese assistants add tools through remote MCP connectors. Aroha's connector, @aroha-sdk/mcp-server in remote mode, is published: each person gets their own key, sensitive actions ask first, and every approval becomes a signed limit. It has not yet been tested with each assistant, so we do not call it supported. Setup guides will follow the tests.
SDKs
Every SDK checks the same test vectors. Feature matrix.
| Language | Package | Published | Status |
|---|---|---|---|
| TypeScript | @aroha-sdk/credentials | 2.0.0 | Reference implementation |
| Python | aroha | 2.1.0 | Beta |
| Go | sdks/go | No | Partial, not yet published |
| Java | com.aroha-labs:aroha-sdk | No | Partial, not yet published |
Using a coding agent?
Point it at the integration guide. It is written as an Agent Skill: the agent picks a path, applies it, and proves each refusal before it reports done. For everything else, llms.txt indexes the documentation as plain text.
Stuck? Ask in GitHub Discussions or email contact@aroha-labs.com.