Skip to main content
Glama

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

NameRequiredDescriptionDefault
facetsNoList of facets to include in the search results (e.g., ['country', 'org'])
fieldsNoList of fields to include in the results (e.g., ['ip_str', 'ports', 'location.country_name'])
max_itemsNoMaximum number of items to include in arrays (default: 5)
pageNoPage number for results pagination (default: 1)
queryYesShodan search query (e.g., 'apache country:US')
summarizeNoWhether 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

  • 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"] }
  • 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}` ); } }
  • 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; } }
  • 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)" } } } } ] }; });

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/Cyreslab-AI/shodan-mcp-server'

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