shodan_search
Search Shodan for internet-connected devices using specific queries to identify hosts, services, and configurations for security analysis and reconnaissance.
Instructions
Search Shodan for hosts matching a query (e.g. 'apache port:443 country:US'). Requires SHODAN_API_KEY.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Shodan search query | |
| page | No | Results page number (default: 1) | |
| facets | No | Facets to include (e.g. 'country,org') |
Implementation Reference
- src/shodan/index.ts:99-122 (handler)The actual implementation of the shodan_search logic, which fetches data from the Shodan host search API.
export async function shodanSearch(query: string, apiKey: string, page = 1, facets?: string): Promise<ShodanSearchResult> { await limiter.acquire(); const params = new URLSearchParams({ key: apiKey, query, page: String(page) }); if (facets) params.set("facets", facets); const res = await fetch(`https://api.shodan.io/shodan/host/search?${params}`); if (!res.ok) throw new Error(`Shodan search failed: ${res.status} ${res.statusText}`); const data = await res.json(); return { total: data.total ?? 0, matches: (data.matches ?? []).map((m: any) => ({ ip_str: m.ip_str, port: m.port, org: m.org, hostnames: m.hostnames ?? [], product: m.product, os: m.os, asn: m.asn, domains: m.domains ?? [], })), facets: data.facets, }; } - src/shodan/index.ts:45-49 (schema)Type definition for the result returned by shodanSearch.
interface ShodanSearchResult { total: number; matches: ShodanSearchMatch[]; facets?: Record<string, [string, number][]>; } - src/protocol/tools.ts:139-152 (registration)Registration of the shodan_search tool in the MCP tool framework, which calls the shodanSearch handler.
const shodanSearchTool: ToolDef = { name: "shodan_search", description: "Search Shodan for hosts matching a query (e.g. 'apache port:443 country:US'). Requires SHODAN_API_KEY.", schema: { query: z.string().describe("Shodan search query"), page: z.number().optional().describe("Results page number (default: 1)"), facets: z.string().optional().describe("Facets to include (e.g. 'country,org')"), }, execute: async (args, ctx) => { const key = requireApiKey(ctx.config.shodanApiKey, "Shodan", "SHODAN_API_KEY"); return json(await shodanSearch(args.query as string, key, args.page as number | undefined, args.facets as string | undefined)); }, };