Python SDK for Sphyr Agent Guard
Project description
sphyr-sdk
Python SDK for Sphyr Agent Guard. Adds verifiable, auditable security checks to every outbound agent request.
Quick-Start
1. Install
pip install sphyr-sdk
2. Sign in (no key copy-paste)
npx @sphyr/cli login
Opens your browser, signs you in via the device flow, and writes your credential to
~/.sphyr/config.json (owner-only 0600). After this, the SDK picks it up automatically.
No Node/npx on your machine? Run
python -m sphyr_sdk loginfor the same device-flow sign-in.Setting up an IDE-based agent (Claude Desktop, Cursor, etc.) instead? Use
npx @sphyr/cli guard init— it signs you in and writes the MCP server config for each detected IDE.
3. Protect every outbound call (recommended — install and forget)
from sphyr_sdk import auto_instrument
# One line at startup. After this, every requests / httpx call is signed, scanned,
# and audited through Sphyr automatically — no per-call wrapping.
report = auto_instrument()
print(report.requests.status) # 'patched' or 'not_installed'
print(report.httpx.status) # 'patched' or 'not_installed'
Breaking change (v0.27.0):
auto_instrument()now returns aPatchReport(per-lib instrumentation status) instead of aSphyrClient. Callers that didclient = auto_instrument(...)must update — useSphyrClient(...).instrument()directly if you need a client reference for later teardown.The SDK does nothing until you call
auto_instrument()— importing the package alone is not protective.Fail-closed by default: if the Sphyr gateway is unreachable, instrumented requests raise
SphyrNetworkErrorrather than leaving unscreened. Passauto_instrument(fail_closed=False)to prioritize app uptime over strict enforcement.
Credentials resolve in order: explicit args → SPHYR_CREDENTIAL env var →
~/.sphyr/config.json. So auto_instrument() with no arguments works after npx @sphyr/cli login.
Works with your agent framework — automatically
auto_instrument() patches the underlying HTTP layer (requests and httpx), so any library or
framework that makes outbound calls through them is signed, scanned, and audited the moment you call
it — no adapters, no per-framework wiring. That includes the OpenAI SDK, the Anthropic SDK,
LangChain / LangGraph, CrewAI, AutoGen, and LlamaIndex (all of which use requests/httpx under the
hood). Call auto_instrument() once at process start, before your agent makes its first request.
Manual / advanced — wrap calls yourself
import asyncio
from sphyr_sdk.client import AsyncSphyrClient
from sphyr_sdk.errors import SphyrError
async def main() -> None:
client = AsyncSphyrClient() # resolves creds from env / ~/.sphyr/config.json
try:
result = await client.call({"url": "https://api.example.com/data", "mthd": "GET"})
print(result)
except SphyrError as err:
print(err.code, err.retryable, err.docs_url)
asyncio.run(main())
4. Add the MCP Server (Claude Desktop, Cursor, etc.)
Recommended — one command:
npx @sphyr/cli guard init
This opens your browser, signs you in, and writes per-IDE configs automatically — including the SPHYR_CREDENTIAL env var. MCP server setup uses the Node-based sphyr-mcp binary from @sphyr/sdk.
See sphyr.io/docs/mcp for per-client setup (Claude Desktop, Claude Code CLI, Cursor, Antigravity, OpenAI Codex).
Full reference (retry policy, custom transport, timeout config, error catalog): sphyr.io/docs
What traffic is intercepted (and what is not)
instrument() / auto_instrument() work by patching specific HTTP client libraries. Traffic from anything else flows directly to the network, unguarded — there is no OS-level interception.
| Transport | Intercepted? |
|---|---|
requests (Session-based and module-level) |
✅ yes |
httpx (Client and AsyncClient) |
✅ yes |
aiohttp |
❌ no — flows unguarded |
urllib / urllib.request / http.client |
❌ no — flows unguarded |
urllib3 (used directly, not via requests) |
❌ no — flows unguarded |
pycurl / subprocess curl |
❌ no — flows unguarded |
If your agent uses an unsupported transport, route those calls through SphyrClient.call() explicitly, or switch the agent's HTTP layer to requests/httpx.
Local/private traffic exclusions. To prevent gateway loops and keep local development working, intercepted clients pass traffic to localhost, RFC 1918 ranges (10/8, 172.16/12, 192.168/16), generic link-local (169.254/16), and IPv6 ULA/link-local directly to the real transport, unguarded. One deliberate exception: the cloud metadata endpoints (169.254.169.254, fd00:ec2::254) are always routed through the gateway, which blocks and audits the attempt — these are the primary SSRF targets a prompt-injected agent probes.
Tool Schema Drift Detection
When SphyrClient.instrument() is active, the SDK automatically detects changes to an MCP server's tools/list response between sessions. The first response per origin sets the baseline; subsequent changes raise SphyrDriftError (in BLOCK mode) or emit a telemetry event and continue (in LOG mode, the default).
from sphyr_sdk import SphyrClient, SphyrDriftError
try:
result = await client.call({"url": "https://mcp.example.com/...", "mthd": "GET"})
except SphyrDriftError as err:
# Tool schema changed unexpectedly — halt and alert
print(err.code) # "TOOL_SCHEMA_DRIFT"
SphyrDriftError is also importable from sdk.agent_guard_utils for legacy integrations. The enforcement mode (LOG or BLOCK) is set per API key via key_flags.tool_drift_mode in the admin console.
User-Agent header (custom integrations)
This SDK sends User-Agent: sphyr-sdk-python/<version> on every request to the Sphyr gateway. You do not need to do anything to enable this — it is set automatically.
If you are building a custom MCP client that talks to the Sphyr gateway directly (i.e. not using this SDK), you must set a User-Agent header on your requests. Cloudflare's WAF blocks Python urllib's default Python-urllib/3.X User-Agent as a bot — requests fail with HTTP 403 / Error 1010 (browser_signature_banned) before they reach the Worker. Any non-empty descriptive value (e.g. your-app/1.0) is sufficient.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sphyr_sdk-2.0.0b1.tar.gz.
File metadata
- Download URL: sphyr_sdk-2.0.0b1.tar.gz
- Upload date:
- Size: 71.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbc6c24c4b074688485a9b21150039da2e739c7c4f9be6977e093a316186a63d
|
|
| MD5 |
ae5bfa0305b8beb58bf9b830b48b01f9
|
|
| BLAKE2b-256 |
556a5d20eac8b1029b8f1a8403945d920bd9e942332a5240e224f30a396f6ba4
|
File details
Details for the file sphyr_sdk-2.0.0b1-py3-none-any.whl.
File metadata
- Download URL: sphyr_sdk-2.0.0b1-py3-none-any.whl
- Upload date:
- Size: 41.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdae944854cd9a5102946d9628d39b3a4f91d1da523d2848361b9ac3a4f61343
|
|
| MD5 |
9de9264564799a73bb00a2a005c61e88
|
|
| BLAKE2b-256 |
40a91c49ac508877f145bfe6453b48f7dffb175f09c28a6681f73feefca43d62
|