agentdisco — Python client for Agent Disco
Grade any public URL for AI-agent discoverability. Thin Python wrapper over the REST API at https://agentdisco.io/api/v1.
Install
pip install agentdisco
Requires Python 3.9+.
Quick start
Submit a scan (anonymous, 10 scans/day/IP)
from agentdisco import AgentDisco
with AgentDisco() as client:
scan = client.submit_scan("https://example.com")
print(scan.id, scan.status)
Poll until complete
import time
with AgentDisco() as client:
scan = client.submit_scan("https://example.com")
while scan.status not in {"completed", "failed"}:
time.sleep(5)
scan = client.get_scan(scan.id)
print(f"grade: {scan.grade} ({scan.score}/100)")
Mint a key (raises your quota to 100 scans/day)
from agentdisco import AgentDisco
# Unauthenticated mint — no prior token needed, rate-limited at
# 5 keys/hour/IP. Token is shown ONCE; store it.
key = AgentDisco().mint_key()
print(key.token) # ak_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
authed = AgentDisco(token=key.token)
authed.submit_scan("https://your-site.example")
Get summary for a previously-scanned host
with AgentDisco() as client:
site = client.get_website("example.com")
print(site.latest_grade, site.latest_score, site.scan_count)
Scan history + re-scan
with AgentDisco() as client:
# Paginated history, most-recent first (per_page capped at 50).
for scan in client.get_scans("example.com", per_page=20):
print(scan.grade, scan.score)
# Queue a fresh scan of a known host (counts against your scan quota).
fresh = client.rescan("example.com")
print(fresh.id, fresh.status)
Async client
AsyncAgentDisco mirrors AgentDisco method-for-method over asyncio:
import asyncio
from agentdisco import AsyncAgentDisco
async def main():
async with AsyncAgentDisco(token="ak_...") as client:
scan = await client.submit_scan("https://example.com")
history = await client.get_scans("example.com")
print(scan.id, len(history))
asyncio.run(main())
Same arguments, return types, and exceptions as the sync client —
including await AsyncAgentDisco.from_colony_token(...).
Sign in with the Colony (agents)
Autonomous agents on The Colony can authenticate
without a browser, and — since v0.4.0 — without ever sending their Colony
credential to Agent Disco. The SDK runs the OAuth 2.0 Token Exchange
(RFC 8693) at the Colony, naming Agent Disco as the audience, and
presents only the short-lived, audience-scoped id_token it mints:
from agentdisco import AgentDisco
# One-liner: sign in with your Colony access token and get an authed client.
# The raw token goes only to thecolony.ai; Agent Disco sees just the id_token.
client = AgentDisco.from_colony_token(my_colony_token)
client.submit_scan("https://your-site.example") # authenticated tier (500/day)
# Or keep the minted key's plaintext to reuse across processes:
key = AgentDisco().exchange_colony_token(my_colony_token)
print(key.token, key.rate_limit_tier) # ak_… authenticated
# Already ran the exchange yourself? Present the id_token directly:
key = AgentDisco().present_colony_id_token(my_id_token)
Agent-only: a human Colony subject is rejected with UnauthorizedError,
as is any token not minted for Agent Disco (wrong audience, raw Colony
tokens included — the server refuses them outright since Agent Disco's
2026-07-20 release; SDK ≤0.3.x no longer works for Colony sign-in).
Higher rate limits
Authenticated-tier keys (500 scans/day/key) need a signed-in account, or a Colony agent login (above). Sign up at https://agentdisco.io/register, then mint via the web form at https://agentdisco.io/developers.
| Tier | Rate limit | How to get |
|---|---|---|
| Anonymous (no key) | 10 scans / day / IP | default |
| Anonymous key | 100 scans / day / key | mint_key() above |
| Authenticated key | 500 scans / day / key | sign in (/developers) or from_colony_token() |
Error handling
from agentdisco import (
AgentDisco,
InvalidUrlError,
NotFoundError,
RateLimitedError,
)
try:
scan = AgentDisco().submit_scan("https://example.com")
except InvalidUrlError as e:
print(f"URL rejected: {e}")
except RateLimitedError as e:
print(f"quota exceeded; retry in {e.retry_after_seconds}s")
except NotFoundError as e:
print(f"not found: {e}")
All SDK-raised exceptions inherit from AgentDiscoError, so a single
broad catch works too:
from agentdisco import AgentDiscoError
try:
...
except AgentDiscoError as e:
log.warning("agentdisco failure: %s", e)
Network-layer failures (connection timeout, DNS) leak through as raw
httpx.HTTPError — they're platform issues, not API errors.
Custom base URL
For self-hosted deployments or local testing:
AgentDisco(base_url="http://localhost:1977")
Links
- API docs: https://agentdisco.io/api/docs
- Check catalogue: https://agentdisco.io/checks
- Live scanner: https://agentdisco.io
Licence
MIT. See LICENSE. The scanner itself is operated by
Starsol Ltd (England, company 06002018); only this client library
is open-source. Issues + pull requests welcome.
Release files for agentdisco 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agentdisco-0.4.0.tar.gz | 16.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentdisco-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.9 kB
Release files / agentdisco-0.4.0.tar.gz
| Download URL | agentdisco-0.4.0.tar.gz |
|---|---|
| Size | 16.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9fc84e123c6c472cb230af2fc68051fd584540fdb4e7adb75ca4ff7fc2034078
|
|
BLAKE2b-256 checksum How to use checksums |
a29461dbca2f6f8ee0daaa2a8cbc33fee8c211aa9debdfd01a694e08b0d7bdcc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / agentdisco-0.4.0-py3-none-any.whl
| Download URL | agentdisco-0.4.0-py3-none-any.whl |
|---|---|
| Size | 15.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f56071f0fefb89ebdbc3ef95af66b825f63b474de6f3ee58867b8764fd3d4f5e
|
|
BLAKE2b-256 checksum How to use checksums |
5a2cdba8135e58c99ed51b7926b10839ab6d56872eebc75a502505feffa18707
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|