Skip to main content
An AgentRuntimePrincipal limits an invocation to explicitly permissioned capabilities. Create it in trusted code after authenticating the caller or selecting a job’s service identity.
The generated id is an opaque runtime identity. Your application remains the source of user, tenant, role, and policy decisions.
Do not derive permissions from model output or an untrusted request field. Authenticate at your application or gateway boundary, then construct the principal in trusted code.

Mark permissioned capabilities

Every capability that should remain available under a principal must declare a permission. Server and client-hosted tools accept one permission identifier:
An MCP client can require a permission for every remote tool and add requirements to individual tools:
mcp/catalog.py
permission= applies to every tool from that client. A matching tool_permissions entry is an additional requirement. Permission identifiers start with a letter and can contain letters, numbers, ., _, :, or -. When you omit the client-wide permission, only operations named in tool_permissions can be available under a principal. Untagged MCP operations remain unavailable.

Grant permissions on built-in routes

Define one grant hook in the root agent’s lifecycle/ directory. Harnest passes it the connection and the identity established by authentication. Use verified claims or look up permissions in your application.
lifecycle/grants.py
This example lets any caller start a turn, but only callers with the verified refund claim can use tools tagged refunds.write. Return None to deny the invocation entirely. The hook may also be async. The hook covers /responses (including streaming), AG-UI, live WebSocket connections, and A2A. Live resolves the grant at the handshake; resumed runs keep their original grants. Without a hook these routes keep their previous tool surface unless server.agentPrincipal: required is set. With that setting, these Harnest routes refuse new invocations without a principal. In advanced ADK mode, native /run, /run_sse, and /run_live invocations bypass this hook, including when grants are required. Apply separate authorization if you expose those endpoints.

Invoke with a principal

Pass the principal through a trusted custom HTTP endpoint:
You can also pass agent_principal= to an in-process AgentSession.invoke(...) or AgentSession.stream(...) call. Harnest removes untagged and unmatched capabilities from Harnest-owned model tool surfaces and checks the permission again at execution. Treat the execution check as defense in depth. The downstream service must still authorize the actual operation.

Understand omission and propagation

Queued Task and external-continuation states contain only permission identifiers. They do not serialize the principal ID, authentication claims, or credentials. A scheduled Task can construct and pass an explicit service principal in trusted task code when it needs declared capabilities.

Managed and advanced modes

In advanced mode, Harnest enforces the principal for Harnest-decorated server tools, client-hosted tools, configured MCP clients, local agent invocation, and queued Task propagation when those operations cross Harnest runtime boundaries. Native tools and graph paths you wire directly can bypass Harnest checks. Enforce equivalent policy there or at a downstream gateway.
The principal is private runtime state rather than a property on harnest.context. Tools and extensions declare required permissions; they do not read or make policy decisions from the active principal.

API reference

Reference: harnest.mcp.