Skip to main content
An agent under Humanos has a key, declares the tools it can call, and asks Humanos before every call. Your organization’s policy decides each call; a tool the policy leaves to a person runs only under a mandate that person grants. Every decision and every outcome is a signed event on the agent’s audit trail. Pick how your agent connects in the selector at the top of the page:
  • Agent SDK: an agent you write in TypeScript, holding its own key. It can also govern MCP servers you did not write.
  • MCP: an MCP client, such as Claude Code, Claude Desktop or Cursor, acting as the agent. Humanos holds its key.

How a call is decided

Humanos decides each call in this order:
  1. The agent. A suspended or retired agent, or a revoked key, is refused whatever the tool.
  2. The policy. The tool’s access, set on the dashboard’s Policy page:
A control is a set of rules over a call’s inputs, chosen for a tool on the Policy page. A control of type Mandate also declares the limits a person sets when granting a mandate under it, such as a refund cap.
The SDK steps need the Quick Start setup: the SDK installed, and an API key with its Signature Secret.With npx humanos init and a framework adapter, or via(), registering, declaring and guarding are done for you: see Agent SDK. The steps below build each piece yourself, for an agent that needs to.

1. Register the agent

The agent’s key is its identity. registerAgent proves the agent holds the key and returns its DID; every call after is signed with that key.
Humanos grades how the key is held and returns the grade as granted. storedSoftwareKey creates the key in the file on the first run and loads it on every run after, so registering again returns the same DID: a new key is a new agent, and its mandates stay with the old one. Keep the file like the API key, out of the repository. Where no file persists, softwareKeyFromJson reads the file’s content from a variable; softwareKey() creates a key that lasts only as long as the process. Any key store works through the ViaAgentKey interface (publicJwk, sign, evidence), so a key that never leaves its KMS or enclave signs the same way.

2. Declare its tools

Humanos governs the tools the agent declares. Declare each one as its server describes it: name, description, inputSchema, outputSchema and annotations, grouped by service.
Declare again whenever the tools change. A tool left out of a service’s new declaration is kept and marked as no longer declared; { emptyServices: ["Files"] } marks every tool of a service the agent stopped using. A service takes at most 500 tools per declaration.

3. Set the policy

Until you set the policy, nothing is enforced: every tool follows the default, which allows it.
  1. In the dashboard, open Policy, under Agents in the sidebar. The tools the agent declared are listed there.
  2. Choose Allow, Restrict, Delegate or Deny for each tool.
  3. For a tool set to Restrict, choose the control whose rules it runs within. A tool set to Delegate runs under any mandate a person grants, a plain authorization included; choose a mandate control to require one under it.
  4. To refuse every tool you have not set, change the policy’s default to deny.
  5. Publish the policy. Nothing changes for your agents until you do. The dashboard asks you to confirm with your passkey or a code sent to your email; only a manager or an owner can publish.
getPolicy(client, did) returns the policy as the agent meets it: each declared tool’s access, its meaning in one sentence, and the controls behind it.

4. Guard every call

For each call the guard:
  1. Picks the mandate the call presents, if any. policyMandates reads the policy and the agent’s mandates, and presents one only for a tool set to Delegate.
  2. Gets a single-use challenge, signs the tool and its parameters with the agent’s key, and asks Humanos to verify.
  3. Runs the tool on allow, then reports the outcome: completed, or failed with the error, which it rethrows.
  4. Throws ViaDeniedError on deny, with reason and the rule evaluations. The tool never runs.
To guard an existing tools object without changing its call sites, guard.interceptTools(tools) replaces each function in place; a guarded tool returns its own result and throws ViaDeniedError on a deny.mode: "observe" runs the whole check and records every decision, but runs the tool even when the decision is deny. Use it to see what a policy would block before enforcing it.

5. When a tool needs a person’s mandate

A call to a tool set to Delegate with no mandate covering it is denied mandate_required, and ViaDeniedError.request says what to ask for:
  • A guardrail (kind: "guardrail"): a mandate under one of the controls in actionIds. getAction returns the control’s limits; your agent fills in their values.
  • An authorization (kind: "authorization"): with no control for the tool, a mandate in plain words. It allows one call and ends in an hour, unless maxExecutions and validUntil say otherwise.
Whom to ask, and the values of the limits, come from your agent’s own context.
waitForMandate returns once the person decides (ACTIVE, REJECTED or INACTIVE), or still PENDING at the earlier of the consent link’s expiry and ten minutes; until changes the deadline and signal stops the wait. The call after an approval presents the new mandate on its own. mandateStatus checks once, for an agent that waits its own way.

6. Govern MCP servers you did not write

startViaMcpProxy puts the guard in front of MCP servers you connect to but did not write. It merges their tools, declares them to Humanos by service, and verifies every call before it reaches the server.
An upstream is a remote server (url, headers) or a local one (command, args, env). Your MCP host connects to the proxy as it would to any MCP server. The proxy presents a mandate only for a tool set to Delegate: the one whose control lists the tool, or whose person allowed it. Every other call is decided on the policy alone.For a remote server, an allowed call also carries its call proof: the proxy sends it with the call, in _meta and in the Humanos-Call-Proof and Humanos-Agent-Record headers, so the server can check that Humanos verified the call.

7. Test without a platform

createTestVerifier decides calls in process, with the same rules and policy the connector applies.

Deny reasons

A deny is a decision, not an error: the agent asked for something it is not allowed to do.

Audit trail

Every decision, every outcome and every mandate a person grants or revokes is a signed event, hash-chained to the agent’s record. The dashboard shows it on the agent’s Audit trail.