Skip to main content
Glama
minghsuy

ctscout

by minghsuy

Search ctscout by company name

ctscout_search_company
Read-only

Search Certificate Transparency logs by organization name to discover attributed apex domains, with options for normalized matching and strict filtering.

Instructions

Search ctscout.dev's domain-attribution warehouse by organization name. Returns apex domains attributed to that organization based on Certificate Transparency log analysis (OV/EV cert subjects matched to entity names).

Args:

  • company_name (string, required): organization name. Partial matches work — 'Goldman' matches 'Goldman Sachs'. Min 2 chars, max 200.

  • strict_match_org_only (boolean, optional): suppress semantic candidates and return only authoritative warehouse org matches.

  • org_match_field ('verbatim' | 'normalized', optional): raw cert-subject substring matching, or the research normalizer's key of the query against the normalized column (legal forms stripped at the edges, '&'/'and' and hyphen/space unified, a leading 'The' dropped, a generic tail like 'Holdings' kept). Leave unset for automatic verbatim-then-normalized fallback.

  • org_match_mode ('substring' | 'word', optional): use word-boundary matching to reduce noise from short/common names.

  • purpose ('underwriting' | 'corporate_family', optional): choose tight operational-attribution defaults or broader corporate-family defaults. Explicit matching controls override the preset.

  • response_format ('markdown' | 'json', default 'markdown'): output format.

Returns (on success, structuredContent follows the declared outputSchema; an error result — 401, 429, timeout — is isError with no structuredContent, so never dereference snapshot on a failed call):

  • "Attributed" means the organization is what the evidence names for that domain, not an ownership claim. On /scan that evidence is the OV/EV certificate subject on both tiers; multi-signal attribution (DNS, RDAP, IP/ASN, homepage, favicon) exists only in a deep-dive job result (ctscout_submit_deep_dive, Pro). "Candidate" means a semantic name-similarity guess that is NOT an attribution.

  • In markdown: a snapshot line, then a table of (domain, attributed to, cert count, subdomain count). When nothing is attributed but match_type is 'semantic', a table of candidate organizations is rendered instead, labelled as candidates.

  • In JSON, structured as: { "domains": [ // attributed pairs; empty when nothing is attributed { "org": string, // attributed organization: the OV/EV certificate subject (both tiers) "apex_domain": string, // e.g. "gs.com" "cert_count": number, // # of distinct certs observed for this pair "subdomain_count": number, // # of distinct subdomains "first_seen": string | null, // warehouse observation time — NOT the CT log SCT / issuance time "last_seen": string | null // warehouse observation time — NOT the CT log SCT / issuance time } ], "total": number, // total matching rows in warehouse "truncated": boolean, // true if response is capped "upgrade_hint": string, // present when truncated "source": "warehouse", // both tiers read the daily warehouse snapshot "match_type": "exact" | "semantic" | "none", // 'semantic' = domains empty, candidates offered "org_match_strategy": string, // which matching pass produced the answer "empty_reason": string, // present on empty results: why nothing was attributed "candidates": [ // only when match_type is 'semantic'; NOT attributions { "org": string, "similarity": number, "top_apex_domain": string | null } ], "snapshot": string | null, // warehouse/D1 sync date (YYYY-MM-DD) the answer was read from (API version 2026-09-05+); null only when the API could not determine it "snapshot_source": "scan" | "unavailable" // 'scan' = API carried the date; 'unavailable' = it did not (snapshot is null). null means unknown freshness, never "current" }

Examples:

  • Use when: "Find all domains attributed to Cloudflare" -> { company_name: "Cloudflare" }

  • Use when: "Which domains are attributed to Goldman?" -> { company_name: "Goldman Sachs" }

  • Don't use when: You have a specific domain and want to find the organization it's attributed to — use ctscout_lookup_domain instead.

Auth & limits:

  • Requires an API key in CTSCOUT_API_KEY. Get a free key (no email) at https://ctscout.dev.

  • Free tier: 10 successful lookups/day, top 5 results from a daily snapshot. The response's "snapshot" field carries that snapshot's sync date (the API reports it since X-API-Version 2026-09-05); when it is null the API could not determine it — treat freshness as unknown, never as current.

  • Pro tier: 3,000 successful lookups/month included, up to 25 rows, a 12-month window; deep-dive jobs (20/day) for multi-signal attribution. $49/month, subscribed from https://ctscout.dev/#tiers.

Error handling:

  • HTTP 401: API key missing or invalid.

  • HTTP 429: a quota on this key is exhausted, on either tier; the error quotes the API's own detail, which names the cap and when it resets. Tier allowances: https://ctscout.dev/#tiers.

  • "No domains found": try a shorter or different company name (see legal-vs-brand caveat below).

Legal-vs-brand caveat (important):

  • The cert subject (O field) uses LEGAL entity names, not brand names.

  • "Travelers Insurance" → 0 results because the legal name is "The Travelers Companies, Inc."

  • "Hartford Financial" → 0 results; legal names are "Hartford Fire Insurance Company" or "The Hartford Financial Services Group".

  • If a brand-name search returns nothing, retry with variants like "X Companies", "X Group", "X Inc", "X Corporation", or "The X". The empty-result markdown output includes these suggestions automatically when the input looks brand-shaped.

Coverage caveat:

  • Best for established US/EU tech companies with OV/EV certs.

  • Limited coverage on small private companies, cyber MGAs, and entities using only DV (Let's Encrypt) certs.

  • Warehouse size (organizations, org-domain pairs, last sync) is not stated here because it changes daily; read the live figures at https://ctscout.dev/stats before treating a miss as meaningful.

Corrections:

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
purposeNoOptional persona preset. 'underwriting' defaults to a tight operational attack-surface set; 'corporate_family' defaults to a broad brand, regional, and family set. Explicitly supplied matching controls always win.
company_nameYesCompany / organization name to search for. Partial matches work (e.g. 'Goldman' matches 'Goldman Sachs'). Case-insensitive.
org_match_modeNoOptional, default 'substring'. Use 'word' for short or common-token names to avoid unrelated substring matches. Applies only to verbatim matching.
org_match_fieldNoOptional, default 'verbatim'. 'verbatim' substring-matches the raw cert subject. 'normalized' compares the research normalizer's key of the query against the normalized column: GLEIF legal forms stripped at the edges, spelled out or abbreviated ('Aktiengesellschaft' and 'AG', 'Incorporated' and 'Inc.'), diacritics folded, lowercased; '&' and 'and' unify; a hyphen and a space no longer split ('Coca-Cola' and 'Coca Cola'), nor does a leading 'The'; a generic tail like 'Holdings' or 'Group' is part of the name and stays. A query that normalizes to nothing (a bare legal form) matches nothing. Leave unset to try verbatim first and retry normalized after an empty result; set 'normalized' only to skip the verbatim attempt.
response_formatNoOutput format: 'markdown' for human-readable summary, 'json' for the raw API response (useful for programmatic processing).markdown
strict_match_org_onlyNoOptional, default false. When true, suppress the semantic-name fallback and return only authoritative warehouse organization matches.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
totalNoMatching pairs in the warehouse before any cap.
sourceNo'warehouse' on /scan (both tiers); 'live-enriched' / 'cache-only' on a deep-dive result.
domainsYesAttributed (domain, organization) pairs. Empty when nothing is attributed.
snapshotYesWarehouse/D1 sync date (YYYY-MM-DD) the answer was read from; the warehouse syncs daily. null when the API could not determine it.
truncatedNo
candidatesNoPresent only when match_type is 'semantic'. Candidates are not attributions.
match_typeNo'exact' = domains are warehouse attributions; 'semantic' = domains is empty and candidates holds name-similarity guesses; 'none' = nothing matched.
empty_reasonNo
upgrade_hintNo
snapshot_sourceYes'scan' = the API response carried the date; 'unavailable' = it did not, snapshot is null and must be treated as unknown, never as current.
org_match_strategyNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changedv0.6.0
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / properties / org_match_field
      Added value: +{
      +  "description": "Optional, default 'verbatim'. 'verbatim' substring-matches the raw cert subject. 'normalized' compares the research normalizer's key of the query against the normalized column: GLEIF legal forms stripped at the edges, spelled out or abbreviated ('Aktiengesellschaft' and 'AG', 'Incorporated' and 'Inc.'), diacritics folded, lowercased; '&' and 'and' unify; a hyphen and a space no longer split ('Coca-Cola' and 'Coca Cola'), nor does a leading 'The'; a generic tail like 'Holdings' or 'Group' is part of the name and stays. A query that normalizes to nothing (a bare legal form) matches nothing. Leave unset to try verbatim first and retry normalized after an empty result; set 'normalized' only to skip the verbatim attempt.",
      +  "enum": [
      +    "verbatim",
      +    "normalized"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / org_match_mode
      Added value: +{
      +  "description": "Optional, default 'substring'. Use 'word' for short or common-token names to avoid unrelated substring matches. Applies only to verbatim matching.",
      +  "enum": [
      +    "substring",
      +    "word"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / purpose
      Added value: +{
      +  "description": "Optional persona preset. 'underwriting' defaults to a tight operational attack-surface set; 'corporate_family' defaults to a broad brand, regional, and family set. Explicitly supplied matching controls always win.",
      +  "enum": [
      +    "underwriting",
      +    "corporate_family"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / response_format / enum
      Previous value: -[
      -  "json",
      -  "markdown"
      -]New value: +[
      +  "markdown",
      +  "json"
      +]
    • addedInput schema / properties / strict_match_org_only
      Added value: +{
      +  "description": "Optional, default false. When true, suppress the semantic-name fallback and return only authoritative warehouse organization matches.",
      +  "type": "boolean"
      +}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "https://json-schema.org/draft/2020-12/schema",
      +  "additionalProperties": {},
      +  "properties": {
      +    "candidates": {
      +      "description": "Present only when match_type is 'semantic'. Candidates are not attributions.",
      +      "items": {
      +        "additionalProperties": {},
      +        "properties": {
      +          "org": {
      +            "description": "Candidate organization name — a semantic match, NOT an attribution.",
      +            "type": "string"
      +          },
      +          "similarity": {
      +            "description": "Name-embedding similarity, 0..1.",
      +            "type": "number"
      +          },
      +          "top_apex_domain": {
      +            "description": "The apex domain most often attributed to this candidate, if any.",
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          }
      +        },
      +        "required": [
      +          "org"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "domains": {
      +      "description": "Attributed (domain, organization) pairs. Empty when nothing is attributed.",
      +      "items": {
      +        "additionalProperties": {},
      +        "properties": {
      +          "apex_domain": {
      +            "type": "string"
      +          },
      +          "attributed_to": {
      +            "type": "string"
      +          },
      +          "cert_count": {
      +            "description": "Distinct certificates observed for this pair.",
      +            "type": "number"
      +          },
      +          "domain": {
      +            "description": "Deep-dive row shape: the apex domain (no apex_domain field).",
      +            "type": "string"
      +          },
      +          "first_seen": {
      +            "description": "When the warehouse first ingested this pair (observation time, NOT the CT log SCT / issuance time).",
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          },
      +          "last_seen": {
      +            "description": "When the warehouse last ingested this pair (observation time, not SCT time).",
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          },
      +          "org": {
      +            "description": "Organization the domain is attributed to. Free tier: the OV/EV cert subject O field. On /scan, both tiers: the OV/EV certificate subject. Multi-signal attribution lives in a deep-dive job result (attributed_to + enrichment), not here.",
      +            "type": "string"
      +          },
      +          "subdomain_count": {
      +            "type": "number"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "empty_reason": {
      +      "type": "string"
      +    },
      +    "match_type": {
      +      "description": "'exact' = domains are warehouse attributions; 'semantic' = domains is empty and candidates holds name-similarity guesses; 'none' = nothing matched.",
      +      "type": "string"
      +    },
      +    "org_match_strategy": {
      +      "type": "string"
      +    },
      +    "snapshot": {
      +      "description": "Warehouse/D1 sync date (YYYY-MM-DD) the answer was read from; the warehouse syncs daily. null when the API could not determine it.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "snapshot_source": {
      +      "description": "'scan' = the API response carried the date; 'unavailable' = it did not, snapshot is null and must be treated as unknown, never as current.",
      +      "enum": [
      +        "scan",
      +        "unavailable"
      +      ],
      +      "type": "string"
      +    },
      +    "source": {
      +      "description": "'warehouse' on /scan (both tiers); 'live-enriched' / 'cache-only' on a deep-dive result.",
      +      "type": "string"
      +    },
      +    "total": {
      +      "description": "Matching pairs in the warehouse before any cap.",
      +      "type": "number"
      +    },
      +    "truncated": {
      +      "type": "boolean"
      +    },
      +    "upgrade_hint": {
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "domains",
      +    "snapshot",
      +    "snapshot_source"
      +  ],
      +  "type": "object"
      +}
  2. First observedv0.2.5

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, but the description goes far beyond by detailing error handling (401/429), truncation via 'truncated' flag, snapshot freshness semantics, match_type behavior, and the difference between attribution and candidates. It discloses that success/failure is conveyed via structuredContent vs isError, and explains auth requirements. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-organized with clear section headers (Args, Returns, Examples, Auth, Error handling, Caveats). It front-loads the core purpose and returns structure before diving into caveats. While some repetition exists (snapshot freshness mentioned multiple times), each section serves a distinct purpose. It earns a high score for structure, slightly deducted for length that could be trimmed without losing critical info.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 params, 4 enums, output schema), the description is exceptionally complete. It covers all error scenarios, quota limits, legal-name pitfalls, coverage limitations, and even provides correction channels. The output schema is referenced and the JSON response structure is fully documented. An agent has everything needed to call this tool correctly in various situations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds substantial meaning beyond the schema. For instance, org_match_field gets a full explanation of normalization rules (GLEIF legal forms, '&' vs 'and', leading 'The' dropping, etc.), and org_match_mode is clarified as word-boundary matching. The response_format parameter is expanded with JSON structure details. The description enriches every parameter beyond the schema's basic type/enum descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches ctscout.dev's domain-attribution warehouse by organization name and returns attributed apex domains. It explicitly differentiates from sibling tools by naming when NOT to use it (domain lookup) and pointing to ctscout_lookup_domain. The verb 'search' and specific resource 'domain-attribution warehouse' make the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use examples ('Find all domains attributed to Cloudflare') and a direct exclusion for domain-to-org lookups. It also gives detailed usage guidance on legal-vs-brand naming, coverage limitations, and handling empty results with retry suggestions. The 'Don't use when' line names the alternative tool, fulfilling the when-not/alternatives criterion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.