mesh7 Python SDK
Governance mesh for AI agent tool calls. Wraps any Python function with policy enforcement, human approval, and tracing via flux7-mesh.
Install
pip install flux7-mesh
pip install flux7-mesh[anthropic] # with Claude API support
Quick start
Direct client
from mesh7 import AgentMesh
mesh = AgentMesh("http://localhost:9090", agent="my-agent")
# Check what's available
tools = mesh.tools()
health = mesh.health()
Identity: self-declared or a JWT
agent="my-agent" is a self-declared identity, sent as Bearer agent:my-agent.
A mesh that validates JWTs (auth.jwt set, allow_legacy off) rejects it.
Pass the token your identity provider issued instead:
mesh = AgentMesh("https://mesh.example.com", agent="my-agent", token=jwt)
The mesh then resolves the agent from the token's claims — and, if the token
carries one, the human the agent acts for (user_claim), which lands on every
trace. The same token= exists on GovernedToolkit and MeshHooks; the CLI
hook reads it from MESH7_TOKEN.
Policy check only (POST /decide) — no execution
decision = mesh.decide("filesystem.write_file", {"path": "/tmp/x"}) print(decision.action) # allow | deny | human_approval
Full proxy (POST /tool/{name}) — policy + execute + trace
decision = mesh.call_tool("filesystem.read_file", {"path": "/tmp/data.txt"}) print(decision.result)
Manage grants
mesh.create_grant("filesystem.*", "30m") mesh.revoke_grant("grant-id")
### GovernedToolkit (Claude API)
```python
from mesh7 import GovernedToolkit
toolkit = GovernedToolkit(agent="my-agent")
@toolkit.tool
def get_weather(city: str) -> str:
"""Get current weather for a city."""
return fetch_weather(city)
@toolkit.tool
def send_email(to: str, subject: str, body: str) -> str:
"""Send an email."""
return smtp_send(to, subject, body)
# Generate tools[] for Claude API — names are namespace-qualified
schemas = toolkit.schemas()
# [{"name": "my-agent__get_weather", ...}, {"name": "my-agent__send_email", ...}]
# Process tool_use blocks with governance
response = client.messages.create(model="claude-sonnet-4-6", tools=schemas, ...)
results = toolkit.process_response([b.model_dump() for b in response.content])
The toolkit:
schemas()— generates thetools[]array with namespace-qualified names (e.g.my-agent__get_weather)process_response()— interceptstool_useblocks, checks policy via mesh7, executes locally if allowedexecute()— single tool call with governance (accepts API-safe, qualified, and bare names)
Tool names are namespace-qualified with the agent name. The Claude API rejects dots in tool names (the schema is ^[a-zA-Z0-9_-]{1,128}$), so schemas() emits the API-safe form my-agent__get_weather (double underscore). On the way back in, execute()/process_response() map it to the dotted form my-agent.get_weather that mesh7 evaluates — so policy authors still write one name format (agent.tool) regardless of call path, matching the MCP proxy server.tool convention. Use namespace="custom" to override the prefix.
Fixed in 0.4.1. Versions ≤ 0.4.0 emitted dotted names from
schemas(), which the Claude API rejected withtools.0.custom.name: String should match pattern. Upgrade if you call the Claude Messages API throughGovernedToolkit.
MeshHooks (Agent SDK)
from mesh7 import MeshHooks
hooks = MeshHooks(agent="my-agent")
# Ready for Anthropic Agent SDK
options = ClaudeAgentOptions(hooks=hooks.agent_sdk_hooks())
Every tool call goes through mesh7's /decide endpoint. Same YAML policies, same tracing, same grants and rate limits as Claude Code or any other mesh7-connected agent. No policy duplication.
| mesh7 action | Agent SDK | Effect |
|---|---|---|
allow |
allow |
Tool executes |
deny |
deny |
Tool blocked with reason |
human_approval |
ask |
User prompted in terminal |
Options:
| Param | Default | Description |
|---|---|---|
tool_matcher |
".*" |
Regex pre-filter (which tools hit mesh7) |
fail_action |
"deny" |
Behavior when mesh7 is unreachable |
See examples/agent-sdk-hooks/ for a complete example.
Prerequisites
mesh7 daemon running:
mesh7 serve --config config.yaml
API
AgentMesh(url, agent, timeout)
| Method | Description |
|---|---|
decide(name, args) |
Evaluate policy without executing |
call_tool(name, args) |
Execute tool through governance (proxy) |
tools() |
List available tools |
approvals() |
List pending approvals |
approve(id) / deny(id) |
Resolve approval |
grants() |
List active grants |
create_grant(tools, duration) |
Create temporal grant |
health() / is_healthy() |
Check mesh status |
GovernedToolkit(agent, url, namespace)
| Method | Description |
|---|---|
@toolkit.tool |
Decorator to register a function |
schemas() |
Generate Claude API tools array |
execute(name, input) |
Governed execution |
process_response(content) |
Process Claude response blocks |
MeshHooks(agent, url, tool_matcher, fail_action)
| Method | Description |
|---|---|
agent_sdk_hooks() |
Return hooks dict for ClaudeAgentOptions |
Metadata
Release files for flux7-mesh 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flux7_mesh-0.6.1.tar.gz | 15.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flux7_mesh-0.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.2 kB
Release files / flux7_mesh-0.6.1.tar.gz
| Download URL | flux7_mesh-0.6.1.tar.gz |
|---|---|
| Size | 15.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
72d82b238e7975dca284f1d9b8f198594a7041469027cd67bbd0204babeee95c
|
|
BLAKE2b-256 checksum How to use checksums |
e1745bdc6dec3b39fe30fc9b427dc0a1743292c8ab5b9176176e0d6df1df843f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / flux7_mesh-0.6.1-py3-none-any.whl
| Download URL | flux7_mesh-0.6.1-py3-none-any.whl |
|---|---|
| Size | 12.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3447e43e3f89f8e5b790cc56c96b8b822187b2230d1b89e10d0b7cd8f3825ec8
|
|
BLAKE2b-256 checksum How to use checksums |
4e55149c00a0d5c03090afd7213097f01dc4b22ef16640ef1a35043f89c56c7b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|