Tenuo MCP Server
Task-scoped authorization for AI agents. Cryptographic warrants constrain tools and arguments, prevent privilege escalation at every delegation hop, and produce signed evidence of what was allowed or denied.
Tenuo is an open-source mcp server by tenuo-ai, written mainly in Rust, with 104 GitHub stars and the Apache-2.0 license. Its code was last updated Oct 31, 2026. The latest PyPI release is tenuo 0.3.7, published Nov 12, 2026, with 5,339 downloads last week.
Tenuo lets you define what an agent may do for a task, carry that authority across services and agent handoffs, and enforce it where actions execute. Each handoff can only narrow the authority granted.
That authority travels as a warrant: a signed grant specifying allowed tools, argument constraints, and an expiry.
- Across frameworks and runtimes. Delegate between agents and services using different languages and frameworks.
- Across organizations and trust domains. Grant limited authority to others and independently verify the authority you receive.
- Online or air-gapped. Verify locally without contacting a central authorization service, using provisioned trust keys and local revocation state.
Open source. Works alongside your existing identity and policy systems.
Install
# Python
pip install tenuo
# TypeScript (beta, Node 20+)
npm install @tenuo/core@beta
# Rust
cargo add tenuo --features sdk
To try Tenuo without installing an SDK:
<a href="https://colab.research.google.com/github/tenuo-ai/tenuo/blob/main/notebooks/tenuo_demo.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a> <a href="https://tenuo.ai/explorer/"><img src="https://img.shields.io/badge/Explorer-decode_warrants-1a1a1a" alt="Explorer"></a> <a href="https://tenuo.ai/demo.html"><img src="https://img.shields.io/badge/Docker_Demo-delegation_chain-333333" alt="Docker Demo"></a> <a href="https://niyikiza.com/posts/tenuo-launch/"><img src="https://img.shields.io/badge/Blog-Why_Tenuo%3F-ff6b6b" alt="Blog"></a>
<a id="quick-start-from-one-tool-to-delegated-work"></a>
Quick Start
Give an agent permission to request up to ten replicas. Calls outside that limit are blocked before the function executes. These examples simulate the action by returning a message.
Python
Save as quickstart.py and run python quickstart.py.
from tenuo import Capability, Range, SigningKey, configure, guard, mint_sync
from tenuo.exceptions import AuthorizationDenied
# Local development setup.
configure(issuer_key=SigningKey.generate(), dev_mode=True, audit_log=False)
@guard(tool="scale")
def scale(replicas: int) -> str:
return f"Requested {replicas} replicas"
with mint_sync(Capability("scale", replicas=Range.max_value(10)), ttl=60):
print(scale(3))
try:
scale(20)
except AuthorizationDenied:
print("Blocked before the function ran")
TypeScript · Beta
Save as quickstart.mts and run npx tsx quickstart.mts.
import { AuthorizationDeniedError, createTenuo, range } from "@tenuo/core";
// Local development setup: this process holds the issuance key.
const tenuo = createTenuo({
root: createTenuo.issuerKeyFromBytes(createTenuo.generateIssuerKey()),
});
const scale = tenuo.tool(
{
execute: async ({ replicas }: { replicas: number }) =>
`Requested ${replicas} replicas`,
},
{ capability: "scale", allow: { replicas: range({ max: 10 }) } },
);
const session = tenuo.session({ tools: [scale], ttlSeconds: 60 });
await tenuo.withSession(session, async () => {
console.log(await scale.execute({ replicas: 3 }));
try {
await scale.execute({ replicas: 20 });
} catch (error) {
if (!(error instanceof AuthorizationDeniedError) ||
error.code !== "TENUO_CONSTRAINT_VIOLATION") throw error;
console.log("Blocked before the function ran");
}
});
Both examples produce:
Requested 3 replicas
Blocked before the function ran
These examples keep issuance and enforcement in one process for development. Python's dev_mode=True also relaxes trust-root and audit-log checks. To enforce limits against an untrusted agent, keep issuance keys outside its reach and verify at a tool service or gateway it cannot bypass. The MCP walkthrough shows that setup with a server that holds only the issuer's public key. The Production Guide covers enforcement modes, rollout, and key management.
Leaving the scoped block ends its local authorization context; it does not revoke a signed warrant. Keep warrant lifetimes short.
Continue with: Python guide · TypeScript guide · Rust guide · MCP walkthrough
For the TypeScript guide's development examples, set NODE_ENV=development.
Delegate Across Boundaries
A task can move between agents, frameworks, and services while retaining its authorization limits.
Issuer Orchestrator Worker
Grants authority → Narrows for a subtask → Presents warrant
↓
Receiving service
Verifies before acting
For example, a Python orchestrator can delegate a narrower warrant to a TypeScript worker calling a Rust service. The receiving service verifies the chain against its configured trusted roots, then checks the caller's proof of possession and the requested action against the warrant.
A delegated warrant can only narrow its parent.
Examples: Python delegation example · TypeScript delegation guide
<a id="python-delegation-example"></a>
<details> <summary>Python delegation example</summary>from tenuo import Range, SigningKey, Warrant
from tenuo.exceptions import MonotonicityError
issuer = SigningKey.generate()
orchestrator = SigningKey.generate()
worker = SigningKey.generate()
root = (Warrant.mint_builder()
.capability("scale", replicas=Range.max_value(10))
.holder(orchestrator.public_key)
.ttl(300)
.mint(issuer))
# The orchestrator hands the worker a lower limit and a shorter lifetime.
worker_warrant = (root.grant_builder()
.capability("scale", replicas=Range.max_value(5))
.holder(worker.public_key)
.ttl(60)
.grant(orchestrator))
try:
(root.grant_builder()
.capability("scale", replicas=Range.max_value(50))
.holder(worker.public_key)
.ttl(60)
.grant(orchestrator))
except MonotonicityError:
print("Rejected: a child cannot raise the limit")
</details>
Sensitive actions can also require a signed human approval.
Explore: Python MCP delegation demo · Security model · Supported integrations
Integrate at the Boundary You Control
Tenuo uses the same warrant format and attenuation rules everywhere. Pick the enforcement point that fits. Authority crosses these boundaries without translation.
| Enforcement point | Use it when | Integrations | Start here |
|---|---|---|---|
| Inside the agent runtime | You own the application and want the shortest path to enforcement | Python functions, OpenAI, LangChain, LangGraph, Google ADK, CrewAI, AutoGen, Hermes Agent, Rust Guard | @guard, OpenAI, Hermes, Rust, framework guides |
| At the MCP tool server | Agents call tools across a process or vendor boundary | FastMCP, official MCP SDK, custom MCP servers | MCP guide |
| At an API or service edge | Multiple agent runtimes share the same downstream services | FastAPI, authorizer sidecar, gateway, Kubernetes | FastAPI, Kubernetes |
| Inside a durable workflow | Authority must survive retries, queues, and long-running execution | Temporal | Temporal guide |
| At an agent handoff | One agent delegates part of a task to another agent | A2A, MCP warrant stacks | A2A guide, delegation demo |
These are deployment choices for one authorization system. A warrant can be verified anywhere its issuer is trusted, and every delegated warrant must remain within its parent.
Security Boundaries
Tenuo checks the warrant and the actual tool arguments before an action executes. Enforcement must run at a boundary the agent cannot modify or bypass; an in-process guard alone does not isolate an untrusted agent.
Tenuo complements your identity system and policy controls. Use a container or VM when you need process isolation. For disconnected deployments, provision trusted keys and revocation state in advance; offline verification cannot discover revocations it has not received.
See the security model for guarantees and limitations.
Deploying to Production
The self-hosted core and sidecar are Apache-2.0 and run entirely in your infrastructure, with no external calls at verification time.
Self-hosted checklist:
- Store signing keys in a secrets manager (Vault, AWS Secrets Manager, GCP Secret Manager). Keep them out of environment variables
- Configure
trusted_rootswith your control plane's public keys - Ensure
dry_runis disabled and warrants are required in all enforcement points - Enable audit callbacks and metrics for observability
See the Production Guide for enforcement modes, gradual rollout, and key management, and the Security Model for the full threat model.
Tenuo Cloud (Optional)
Tenuo Cloud is an optional managed control plane for issuance, key rotation, hosted revocation distribution, observability, and multi-tenant isolation. Verification stays local. Self-hosted Tenuo already verifies warrants and signed revocation lists (SRLs) in your own infrastructure.
Docker & Kubernetes
Try the Demo:
docker compose up
This runs the orchestrator -> worker -> authorizer stack: issuance, delegation, and verification.
Official Images on Docker Hub:
docker pull tenuo/authorizer:0.3.7 # Sidecar for warrant verification
docker pull tenuo/control:0.3.7 # Control plane (demo/reference)
Helm Chart:
helm install tenuo-authorizer ./charts/tenuo-authorizer \
--set config.trustedRoots[0]="YOUR_CONTROL_PLANE_PUBLIC_KEY"
See Helm chart README and Kubernetes guide.
Documentation
| Resource | Description |
|---|---|
| AI Agent Delegation Security Lab | A hands-on lab: six agents, one rogue, five core levels plus two optional bosses |
| Quickstart | Get running in 5 minutes |
| Concepts | How warrants and attenuation work |
| Constraints | All 11 constraint types explained |
| Security | Threat model and guarantees |
| OpenAI | Direct API protection with streaming |
| Google ADK | ADK agent tool protection |
| AutoGen | AgentChat tool protection |
| Hermes Agent | Official Hermes plugin for signed, expiring tool authorization |
| A2A | Inter-agent delegation |
| FastAPI | Protect FastAPI routes |
| LangChain | Tool protection |
| LangGraph | Multi-agent graph security |
| CrewAI | Multi-agent crew protection |
| Temporal | Durable workflow authorization |
| MCP | Model Context Protocol client + server verification |
AI Coding Agents
Install Tenuo's implementation skill so a supported coding agent can place authorization at the effect boundary, use the SDK version in your project, and generate both allow and deny-before-effect tests:
npx skills add tenuo-ai/tenuo --skill tenuo-agent-authorization
The skill distinguishes an in-process guardrail from an independently enforced boundary and reports the guarantee and remaining bypasses explicitly. It does not ask the agent to reimplement Tenuo's cryptography or protocol.
Try It: The AI Agent Delegation Security Lab
A travel assistant made of six AI agents is booking a spring-break trip. One of them has been told to do something it shouldn't. Secure the system so the trip still happens and the rogue agent gets nowhere.
git clone https://github.com/tenuo-ai/tenuo
cd tenuo/labs/agent-delegation
npm install
npm run lab
Five main levels plus two optional bosses, no agent-framework experience needed. Book the trip, stop the rogue agent, and learn why each handoff should carry only the authority its task needs. Runs offline with free retries and no API key. The guide is at tenuo.ai/lab; the code is in labs/agent-delegation.
Requirements
| Component | Supported |
|---|---|
| Python | 3.9 - 3.14 |
| Node.js | Beta. Node 20+ (npm i @tenuo/core@beta) |
| OS | Linux, macOS, Windows |
| Python installation | Prebuilt wheels for Linux (x86_64 and aarch64), macOS (arm64), and Windows (x64). Other platforms build from source and need Rust |
Optional Dependencies
With uv, use uv pip install in place of pip install.
pip install tenuo # Core only
pip install "tenuo[openai]" # + OpenAI Agents SDK
pip install "tenuo[google_adk]" # + Google ADK
pip install "tenuo[a2a]" # + A2A (inter-agent delegation)
pip install "tenuo[fastapi]" # + FastAPI integration
pip install "tenuo[langchain]" # + LangChain (langchain-core ≥0.2)
pip install "tenuo[langgraph]" # + LangGraph (includes LangChain)
pip install "tenuo[crewai]" # + CrewAI
pip install "tenuo[temporal]" # + Temporal workflows
pip install "tenuo[autogen]" # + AutoGen AgentChat (Python ≥3.10)
pip install "tenuo[mcp]" # + official MCP SDK, client & server verification (Python ≥3.10)
pip install "tenuo[fastmcp]" # + FastMCP (TenuoMiddleware / FastMCP servers)
pip install "tenuo[cloud]" # + Tenuo Cloud SDK (proprietary control-plane client)
Rust
The core crate is the protocol. The sdk feature is the enforcement surface: a guard that checks a call before it runs, an authority that binds a warrant chain to a signing key, cryptographic delegation, an observe mode, and MCP and HTTP transports.
[dependencies]
tenuo = { version = "0.3.7", features = ["sdk"] }
use std::time::Duration;
use tenuo::sdk::prelude::*;
use tenuo::{args, constraints};
let root = SigningKey::generate(); // in production this lives in your control plane
let holder = SigningKey::generate();
let warrant = Warrant::builder()
.capability("read_file", constraints! { "path" => Pattern::new("/data/*")? })
.holder(holder.public_key())
.ttl(Duration::from_secs(300))
.build(&root)?;
let runtime = Runtime::builder()
.holder(holder)
.trusted_root(root.public_key())
.revocation(RevocationMode::TtlOnly { max_lifetime: Duration::from_secs(600) })
.build()?;
let session = runtime.session_from_warrant(warrant)?;
let allowed = Call::owned("read_file", args! { "path" => "/data/report.csv" })?;
let out = session.guard(&allowed, |_| Ok::<_, std::io::Error>("read"))?;
assert_eq!(out.into_inner(), "read");
let refused = Call::owned("read_file", args! { "path" => "/etc/shadow" })?;
assert!(session.check(&refused).is_err());
The closure runs only after an allow. A call outside the constraint is denied before it runs, same as Python @guard. A guard with no trust root or no revocation policy does not compile.
Features, all off by default: sdk, mcp-transport, http-transport, async, receipts, otel, test-utils. The default build adds no extra crates.
Use Rust for authorizer sidecars, gateways, MCP servers built on rmcp, and any service that needs enforcement without a Python runtime.
- API docs: docs.rs/tenuo
- Security model: tenuo.ai/security
- Constraints reference: tenuo.ai/constraints
How It Works
Tenuo is capability-based authorization. A warrant is a capability: a signed grant that lists the tools an agent may call, the argument values it may pass, the key that may use it, and when it expires. The warrant travels with the request. The verifier uses the trusted issuer key and locally available revocation state.
Holder-bound. Every warrant names a public key. Every call carries a signature from that key over the warrant, the tool, the exact arguments, and a short time window. A copied warrant is useless without the key.
Verified offline. The warrant carries its own authority and signature. Checking it needs no lookup and no network. Checks run in under 50 μs, and enforcement keeps working when the control plane is down.
Attenuates monotonically. Delegation mints a child warrant signed by the parent's holder. The verifier walks the whole chain from a trusted root to the leaf. Each link may drop tools, tighten constraints, or shorten expiry. No delegated warrant can exceed its parent. Tenuo calls this Subtractive Delegation.
Holds under prompt injection. The check never asks the model. It runs at the tool boundary, on the real arguments, after the model has chosen what to call. A hijacked agent can only make the calls its warrant already allowed.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Control Plane │ │ Orchestrator │ │ Worker │
│ │ │ │ │ │
│ Issues root │────▶│ Attenuates │────▶│ Executes with │
│ warrant │ │ for task │ │ proof │
└──────────────────┘ └──────────────────┘ └──────────────────┘
Full scope --> Narrower --> Narrowest
- Control plane issues a root warrant with broad capabilities
- Orchestrator attenuates it for a specific task; scope can only shrink
- Worker proves possession of the bound key and executes
See Concepts for the model and Related Work for how this compares to Biscuit, Macaroons, UCAN, and CaMeL.
Why Tenuo?
IAM answers who you are. Tenuo answers what this workload may do for this task, right now. Agents stay free to plan and pick tools. The warrant still applies after they choose.
| Existing limitation | Tenuo |
|---|---|
| IAM typically grants authority by identity or role | Warrants limit authority to the current task |
| Conventional agent handoffs do not carry the original authorization context | Authority travels with the work and can only narrow |
| Plain bearer tokens can be copied or replayed | Every warrant is bound to the key using it |
| Central policy checks introduce a runtime dependency | Signed authority is verified locally at execution |
| Generic string matching can disagree with downstream systems | Semantic constraints interpret arguments as the target does (why this matters) |
Signed authorization receipts are opt-in when you need to show why a call was allowed or denied.
Prior Art
Tenuo builds on capability token ideas described in CaMeL (Debenedetti et al., 2025). Inspired by Macaroons, Biscuit, and UCAN.
The token format and delegation protocol are specified in Attenuating Authorization Tokens for Agentic Delegation Chains, an active individual Internet-Draft in the IETF OAuth Working Group. The core attenuation rules are formally verified with Alloy (capability and argument-key monotonicity) and Z3 (constraint-type subsumption bounds).
See Related Work for detailed comparison.
Featured In
- TLDR InfoSec - "The Map is not the Territory: The Agent-Tool Trust Boundary"
- TLDR InfoSec - "Capabilities Are the Only Way to Secure Agent Delegation"
- Awesome Object Capabilities - Curated list of capability-based security resources
- Awesome LangChain
- Awesome LLM Agent Security
- Awesome LLMSecOps
Etymology
Tenuo (/tɛn-ju-oʊ/ • Ten-YOO-oh)
From Latin tenuare: "to make thin; to attenuate." Authority starts broad at the root and is attenuated as it flows down the delegation chain.
Contributing
Tenuo is Apache-2.0 and built in the open. The core is Rust, with Python and TypeScript SDKs on top. Good places to start:
- Framework integrations. Adapters live in
tenuo-python/tenuo/. The integration guide covers the required API patterns and invariant tests. OpenAI and Google ADK are good templates. - Constraint types. There are 11 today. A new one has to parse input the same way the target system does.
- The Rust SDK. New in 0.2.4. Adapters for Rust agent frameworks are open ground.
- The TypeScript SDK. It is in beta and needs real-world use.
- Docs and examples. If a guide confused you, that is a bug worth filing.
See CONTRIBUTING.md for setup, tests, and the PR process.
Security issues: Email security@tenuo.ai with PGP (key). Please do not open public issues for these.
License
Apache-2.0. See LICENSE for details.
Tenuo alternatives
View more →Similar mcp servers in Finance & Trading, ranked by GitHub stars. Compare licence, recent activity and scan status before you choose.
| Name | Stars | Licence | Last updated | Scan |
|---|---|---|---|---|
| Tenuo (this page) tenuo-ai | 104 | Apache-2.0 | Oct 31, 2026 | Scanned, no flagged issues |
| QuantDinger OpenByteInc | 13k | Apache-2.0 | Nov 1, 2026 | Scanned, no flagged issues |
| FinanceToolkit JerBouma | 5.5k | MIT | Nov 1, 2026 | Scanned, no flagged issues |
| Tradingview MCP atilaahmettaner | 5.2k | MIT | Oct 29, 2026 | Scanned, no flagged issues |
| Aktools akfamily | 1.5k | MIT | Nov 1, 2026 | Scanned, no flagged issues |
| Tradememory Protocol mnemox-ai | 1.4k | MIT | Oct 23, 2026 | Scanned, no flagged issues |