Summary
AdCP 3.x adds identity.brand_json_url to get_adcp_capabilities (PR adcontextprotocol/adcp#3690). Verifiers can now bootstrap from an agent URL to that agent's signing keys without out-of-band knowledge of the operator domain. This issue tracks the Python SDK port.
Spec references
API to implement
from adcp import resolve_agent, get_agent_jwks, verify_request_signature
result = resolve_agent("https://buyer.example.com/mcp")
# result: AgentResolution { agent_url, brand_json_url, agent_entry, jwks_uri,
# jwks, identity_posture, consistency, freshness, trace }
verified = verify_request_signature(
request, # httpx.Request
agent_url="https://buyer.example.com/mcp",
allowed_algs=("EdDSA",),
)
# Raises typed exceptions matching the spec's request_signature_* error codes.
CLI
python -m adcp resolve <agent-url> — same output format as the TypeScript CLI (npx @adcp/client resolve). Flags: --json, --fresh, --quiet. Output portable across SDKs so shell pipelines work either way.
Implementation notes
- SSRF hardening: HTTPS only, address-family filter before DNS-pin, IPv4 RFC 1918 + IPv6 ULA + cloud-metadata IP blocks, body cap 256 KiB on brand.json / 16 KiB JWKS / 64 KiB capabilities, no redirects, connect 5s / total 10s.
httpx provides hooks for connect-time IP filtering.
- PSL: use
publicsuffixlist or tldextract with a pinned snapshot. Don't fetch the PSL at runtime.
- Cache: brand.json TTL bounded above by JWKS revocation polling interval. Negative-cache ≤ 60s. No SWR on JWKS.
- Error class:
AgentResolverError(Exception) with code and detail matching the spec's taxonomy. Subclasses keyed by error code for except clarity.
- Pydantic models for
AgentResolution, Trace, IdentityPosture, etc.
- Reference design: see adcontextprotocol/adcp@bd89c62ff4 for the dropped Node.js reference implementation — the algorithm/structure ports cleanly.
Tests
- Unit: pure-function consistency tests covering every storyboard variant
- Integration: spin up a fixture HTTP server with brand.json + JWKS, drive the resolver and assert wire shape, error codes, JOSE round-trip via
python-jose
- E2E gated by env var against a known-good agent
Acceptance
Summary
AdCP 3.x adds
identity.brand_json_urltoget_adcp_capabilities(PR adcontextprotocol/adcp#3690). Verifiers can now bootstrap from an agent URL to that agent's signing keys without out-of-band knowledge of the operator domain. This issue tracks the Python SDK port.Spec references
identity.brand_json_urlfield onget_adcp_capabilitiesresponse.security.mdx§"Discovering an agent's signing keys via brand_json_url".specs/capabilities-brand-url.md.API to implement
CLI
python -m adcp resolve <agent-url>— same output format as the TypeScript CLI (npx @adcp/client resolve). Flags:--json,--fresh,--quiet. Output portable across SDKs so shell pipelines work either way.Implementation notes
httpxprovides hooks for connect-time IP filtering.publicsuffixlistortldextractwith a pinned snapshot. Don't fetch the PSL at runtime.AgentResolverError(Exception)withcodeanddetailmatching the spec's taxonomy. Subclasses keyed by error code forexceptclarity.AgentResolution,Trace,IdentityPosture, etc.Tests
python-joseAcceptance
resolve_agent,get_agent_jwks,verify_request_signatureexported fromadcppython -m adcp resolve <url>printing the chain + tracerequest_signature_*codes surface as typed exceptionssecurity.mdx§"Quickstart"