Python client
Use standard-library HTTP or the official MCP Python SDK.
Set M0_BASE_URL and a sandbox M0_API_KEY as in the quickstart. Keep both examples server-side. There is no verified standalone Mandate0 Python SDK package in this checkout.
HTTP client
This read-only example uses Python's standard library and refuses redirects:
import json
import os
import urllib.error
import urllib.request
from urllib.parse import urljoin
class NoRedirect(urllib.request.HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None
base_url = os.environ["M0_BASE_URL"]
api_key = os.environ["M0_API_KEY"]
request = urllib.request.Request(
urljoin(base_url, "/api/v1/wallets"),
headers={"Authorization": f"Bearer {api_key}", "Accept": "application/json"},
)
try:
with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response:
print(json.load(response))
except urllib.error.HTTPError as error:
raise SystemExit(f"Wallet request failed: HTTP {error.code}") from NoneUse an HTTPS platform origin, except for an intentional loopback development server. An empty wallet list is valid in a new sandbox account.
MCP client
This recipe targets the official MCP Python SDK 2.x interface and Python 3.11+. It uses the SDK's HTTP transport with an explicitly configured HTTP client:
python -m pip install 'mcp>=2,<3' httpx2Save as client.py and run with python client.py:
import asyncio
import os
from urllib.parse import urljoin
import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
async def main():
endpoint = urljoin(os.environ["M0_BASE_URL"], "/api/mcp")
async with httpx2.AsyncClient(
headers={"Authorization": f"Bearer {os.environ['M0_API_KEY']}"},
timeout=httpx2.Timeout(30.0, read=300.0),
follow_redirects=False,
) as http_client:
transport = streamable_http_client(endpoint, http_client=http_client)
async with Client(transport) as client:
listing = await client.list_tools()
print([tool.name for tool in listing.tools])
result = await client.call_tool("m0_list_merchants", {"limit": 5})
if result.is_error:
raise RuntimeError("Merchant listing was refused")
print(result.content)
asyncio.run(main())Do not combine SDK 1.x examples with 2.x imports. In 2.x, transport headers and timeouts belong on httpx2.AsyncClient, rather than streamable_http_client keyword arguments. See the official transport guide and migration guide.
The example uses a static key. It does not implement OAuth login or token refresh. It performs a read-only tool call; payment and write operations require their own schema, authority and approval checks.