The ctscout.dev API and MCP server, endpoint by endpoint
Every endpoint below is served from the same Worker. Keyed routes take X-API-Key; a free key comes from the box on the front page, no account. Contract changes are dated in the API changelog and surfaced as the X-API-Version header on /scan.
POST /scan# Search by company name
curl -X POST https://ctscout.dev/scan \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_KEY" \
-d '{"company_name": "Goldman Sachs"}'
# Search by domain
curl ... -d '{"seed_domain": ["gs.com"]}'
# Both (OR logic)
curl ... -d '{"company_name": "Goldman Sachs", "seed_domain": ["gs.com"]}'
A result row is an apex domain with the organization its OV/EV certificates name, a certificate count and a subdomain count. Free keys see the top 5 rows over the last 90 days; Pro keys the top 25 over up to 12 months (tiers). A query counts against the tier's lookup quota only when it returns at least one row; remaining_quota on a batch and GET /keys/usage report what is left in the period (a day on Free, a month on Pro). A batch is refused whole when it could overrun what is left, as if every query would succeed; if another call takes the remaining quota while it runs, it is refused rather than part-charged. A separate per-day request guard, set above the quota and charged for refused requests too, stops runaway scripts.
POST /scan/batch# Up to 10 queries per request, single auth; each query that returns a result counts as one lookup
curl -X POST https://ctscout.dev/scan/batch \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_KEY" \
-d '{
"queries": [
{"company_name": "Goldman Sachs", "strict_match_org_only": true},
{"company_name": "Morgan Stanley", "strict_match_org_only": true},
{"seed_domain": ["gs.com"]}
]
}'
# Response: { "results": [ {"query": {...}, "domains": [...], ...}, ... ],
# "remaining_quota": 7 }
Batch semantics: one auth check, per-query parallel execution (up to 10 in flight), and one lookup charged per query that returns at least one row, recorded before the batch is returned; an empty answer costs nothing. The batch is checked up front as if every query will succeed: it is refused whole with a 429 when len(queries) exceeds the lookups left in the period, and the per-day request guard is charged len(queries) whether the batch runs or not. The whole batch returns 400, with nothing charged, if any query fails validation or if len > 10. The MCP equivalent is ctscout_search_company_batch, available through both hosted transports and the local package, with the same ten-query limit. Use strict_match_org_only: true on each query when you want certificate-organization matching without semantic fallback.
# Queue a deep-dive: same body as /scan (company_name and/or up to 10 seed_domain)
curl -X POST https://ctscout.dev/jobs \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_PRO_KEY" \
-d '{"company_name": "Goldman Sachs"}'
# 202 { "job_id": "…", "status": "queued", "submitted_at": "…", "poll": "/jobs/…" }
# Poll (backoff: 30s → 5min). `result` appears once status is "done".
curl -H "X-API-Key: YOUR_PRO_KEY" https://ctscout.dev/jobs/JOB_ID
# { "job_id", "kind", "status": "queued|running|done|failed",
# "submitted_at", "started_at", "finished_at", "result"?, "error"? }
# Your last 50 jobs
curl -H "X-API-Key: YOUR_PRO_KEY" https://ctscout.dev/jobs
A job is picked up by a batch worker (roughly every 10 minutes) and runs the Pro enrichment off the request path — DNS, RDAP, IP/ASN, homepage-metadata and favicon corroboration, with snapshot, signals_attempted, signal_health and confidence_band computed in one place. Result fields match Pro /scan plus those four. 20 jobs per key per day; jobs never count as lookups. Only the submitting key can read a job. VLM verdicts are not included yet. Free keys get a 403 — the synchronous /scan path stays edge-only for every tier.
# One LEI: GLEIF legal name, country, ISIN count, first/last seen, confirmed vendors,
# a capped domain sample, and the URL of its answer page. No key.
curl https://ctscout.dev/lei/2138006IPPRD4N6XLT30
# Name to LEI (exact, then normalized; capped at 20). No key.
curl "https://ctscout.dev/lei?name=ABSA%20Group"
# { "query": "…", "name_match": "exact" | "normalized" | "none", "leis": [...], "lei_count": 1, "limit": 20, "truncated": false, ... }
# One vendor: candidate and DNS-confirmed customer counts, country distribution, co-use, a capped sample
curl https://ctscout.dev/vendors/salesforce
# The enumeration — any active key: Free gets the first 100 rows of each list with the true counts and truncated: true
# when rows were dropped, Pro the whole list
curl -H "X-API-Key: YOUR_KEY" https://ctscout.dev/vendors/salesforce/customers
# { "confirmed": [{"apex": "…", "attributed_to": "…"|null, "lei": "…"|null}], "candidates": rows of the same shape,
# "counts": {"candidates": N, "confirmed": N}, "capped": false, # capped: true = candidates is a hash-chosen subset
# "truncated": false, # true only when a Free slice dropped rows
# "free_slice": {"rows": 100, "full_list": "pro"} | null, ... } # null on Pro
These serve precomputed objects from the weekly research refresh, not the /scan warehouse: nothing is matched or counted at request time. Every response carries product_version, as_of and snapshot_dates (GLEIF, Wikidata, ISIN, ELF, PSL), and uses the notes' vocabulary — attributed, candidate, confirmed, never "owns". Counts and samples are free; the customer list is the keyed boundary. Until the product is published the routes answer 503, never a guess. The same objects back the human-readable pages: one per organization at /research/companies/<lei>, one per confirmed vendor at /research/vendors/<slug>.
Use ctscout from Claude Code, Claude Desktop, Cursor, or any client that speaks the Model Context Protocol. Tools: ctscout_search_company, ctscout_search_company_batch, ctscout_lookup_domain, the research-product reads ctscout_lookup_lei / ctscout_vendor_customers, and for Pro keys the async pair ctscout_submit_deep_dive / ctscout_get_job. The hosted server and the npm package register the same tool contract (ctscout-mcp-server/contract), so both transports expose one surface.
First, get a free key from the front page. Replace YOUR_KEY in the setup for your client below. Hosted HTTP needs no local CTScout package; the Desktop stdio option requires Node.js and npm.
With Claude Code installed, run this command in your terminal:
claude mcp add --header "X-API-Key: YOUR_KEY" --transport http --scope user ctscout https://ctscout.dev/mcp
Start or restart Claude Code, then use /mcp to check that ctscout connects. See the Claude Code MCP setup guide.
Merge this entry into mcpServers in ~/.cursor/mcp.json for all projects, or .cursor/mcp.json inside one project. Keep any existing servers:
{
"mcpServers": {
"ctscout": {
"url": "https://ctscout.dev/mcp",
"headers": { "X-API-Key": "YOUR_KEY" }
}
}
}
Check the server in Cursor's MCP settings. See the Cursor MCP setup guide. Clients that require legacy SSE can use https://ctscout.dev/sse with their client's SSE transport setting and the same key header.
Install Node.js LTS (24 LTS is supported), which includes npm. Open a new terminal and check node --version and npm --version. No npm account or npm login is needed to run this public package.
In Claude Desktop, open Settings → Developer → Edit Config. Merge this entry into mcpServers, preserving any existing servers. The file is ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows:
{
"mcpServers": {
"ctscout": {
"command": "npx",
"args": ["-y", "ctscout-mcp-server@0.6.1"],
"env": { "CTSCOUT_API_KEY": "YOUR_KEY" }
}
}
}
Quit and reopen Claude Desktop to load the server. This launches a local compatibility client that calls ctscout.dev; it still needs internet access. See the Desktop local-server setup and troubleshooting guide.
Then ask Claude: "Use ctscout to find domains attributed to Cloudflare."
Source: github.com/minghsuy/ctscout-mcp (MIT). For Claude Code CLI configs and full setup, see the README.
Built for account-to-domain enrichment, subsidiary discovery, and SAN-cohort analysis from LLM-driven workflows. DV-only infrastructure (Let's Encrypt, ZeroSSL, cloud-native shops) is out of scope by design. Not a cyber-risk-scoring tool — see LIMITATIONS. Tiers and quotas: front page.