search_shodan
Query Shodan's database to discover internet-connected devices and services. Analyze results with customizable fields, facets, and pagination for cybersecurity research and threat intelligence.
Instructions
Search Shodan's database for devices and services
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| facets | No | List of facets to include in the search results (e.g., ['country', 'org']) | |
| fields | No | List of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name']) | |
| max_items | No | Maximum number of items to include in arrays (default: 5) | |
| page | No | Page number for results pagination (default: 1) | |
| query | Yes | Shodan search query (e.g., 'apache country:US') | |
| summarize | No | Whether to return a summary of the results instead of the full data (default: false) |
Input Schema (JSON Schema)
{
"properties": {
"facets": {
"description": "List of facets to include in the search results (e.g., ['country', 'org'])",
"items": {
"type": "string"
},
"type": "array"
},
"fields": {
"description": "List of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name'])",
"items": {
"type": "string"
},
"type": "array"
},
"max_items": {
"description": "Maximum number of items to include in arrays (default: 5)",
"type": "number"
},
"page": {
"description": "Page number for results pagination (default: 1)",
"type": "number"
},
"query": {
"description": "Shodan search query (e.g., 'apache country:US')",
"type": "string"
},
"summarize": {
"description": "Whether to return a summary of the results instead of the full data (default: false)",
"type": "boolean"
}
},
"required": [
"query"
],
"type": "object"
}
Implementation Reference
- src/index.ts:904-941 (schema)Input schema definition for the search_shodan tool, registered in ListToolsRequestSchema handler.name: "search_shodan", description: "Search Shodan's database for devices and services", inputSchema: { type: "object", properties: { query: { type: "string", description: "Shodan search query (e.g., 'apache country:US')" }, page: { type: "number", description: "Page number for results pagination (default: 1)" }, facets: { type: "array", items: { type: "string" }, description: "List of facets to include in the search results (e.g., ['country', 'org'])" }, max_items: { type: "number", description: "Maximum number of items to include in arrays (default: 5)" }, fields: { type: "array", items: { type: "string" }, description: "List of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name'])" }, summarize: { type: "boolean", description: "Whether to return a summary of the results instead of the full data (default: false)" } }, required: ["query"] }
- src/index.ts:1317-1374 (handler)MCP tool handler for search_shodan in CallToolRequestSchema switch statement. Parses arguments, calls ShodanClient.search, handles summarization and returns JSON response.case "search_shodan": { const query = String(request.params.arguments?.query); if (!query) { throw new McpError( ErrorCode.InvalidParams, "Search query is required" ); } const page = Number(request.params.arguments?.page) || 1; const facets = Array.isArray(request.params.arguments?.facets) ? request.params.arguments?.facets.map(String) : []; const maxItems = Number(request.params.arguments?.max_items) || 5; const fields = Array.isArray(request.params.arguments?.fields) ? request.params.arguments?.fields.map(String) : undefined; const summarize = Boolean(request.params.arguments?.summarize); try { const searchResults = await shodanClient.search(query, page, facets, maxItems, fields); // Check if we got an error response from the search method if (searchResults.error && searchResults.status === 401) { return { content: [{ type: "text", text: JSON.stringify(searchResults, null, 2) }] }; } if (summarize) { const summary = shodanClient.summarizeResults(searchResults); return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] }; } return { content: [{ type: "text", text: JSON.stringify(searchResults, null, 2) }] }; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Error searching Shodan: ${(error as Error).message}` ); } }
- src/index.ts:155-184 (helper)Core ShodanClient.search method that performs the API call to /shodan/host/search, handles sampling and 401 errors.async search(query: string, page: number = 1, facets: string[] = [], maxItems: number = 5, selectedFields?: string[]): Promise<any> { try { const params: any = { query, page }; if (facets.length > 0) { params.facets = facets.join(','); } const response = await this.axiosInstance.get("/shodan/host/search", { params }); return this.sampleResponse(response.data, maxItems, selectedFields); } catch (error: unknown) { if (axios.isAxiosError(error)) { if (error.response?.status === 401) { return { error: "Unauthorized: The Shodan search API requires a paid membership. Your API key does not have access to this endpoint.", message: "The search functionality requires a Shodan membership subscription with API access. Please upgrade your Shodan plan to use this feature.", status: 401 }; } throw new McpError( ErrorCode.InternalError, `Shodan API error: ${error.response?.data?.error || error.message}` ); } throw error; } }
- src/index.ts:580-635 (helper)ShodanClient.summarizeResults helper method used optionally by the tool handler to generate summaries of search results.summarizeResults(data: any): any { if (!data || !data.matches || !Array.isArray(data.matches)) { return { error: "No valid data to summarize" }; } // Count countries const countries = new Map<string, number>(); data.matches.forEach((match: any) => { if (match.location && match.location.country_name) { const country = match.location.country_name; countries.set(country, (countries.get(country) || 0) + 1); } }); // Count organizations const organizations = new Map<string, number>(); data.matches.forEach((match: any) => { if (match.org) { const org = match.org; organizations.set(org, (organizations.get(org) || 0) + 1); } }); // Count ports const ports = new Map<number, number>(); data.matches.forEach((match: any) => { if (match.port) { const port = match.port; ports.set(port, (ports.get(port) || 0) + 1); } }); // Convert maps to sorted arrays const topCountries = Array.from(countries.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([name, count]) => ({ name, count })); const topOrganizations = Array.from(organizations.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([name, count]) => ({ name, count })); const topPorts = Array.from(ports.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([port, count]) => ({ port, count })); return { total_results: data.total, sample_size: data.matches.length, top_countries: topCountries, top_organizations: topOrganizations, top_ports: topPorts }; }
- src/index.ts:875-1281 (registration)Tool registration via static list in ListToolsRequestSchema handler, includes search_shodan schema.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_host_info", description: "Get detailed information about a specific IP address", inputSchema: { type: "object", properties: { ip: { type: "string", description: "IP address to look up" }, max_items: { type: "number", description: "Maximum number of items to include in arrays (default: 5)" }, fields: { type: "array", items: { type: "string" }, description: "List of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name'])" } }, required: ["ip"] } }, { name: "search_shodan", description: "Search Shodan's database for devices and services", inputSchema: { type: "object", properties: { query: { type: "string", description: "Shodan search query (e.g., 'apache country:US')" }, page: { type: "number", description: "Page number for results pagination (default: 1)" }, facets: { type: "array", items: { type: "string" }, description: "List of facets to include in the search results (e.g., ['country', 'org'])" }, max_items: { type: "number", description: "Maximum number of items to include in arrays (default: 5)" }, fields: { type: "array", items: { type: "string" }, description: "List of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name'])" }, summarize: { type: "boolean", description: "Whether to return a summary of the results instead of the full data (default: false)" } }, required: ["query"] } }, { name: "scan_network_range", description: "Scan a network range (CIDR notation) for devices", inputSchema: { type: "object", properties: { cidr: { type: "string", description: "Network range in CIDR notation (e.g., 192.168.1.0/24)" }, max_items: { type: "number", description: "Maximum number of items to include in results (default: 5)" }, fields: { type: "array", items: { type: "string" }, description: "List of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name'])" } }, required: ["cidr"] } }, { name: "get_ssl_info", description: "Get SSL certificate information for a domain", inputSchema: { type: "object", properties: { domain: { type: "string", description: "Domain name to look up SSL certificates for (e.g., example.com)" } }, required: ["domain"] } }, { name: "search_iot_devices", description: "Search for specific types of IoT devices", inputSchema: { type: "object", properties: { device_type: { type: "string", description: "Type of IoT device to search for (e.g., 'webcam', 'router', 'smart tv')" }, country: { type: "string", description: "Optional country code to limit search (e.g., 'US', 'DE')" }, max_items: { type: "number", description: "Maximum number of items to include in results (default: 5)" } }, required: ["device_type"] } }, { name: "get_host_count", description: "Get the count of hosts matching a search query without consuming query credits", inputSchema: { type: "object", properties: { query: { type: "string", description: "Shodan search query to count hosts for" }, facets: { type: "array", items: { type: "string" }, description: "List of facets to include in the count results (e.g., ['country', 'org'])" } }, required: ["query"] } }, { name: "list_search_facets", description: "List all available search facets that can be used with Shodan queries", inputSchema: { type: "object", properties: {} } }, { name: "list_search_filters", description: "List all available search filters that can be used in Shodan queries", inputSchema: { type: "object", properties: {} } }, { name: "parse_search_tokens", description: "Parse a search query to understand which filters and parameters are being used", inputSchema: { type: "object", properties: { query: { type: "string", description: "Shodan search query to parse and analyze" } }, required: ["query"] } }, { name: "list_ports", description: "List all ports that Shodan crawls on the Internet", inputSchema: { type: "object", properties: {} } }, { name: "list_protocols", description: "List all protocols that can be used when performing on-demand Internet scans", inputSchema: { type: "object", properties: {} } }, { name: "get_api_info", description: "Get information about your API plan including credits and limits", inputSchema: { type: "object", properties: {} } }, { name: "get_my_ip", description: "Get your current IP address as seen from the Internet", inputSchema: { type: "object", properties: {} } }, { name: "dns_lookup", description: "Resolve hostnames to IP addresses using DNS lookup", inputSchema: { type: "object", properties: { hostnames: { type: "array", items: { type: "string" }, description: "List of hostnames to resolve (e.g., ['google.com', 'facebook.com'])" } }, required: ["hostnames"] } }, { name: "reverse_dns_lookup", description: "Get hostnames for IP addresses using reverse DNS lookup", inputSchema: { type: "object", properties: { ips: { type: "array", items: { type: "string" }, description: "List of IP addresses to lookup (e.g., ['8.8.8.8', '1.1.1.1'])" } }, required: ["ips"] } }, { name: "get_domain_info", description: "Get comprehensive domain information including subdomains and DNS records", inputSchema: { type: "object", properties: { domain: { type: "string", description: "Domain name to lookup (e.g., 'google.com')" }, history: { type: "boolean", description: "Include historical DNS data (default: false)" }, type: { type: "string", description: "DNS record type filter (A, AAAA, CNAME, NS, SOA, MX, TXT)" }, page: { type: "number", description: "Page number for pagination (default: 1)" } }, required: ["domain"] } }, { name: "get_account_profile", description: "Get account profile information including membership status and credits", inputSchema: { type: "object", properties: {} } }, { name: "get_cve_info", description: "Get detailed information about a specific CVE", inputSchema: { type: "object", properties: { cve_id: { type: "string", description: "CVE ID to look up (e.g., 'CVE-2021-44228')" } }, required: ["cve_id"] } }, { name: "search_cves", description: "Search for vulnerabilities with various filters", inputSchema: { type: "object", properties: { cpe23: { type: "string", description: "CPE 2.3 string to search for (e.g., 'cpe:2.3:a:apache:log4j:*')" }, product: { type: "string", description: "Product name to search for vulnerabilities (e.g., 'apache', 'windows')" }, is_kev: { type: "boolean", description: "Filter for Known Exploited Vulnerabilities only" }, sort_by_epss: { type: "boolean", description: "Sort results by EPSS score (Exploit Prediction Scoring System)" }, start_date: { type: "string", description: "Start date for filtering CVEs (YYYY-MM-DD format)" }, end_date: { type: "string", description: "End date for filtering CVEs (YYYY-MM-DD format)" }, limit: { type: "number", description: "Maximum number of results to return (default: 10)" }, skip: { type: "number", description: "Number of results to skip for pagination (default: 0)" } } } }, { name: "get_cpes", description: "Get Common Platform Enumeration (CPE) information for products", inputSchema: { type: "object", properties: { product: { type: "string", description: "Product name to search for (e.g., 'apache', 'windows')" }, vendor: { type: "string", description: "Vendor name to filter by (e.g., 'microsoft', 'apache')" }, version: { type: "string", description: "Version to filter by (e.g., '2.4.1')" }, limit: { type: "number", description: "Maximum number of results to return (default: 10)" }, skip: { type: "number", description: "Number of results to skip for pagination (default: 0)" } } } }, { name: "get_newest_cves", description: "Get the newest vulnerabilities from the CVE database", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Maximum number of results to return (default: 10)" } } } }, { name: "get_kev_cves", description: "Get Known Exploited Vulnerabilities (KEV) from CISA", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Maximum number of results to return (default: 10)" } } } }, { name: "get_cves_by_epss", description: "Get CVEs sorted by EPSS score (Exploit Prediction Scoring System)", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Maximum number of results to return (default: 10)" } } } } ] }; });