certindex
CertIndex is a Certificate Transparency API and hosted MCP server over every public CT log — search, monitor, and stream every TLS certificate on the internet.
What it can do
- Search Certificates: Search the CT certificate index. Filter by domain (exact), subject CN (substring), issuer name (substring, matched against issuer CN and issuer organization), SAN value (exact ele
- Submit Global Sweep: Submit a global (domain-less) certificate sweep as an async job. Use this instead of ``search_certificates`` when a global ``cn`` / ``san_contains`` sweep times out or needs more
- Get Sweep Results: Poll an async global sweep job; paginate results when done. While the job is ``queued`` / ``running``, returns status only — poll again after a few seconds. When ``done``, returns a
What data it sees
Do you need an account
An API key from the service settings is required
CertIndex is a Certificate Transparency API and hosted MCP server over every public CT log — search, monitor, and stream every TLS certificate on the internet. Built for the developers who used to copy-paste crt.sh queries, and licensed for the enterprises and EASM platforms that redistribute CT data inside their own products.
How to connect
How to connect certindex to Claude
The server address to paste into Claude settings:
https://certindex--certindex.run.tools
- Open Claude (claude.ai or the desktop app).
- Go to Settings → Connectors.
- Click Add custom connector.
- Paste the server address copied below into Remote MCP server URL and click Add.
- In a chat, click + → Connectors and switch the new connector on.
Custom connectors are available on Free, Pro, Max, Team and Enterprise plans (Free is limited to one). On Team and Enterprise an organization Owner adds the connector first under Organization settings → Connectors.
Authorization
After you click Add, a sign-in window for the service opens. Sign in with your own account and approve access. Claude never sees your password.
How to connect certindex to ChatGPT
The server address to paste into ChatGPT settings:
https://certindex--certindex.run.tools
- Open ChatGPT in a browser (chatgpt.com). A Plus, Pro, Business, Enterprise or Edu plan is required.
- Turn on developer mode once: Settings → Apps → Advanced settings → Developer mode.
- Open Settings → Connectors and click Create.
- Fill in the form: Name (anything), Description (one line about what the service does), MCP server URL (copy it below).
- Under Authentication choose OAuth if the service requires sign-in, otherwise None. Click Create.
- In a new chat open + → Apps/Connectors and enable the connector.
OpenAI has renamed this section before (Connectors → Apps/Plugins). If the label differs, search settings for "developer mode". On Business/Enterprise workspaces an admin must allow custom connectors first.
Authorization
On first use ChatGPT opens the service's sign-in window. Sign in and approve access.
How to connect certindex to Cursor
The server address to paste into Cursor settings:
https://certindex--certindex.run.tools
Fastest: click Open in Cursor below and confirm the prompt.
Manually:
- In Cursor open Settings → Cursor Settings → MCP and click Add new global MCP server.
- Paste the JSON copied below into
~/.cursor/mcp.json(per project:.cursor/mcp.jsonin the repo root). - Save the file. The server appears in the MCP list; authorize it there if asked.
Authorization
If the service needs sign-in, an authorize button appears next to the server in the MCP list.
Server tool list (10)
Raw names from tools/list. Only developers need these.
| search_certificates | Search the CT certificate index. Filter by domain (exact), subject CN (substring), issuer name (substring, matched against issuer CN and issuer organization), SAN value (exact element match), SAN substring (``san_contains``), expiry status, wildcard flag, and first_seen / not_after datetime ranges. Max limit: 50 per page. Global sweeps (task #612): ``cn`` and ``san_contains`` work WITHOUT a ``domain`` scope at 3+ characters — this is a global brand sweep, governed by the ``global_sweep_per_hr`` rate class (paid tiers only; the free tier gets a clear not-entitled error). Exact ``san`` still requires a ``domain`` scope, and ``issuer`` alone must be composed with a ``cn`` / ``san_contains`` pattern when unscoped. Deep / slow sweeps (task #644): this synchronous tool caps global sweeps at a shallow pagination depth and a ~10 s budget. When a global sweep times out here, or you need MORE results than the depth cap allows, use ``submit_global_sweep`` instead — it runs the same filters asynchronously with a much larger budget and a 10 000-row result store, polled via ``get_sweep_results``. Args: domain: Exact domain / subdomain (e.g. "api.example.com") cn: Subject CN ILIKE substring (e.g. "example") issuer: Issuer name ILIKE substring, matched against both issuer CN and issuer organization (e.g. "Let's Encrypt" matches certs whose issuer_cn is "R12") san: Exact SAN value present in the cert's SAN array san_contains: SAN substring — matches certs with ANY name containing this substring (global at 3+ chars) expired: true = expired only; false = valid only; omit = all is_wildcard: true = wildcard certs only first_seen_after: first_seen >= this ISO-8601 datetime first_seen_before: first_seen <= this ISO-8601 datetime not_after_after: not_after >= this ISO-8601 datetime not_after_before: not_after <= this ISO-8601 datetime page: Page number (1-indexed) limit: Results per page (1–50) |
| submit_global_sweep | Submit a global (domain-less) certificate sweep as an async job. Use this instead of ``search_certificates`` when a global ``cn`` / ``san_contains`` sweep times out or needs more results than the synchronous depth cap: the job runs the SAME filter shapes with a much larger query budget and stores up to 10 000 rank-ordered results (first_seen DESC). Poll ``get_sweep_results`` with the returned ``job_id`` until ``status`` is ``done``, then paginate. Requires at least one of ``cn`` / ``san_contains`` (3+ chars). ``issuer`` alone is rejected (it would match a large fraction of all certificates). Consumes one ``global_sweep_per_hr`` quota unit at submit (paid tiers only); polling is quota-free. Args: cn: Subject CN ILIKE substring (3+ chars) issuer: Issuer substring (issuer CN or organization); only allowed composed with cn / san_contains san_contains: SAN substring — matches certs with ANY name containing this substring (3+ chars) is_wildcard: true = wildcard certs only; false = non-wildcard is_precert: true = precerts only; false = leaf certs only expired: true = expired only; false = currently valid only first_seen_after: first_seen >= this ISO-8601 datetime first_seen_before: first_seen <= this ISO-8601 datetime not_after_after: not_after >= this ISO-8601 datetime not_after_before: not_after <= this ISO-8601 datetime |
| get_sweep_results | Poll an async global sweep job; paginate results when done. While the job is ``queued`` / ``running``, returns status only — poll again after a few seconds. When ``done``, returns a page of results (same row shape as ``search_certificates``) plus ``result_count`` and a ``truncated`` flag (true when the sweep hit the result cap). When ``failed``, ``error`` carries a structured body — ``sweep_timeout`` means the filters must be narrowed and resubmitted. Polling is quota-free. Args: job_id: The ``job_id`` returned by ``submit_global_sweep`` page: Page number (1-indexed) limit: Results per page (1–50 for MCP) |
| get_certificate | Get full certificate details by SHA-256 fingerprint. Returns the complete cert record: SANs, issuer info, crypto-hygiene metadata, and CT log metadata (log_id, leaf_index). Args: sha256: 64-character lowercase hex SHA-256 fingerprint include_raw: When true, fetch the raw certificate bytes from cold storage and return them as PEM in ``raw_pem`` (task #586, mirrors the REST ``?include_raw=true``). Also backfills any NULL crypto-hygiene fields (``key_type`` / ``key_size`` / ``signature_algorithm`` / ``is_weak_crypto``) by parsing the DER. Defaults to false to keep LLM context small. A long-expired cert whose bytes were dropped by the retention sweep returns an ``error: "raw_swept"`` dict with a ``log_id`` / ``leaf_index`` pointer. include_enrichment: When true, attach RDAP + DNS + ASN/hosting context for the cert's primary hostname under ``enrichment`` (task #501). Opt-in; a slow/failed source degrades to a partial block and never fails the lookup. |
| get_domain_certificates | List all certificates for a domain. Returns paginated certificates associated with the exact domain name. **Self-healing for cold domains:** if CertIndex has not indexed this domain yet, the response contains zero results plus a ``backfill_status`` sentinel. When ``backfill_status == "in_progress"``, an on-demand crt.sh backfill has just been started — wait ``retry_after_seconds`` seconds and call this tool again, the index will be populated shortly. When ``backfill_status`` is ``previously_completed``, ``previously_failed``, ``not_triggered``, or ``refused_over_budget``, do NOT retry — the result will not change. ``refused_over_budget`` means the domain is valid but too large to backfill inline (read the ``hint``); it is NOT a "no such domain" answer. Args: domain: Exact domain name (e.g. "example.com") valid_only: When true, return only non-expired certificates include_enrichment: When true, attach RDAP + DNS + ASN/hosting context for the domain under ``enrichment`` (task #501). Opt-in; a slow/failed source degrades to a partial block and never fails the lookup. include_signals: When true, attach derived attribution signals under ``enrichment.signals``: issuer_diversity_score (0.0 single CA → 1.0 at 5+ distinct CAs), wildcard_breadth (distinct wildcard patterns), third_party_vendors (SaaS vendors inferred from the domain's TXT/SPF inventory), and weak_crypto_reasons. Implies enrichment computation. Requires a paid plan (Pro or higher); the free tier gets a structured ``tier_not_entitled`` error. page: Page number (1-indexed). Ignored when ``cursor`` is supplied. limit: Results per page (1–50 in offset mode). In cursor mode ``limit`` may go up to the caller's tier ceiling (base 200, enterprise 1000). cursor: Opaque keyset cursor (task #635). Pass ``cursor=""`` (empty string) to start a cursor enumeration, then the ``next_cursor`` from each response until it is absent. Cursor pages are ordered newest-first by observation (monotone internal id) and are stable against concurrent inserts — rows never shift, repeat, or drop between pages. Omit ``cursor`` entirely for the classic offset pagination (unchanged). |
| get_subdomains | Enumerate unique subdomains seen in CT logs for a domain. Returns all unique subdomains of the given domain observed across Certificate Transparency logs. Useful for attack-surface discovery. **Query budget & partial results:** each call runs under a fixed server-side query budget (~10s). For very high-cardinality apexes the scan is bounded, and when the bound is hit the response sets ``results_partial: true`` and ``total_is_lower_bound: true`` — the page you got is ranked from a sample and ``total_subdomains`` is a floor, not an exact count. The default ``limit`` (25) is sized to fit the budget even on huge domains; keep ``limit`` at or below the default and page through results rather than requesting large pages. If a call still returns ``error: "timeout"``, the same partial flags are included — retry with a smaller ``limit``. Args: domain: Root domain to enumerate (e.g. "example.com") page: Page number (1-indexed). Ignored when ``cursor`` is supplied. limit: Results per page (1–50 in offset mode; default 25 is budget-safe even for high-cardinality domains). In cursor mode ``limit`` may go up to the caller's tier ceiling (base 200, enterprise 1000). cursor: Opaque keyset cursor (task #635). Pass ``cursor=""`` (empty string) to start a cursor enumeration, then the ``next_cursor`` from each response until it is absent. Cursor pages are ordered by subdomain name ASC (an immutable key), so pages are stable against concurrent inserts — unlike the default popularity (cert_count) ordering, which is offset-only. Omit ``cursor`` entirely for the classic offset pagination (unchanged). **Self-healing for cold domains:** if CertIndex has not indexed this domain yet, the response contains zero results plus a ``backfill_status`` sentinel. When ``backfill_status == "in_progress"``, wait ``retry_after_seconds`` seconds and call this tool again. Any other status means the result will not change on retry. |
| get_latest_cert | Get the most recently issued certificate for a domain. Returns ``{"cert": <detail>}`` when found, otherwise ``{"cert": null, "backfill_status": ...}``. **``raw_pem`` is always null here (by design):** raw certificate bytes live in cold storage and are deliberately excluded from domain-shaped tools to keep LLM context small (task #66). To get the PEM body, take ``cert.sha256`` from this response and call ``get_certificate`` with ``include_raw=true``. **Self-healing for cold domains:** if CertIndex has not indexed this domain yet, the response is ``{"cert": null, "backfill_status": ...}`` with the same sentinel semantics as the other domain-shaped tools. When ``backfill_status == "in_progress"``, wait ``retry_after_seconds`` seconds and call this tool again. Any other status means the result will not change on retry. Args: domain: Exact domain name (e.g. "example.com") include_enrichment: When true, attach RDAP + DNS + ASN/hosting context for the domain under ``cert.enrichment`` (task #501). Opt-in; a slow/failed source degrades to a partial block and never fails the lookup. include_signals: When true, attach derived attribution signals under ``cert.enrichment.signals``: issuer_diversity_score, wildcard_breadth, third_party_vendors, and weak_crypto_reasons. Implies enrichment computation. Requires a paid plan (Pro or higher); the free tier gets a structured ``tier_not_entitled`` error. |
| get_usage | Return the caller's current usage and tier limits. Mirrors the REST ``GET /v1/usage`` endpoint. Returns tier, per-window limits, current usage, remaining quota, billing period boundary, firehose entitlement, and commercial-use flag. Note: this tool is reached over the MCP ``/mcp`` transport, which is gated by the ``mcp_per_min`` rate limit (same as every other MCP tool). For unrate-limited polling, call the REST endpoints ``GET /v1/usage`` or ``GET /mcp-api/usage`` instead. |
| get_historical_backfill_status | Check the paid deep-historical (expired / deep-past) certificate backfill for a domain, and start it when entitled. Active (currently-valid) certificate lookups are always free and instant via the other tools. This tool covers the SEPARATE paid per-domain add-on that walks the full CT history (including long- expired certificates) for a domain you have provisioned. Behavior (scoped to your account + this domain): * If deep-historical backfill is NOT enabled for this domain on your account, returns ``entitled: false`` and a ``hint`` — the add-on must be enabled for the domain in the billing portal first. Nothing is started. * If entitled, the deep full-history walk is started (or resumed) and the response includes a wall-clock ``estimate`` plus live ``progress`` (percent complete, certs found so far). Call again to poll progress. Args: domain: Exact domain name (e.g. "example.com") |
| get_expiring_certs | List certificates expiring soon for a domain. Returns certificates expiring within `days` days from now. Useful for proactive renewal monitoring. Out-of-range ``days`` values are clamped into [1, 365] (0 or negative → 1, above 365 → 365); when that happens the response carries ``days_clamped: true`` plus ``days_requested`` so you know the effective window differs from what you asked for. Args: domain: Exact domain name (e.g. "example.com") days: Lookahead window in days (1–365, default 30; values outside the range are clamped and flagged via ``days_clamped`` / ``days_requested``) **Self-healing for cold domains:** if CertIndex has not indexed this domain yet, the response contains zero results plus a ``backfill_status`` sentinel. When ``backfill_status == "in_progress"``, wait ``retry_after_seconds`` seconds and call this tool again. Any other status means the result will not change on retry. |