Skip to main content
Glama
badchars

osint-mcp-server

by badchars

crtsh_search

Search Certificate Transparency logs to discover subdomains and analyze SSL/TLS certificates for domain reconnaissance and attack surface mapping.

Instructions

Search Certificate Transparency logs via crt.sh. Returns unique subdomains and certificate details (issuer, validity, SANs).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
domainYesDomain to search CT logs for
exclude_expiredNoExclude expired certificates (default: false)

Implementation Reference

  • The core implementation of the crtsh_search tool. It queries crt.sh, processes the JSON response, deduplicates subdomains, handles expiration filtering, and caches results.
    export async function crtshSearch(domain: string, excludeExpired = false): Promise<CrtshResult> {
      const cacheKey = `${domain}:${excludeExpired}`;
      const cached = cache.get(cacheKey);
      if (cached) return cached;
    
      await limiter.acquire();
    
      const controller = new AbortController();
      const timeout = setTimeout(() => controller.abort(), 30000);
    
      try {
        const url = `https://crt.sh/?q=%25.${encodeURIComponent(domain)}&output=json`;
        const res = await fetch(url, { signal: controller.signal });
        if (!res.ok) throw new Error(`crt.sh returned ${res.status}`);
    
        const data: any[] = await res.json();
        const now = Date.now();
    
        // Deduplicate subdomains
        const subdomainSet = new Set<string>();
        const certificates: CrtshCert[] = [];
    
        for (const entry of data) {
          const nameValue: string = entry.name_value ?? "";
          const notAfter = entry.not_after ? new Date(entry.not_after).getTime() : Infinity;
    
          if (excludeExpired && notAfter < now) continue;
    
          // name_value can contain multiple domains separated by \n
          const names = nameValue.split("\n").map((n: string) => n.trim().toLowerCase()).filter(Boolean);
          for (const name of names) {
            if (!name.startsWith("*")) subdomainSet.add(name);
            else subdomainSet.add(name); // Keep wildcards too
          }
    
          certificates.push({
            issuer: entry.issuer_name ?? "",
            commonName: entry.common_name ?? "",
            nameValue,
            notBefore: entry.not_before ?? "",
            notAfter: entry.not_after ?? "",
            id: entry.id ?? 0,
          });
        }
    
        // Sort subdomains and limit certificates shown
        const uniqueSubdomains = [...subdomainSet].sort();
    
        const result: CrtshResult = {
          domain,
          totalCerts: data.length,
          uniqueSubdomains,
          certificates: certificates.slice(0, 50), // Limit to avoid huge responses
        };
    
        cache.set(cacheKey, result);
        return result;
      } finally {
        clearTimeout(timeout);
      }
    }
  • Registration of the crtsh_search tool including its schema definition and invocation of the handler.
    const crtshSearchTool: ToolDef = {
      name: "crtsh_search",
      description: "Search Certificate Transparency logs via crt.sh. Returns unique subdomains and certificate details (issuer, validity, SANs).",
      schema: {
        domain: z.string().describe("Domain to search CT logs for"),
        exclude_expired: z.boolean().optional().describe("Exclude expired certificates (default: false)"),
      },
      execute: async (args) =>
        json(await crtshSearch(args.domain as string, args.exclude_expired as boolean | undefined)),
    };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/badchars/osint-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server