Skip to main content

metamynd-client

The MetaMynd/AgentSafe authorize-gate client for Python — the supported reference implementation. MAGP is language-agnostic by design: the gate verifies an Ed25519 signature over a canonical string, and nothing about that is JavaScript-specific. This is the proof, and the shortest path for a Python team that doesn't want to read the Node guard to find out what the protocol actually expects.

pip install metamynd-client

Upgrading from 0.1.0? Do. 0.1.0 signs a seven-field message; the gate requires eight (resource was added), so every request from 0.1.0 is refused with CLIENT_PROTOCOL_VERSION_UNSUPPORTED. This release signs the eight-field message and is tested against the gate's own vectors and the real guard (see Tests).

from metamynd_client import MetaMyndClient

client = MetaMyndClient.from_env()  # reads METAMYND_API / AGENT_DID / AGENT_KEY

verdict = client.authorize(
    "flight-purchase", 150,
    merchant="skyward-air",
    context={"tool": "book-flight", "riskLevel": "low"},
)

if verdict.permitted:
    ...  # run the action
elif verdict.decision == "escalate":
    # ESCALATE is a HOLD, not a denial. Wait for a human; act ONLY on may_proceed.
    state = client.wait_for_escalation(verdict.escalation_id, timeout=600)
    if state.may_proceed:
        ...
else:
    raise RuntimeError(f"refused: {verdict.reason_code}")

Send an honest riskLevel

A rule that judges risk escalates a request that carries none (or an unrecognised one), instead of allowing it: an agent that omits its risk is indistinguishable from one hiding it. guard_tool never invents a risk for you, and the "low" in the examples is a placeholder, not an assessment. A real integration states an honest one — or, better, doesn't depend on the agent: the mandate's owner can set a riskTier no claim can lower (MAGP §6.3).

Guard a tool

from metamynd_client import MetaMyndClient, guard_tool, GovernanceBlocked

client = MetaMyndClient.from_env()

def book_flight(amount, merchant):
    ...  # your real implementation

governed_book_flight = guard_tool(
    client, "flight-purchase", book_flight,
    lambda amount, merchant: {
        "amount": amount, "merchant": merchant,
        "context": {"tool": "book-flight", "riskLevel": "low"},  # state an honest risk
    },
)

try:
    governed_book_flight(amount=150, merchant="skyward-air")
except GovernanceBlocked as refused:
    print(f"refused: {refused.verdict.reason_code}")
    # refused.verdict.escalation_id, for a hold: client.wait_for_escalation(...)

map_args returns amount, currency, merchant, resource and context. Async tools are supported: hand guard_tool an async def and you get an async def back (the gate call runs in a worker thread, so it never stalls your event loop). The original signature is preserved, so a framework that builds the tool schema from it — the OpenAI Agents SDK, PydanticAI — sees exactly the unguarded function. If the awaiting task is cancelled (a timeout) while the gate is answering, and the gate permits, the hold that call created is voided rather than left reserving the budget. Async generator tools are refused when you wrap them: one authorization covers one action.

An escalation can also end as modified — a reviewer changed the action instead of approving it as asked. That stops the wait too, is never may_proceed, and status.next_escalation_id is the follow-up hold for the modified action.

Behind a gateway or MCP server

A service protected by @metamynd/agentsafe-http-gateway or an MCP server using agentsafe-mcp-guard doesn't take the agent's word: it re-verifies the signed request against the agent's own policy. The client hands it over:

import requests
from metamynd_client import governance_headers, guard_tool

def book_via_gateway(amount, merchant):
    # inside a guarded tool, governance_headers() is the x-magp-request header for THIS call
    return requests.post("https://gateway.example/book",
                         json={"amount": amount, "merchant": merchant},
                         headers=governance_headers()).json()

book = guard_tool(client, "flight-purchase", book_via_gateway, map_args)

Outside a guarded tool: verdict.signed.headers(). It is not a parameter of your function, so the tool's signature is unchanged. Without the header the service refuses (MISSING_GOVERNANCE) — the safe failure. The gateway also refuses arguments that differ from what was signed (PAYLOAD_NOT_BOUND), so the amount you authorized is the amount that executes.

After a human approves a held action, the request you first signed is stale (a service refuses one more than a few minutes old). Sign a fresh one carrying the approved authorization:

signed = client.sign_request("flight-purchase", 150, merchant="skyward-air",
                             context={"riskLevel": "low"},
                             authorization_id=state.authorization_id)
requests.post(url, json=body, headers=signed.headers())

Settle, release, look up

client.capture(verdict.authorization_id, 150, booking_ref="PNR1")   # commit at the FULL amount
client.void(verdict.authorization_id, reason="not needed")           # release an UNCLAIMED hold
out = client.outcome(verdict.authorization_id)                       # did it happen? may I retry?

Who settles. The service that executed the action settles or releases the hold it claimed; an agent normally doesn't. Once a service has claimed a hold, only that service can settle it below the authorized amount or release it — the gate refuses the agent's attempt (ok=False, with the reason), on purpose: otherwise an agent could wait for a purchase to happen and then take its budget back. An agent can capture at the full amount, and void a hold nobody has claimed.

What was authorized, what was settled, and how far to trust it. Outcome reports authorized_amount (kept after settlement — None means unknown, not zero), settled_amount, and settlement_evidence: unattested (the full authorization, counted for a caller that is not the claiming service), unclaimed_lowered (released below the authorization before anyone claimed it), counterparty_attested (the claiming service said so), independently_confirmed (the payment facilitator reported the same amount), operator_resolved, or reconciled_at_authorized. Where a facilitator is configured, a service settling below the authorization must be confirmed by it — an unreachable or silent facilitator refuses the lower figure rather than believing it (the service can still settle in full).

Retry only when it is safe. Outcome carries two flags: nothing_executed (nothing has run so far) and retry_safe (nothing can run later either — only expired and not_executed). Retry a purchase only on retry_safe. A not_started hold is not yet retry-safe (a service queued behind a slow gateway can still claim it — void it first); unknown and in_flight are ambiguous and are reconciled, never retried blindly.

Examples

Six runnable examples in docs/integration/examples — each runs offline against a test gate, and CI runs them: langgraph_agent.py, openai_agents_agent.py, crewai_agent.py, langchain_agent.py, pydantic_ai_agent.py, and plain_python_agent.py (no framework: the whole lifecycle — authorize, hold, gateway handoff, capture, void, outcome — in one file). Frameworks are imported lazily, so an example still runs the governance without its framework installed.

Scope

This is the entry price, not a full SDK: it signs and submits authorize requests, returns the verdict, wraps a tool (guard_tool, sync or async), hands the signed request to a gateway, follows up an escalate, and settles or looks up a hold. Local bundle evaluation (deciding at the edge, no network) and evidence inclusion-proof fetch exist in the protocol and in the Node guard and are deliberately not reimplemented here — see the full comparison.

Tests

python -m metamynd_client --selftest        # offline: the details that cost a day each,
                                            # plus the whole client against an in-process gate stub

The repository's CI additionally checks the client against the shared protocol vectors (docs/protocol/authorize-vectors.json, generated from the gate's own message builder and read by both the gate's tests and this client's — so the two cannot drift apart again), runs every example, and has the real agentsafe-mcp-guard and agentsafe-http-gateway verify what the client signs.

MIT licensed.

Release files for metamynd-client 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for metamynd-client 0.2.0
File Size Uploaded
metamynd_client-0.2.0.tar.gz 41.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for metamynd-client 0.2.0
File Interpreter ABI Platform
metamynd_client-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 70.1 kB

Release files / metamynd_client-0.2.0.tar.gz

Download URL metamynd_client-0.2.0.tar.gz
Size 41.6 kB
Tags Source
SHA-256 checksum
How to use checksums
97467fc98b07c4160691a990234e5f38a4bd37a88e12e3f196019da80673e90c
BLAKE2b-256 checksum
How to use checksums
38e3b46bb910100c1316a5cae7bb638c24ce69c6383fb1d55f5f19a2a6aa3bc0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / metamynd_client-0.2.0-py3-none-any.whl

Download URL metamynd_client-0.2.0-py3-none-any.whl
Size 28.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
69263eb51106eb1e6b5c492074f2ac8302f75b780808120928ed9659b84381f9
BLAKE2b-256 checksum
How to use checksums
f0d5c18bb85471384987d24e9093bb1b128de40cd339ab968c50b885383d4378
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.5.1

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page