@burtthecoder/mcp-shodan 1.0.12 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +103 -39
  2. package/build/index.js +263 -47
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Shodan MCP Server
2
2
 
3
- A Model Context Protocol (MCP) server for querying the [Shodan API](https://shodan.io) and [Shodan CVEDB](https://cvedb.shodan.io). This server provides tools for IP lookups, device searches, DNS lookups, vulnerability queries, CPE lookups, and more. It is designed to integrate seamlessly with MCP-compatible applications like [Claude Desktop](https://claude.ai).
3
+ A Model Context Protocol (MCP) server for querying the [Shodan API](https://shodan.io) and [Shodan CVEDB](https://cvedb.shodan.io). This server provides comprehensive access to Shodan's network intelligence and security services, including IP reconnaissance, DNS operations, vulnerability tracking, and device discovery. All tools provide structured, formatted output for easy analysis and integration.
4
+
5
+ <a href="https://glama.ai/mcp/servers/79uakvikcj"><img width="380" height="200" src="https://glama.ai/mcp/servers/79uakvikcj/badge" /></a>
4
6
 
5
7
  ## Quick Start (Recommended)
6
8
 
@@ -58,45 +60,78 @@ npm run build
58
60
 
59
61
  ## Features
60
62
 
61
- - **IP Lookup**: Retrieve detailed information about an IP address
62
- - **Search**: Search for devices on Shodan matching specific queries
63
- - **Ports**: Get a list of ports that Shodan is scanning
64
- - **CVE Lookup**: Fetch detailed information about specific CVEs using Shodan's CVEDB
65
- - **CPE Lookup**: Search for Common Platform Enumeration (CPE) entries by product name
66
- - **CVEs by Product**: Search for all CVEs affecting a specific product or CPE
67
- - **DNS Lookup**: Resolve hostnames to IP addresses
63
+ - **Network Reconnaissance**: Query detailed information about IP addresses, including open ports, services, and vulnerabilities
64
+ - **DNS Operations**: Forward and reverse DNS lookups for domains and IP addresses
65
+ - **Vulnerability Intelligence**: Access to Shodan's CVEDB for detailed vulnerability information, CPE lookups, and product-specific CVE tracking
66
+ - **Device Discovery**: Search Shodan's database of internet-connected devices with advanced filtering
68
67
 
69
68
  ## Tools
70
69
 
71
70
  ### 1. IP Lookup Tool
72
71
  - Name: `ip_lookup`
73
- - Description: Retrieve detailed information about an IP address
72
+ - Description: Retrieve comprehensive information about an IP address, including geolocation, open ports, running services, SSL certificates, hostnames, and cloud provider details if available
74
73
  - Parameters:
75
74
  * `ip` (required): IP address to lookup
76
-
77
- ### 2. Search Tool
78
- - Name: `search`
79
- - Description: Search for devices on Shodan
75
+ - Returns:
76
+ * IP Information (address, organization, ISP, ASN)
77
+ * Location (country, city, coordinates)
78
+ * Services (ports, protocols, banners)
79
+ * Cloud Provider details (if available)
80
+ * Associated hostnames and domains
81
+ * Tags
82
+
83
+ ### 2. Shodan Search Tool
84
+ - Name: `shodan_search`
85
+ - Description: Search Shodan's database of internet-connected devices
80
86
  - Parameters:
81
87
  * `query` (required): Shodan search query
82
88
  * `max_results` (optional, default: 10): Number of results to return
89
+ - Returns:
90
+ * Search summary with total results
91
+ * Country-based distribution statistics
92
+ * Detailed device information including:
93
+ - Basic information (IP, organization, ISP)
94
+ - Location data
95
+ - Service details
96
+ - Web server information
97
+ - Associated hostnames and domains
83
98
 
84
99
  ### 3. CVE Lookup Tool
85
100
  - Name: `cve_lookup`
86
- - Description: Fetch detailed information about CVEs using Shodan's CVEDB
101
+ - Description: Query detailed vulnerability information from Shodan's CVEDB
87
102
  - Parameters:
88
103
  * `cve` (required): CVE identifier in format CVE-YYYY-NNNNN (e.g., CVE-2021-44228)
89
104
  - Returns:
90
- * CVE details including:
91
- - CVSS v2 and v3 scores
92
- - EPSS score and ranking
105
+ * Basic Information (ID, published date, summary)
106
+ * Severity Scores:
107
+ - CVSS v2 and v3 with severity levels
108
+ - EPSS probability and ranking
109
+ * Impact Assessment:
93
110
  - KEV status
94
- - Proposed action
95
- - Ransomware campaign information
96
- - Affected products (CPEs)
97
- - References
111
+ - Proposed mitigations
112
+ - Ransomware associations
113
+ * Affected products (CPEs)
114
+ * References
115
+
116
+ ### 4. DNS Lookup Tool
117
+ - Name: `dns_lookup`
118
+ - Description: Resolve domain names to IP addresses using Shodan's DNS service
119
+ - Parameters:
120
+ * `hostnames` (required): Array of hostnames to resolve
121
+ - Returns:
122
+ * DNS resolutions mapping hostnames to IPs
123
+ * Summary of total lookups and queried hostnames
98
124
 
99
- ### 4. CPE Lookup Tool
125
+ ### 5. Reverse DNS Lookup Tool
126
+ - Name: `reverse_dns_lookup`
127
+ - Description: Perform reverse DNS lookups to find hostnames associated with IP addresses
128
+ - Parameters:
129
+ * `ips` (required): Array of IP addresses to lookup
130
+ - Returns:
131
+ * Reverse DNS resolutions mapping IPs to hostnames
132
+ * Summary of total lookups and results
133
+
134
+ ### 6. CPE Lookup Tool
100
135
  - Name: `cpe_lookup`
101
136
  - Description: Search for Common Platform Enumeration (CPE) entries by product name
102
137
  - Parameters:
@@ -108,9 +143,9 @@ npm run build
108
143
  * When count is true: Total number of matching CPEs
109
144
  * When count is false: List of CPEs with pagination details
110
145
 
111
- ### 5. CVEs by Product Tool
146
+ ### 7. CVEs by Product Tool
112
147
  - Name: `cves_by_product`
113
- - Description: Search for CVEs affecting a specific product or CPE
148
+ - Description: Search for vulnerabilities affecting specific products or CPEs
114
149
  - Parameters:
115
150
  * `cpe23` (optional): CPE 2.3 identifier (format: cpe:2.3:part:vendor:product:version)
116
151
  * `product` (optional): Name of the product to search for CVEs
@@ -125,14 +160,13 @@ npm run build
125
160
  * Must provide either cpe23 or product, but not both
126
161
  * Date filtering uses published time of CVEs
127
162
  - Returns:
128
- * When count is true: Total number of matching CVEs
129
- * When count is false: List of CVEs with pagination details and query parameters
130
-
131
- ### 6. DNS Lookup Tool
132
- - Name: `dns_lookup`
133
- - Description: Resolve hostnames to IP addresses
134
- - Parameters:
135
- * `hostnames` (required): Array of hostnames to resolve
163
+ * Query information
164
+ * Results summary with pagination details
165
+ * Detailed vulnerability information including:
166
+ - Basic information
167
+ - Severity scores
168
+ - Impact assessments
169
+ - References
136
170
 
137
171
  ## Requirements
138
172
 
@@ -143,15 +177,44 @@ npm run build
143
177
 
144
178
  ### API Key Issues
145
179
 
146
- If you see API key related errors:
180
+ If you see API key related errors (e.g., "Request failed with status code 401"):
147
181
 
148
182
  1. Verify your API key:
149
- - Should be a valid Shodan API key
150
- - No extra spaces or quotes around the key
151
- - Must be from your Shodan account settings
152
- 2. After any configuration changes:
153
- - Save the config file
154
- - Restart Claude Desktop
183
+ - Must be a valid Shodan API key from your [account settings](https://account.shodan.io/)
184
+ - Ensure the key has sufficient credits/permissions for the operation
185
+ - Check for extra spaces or quotes around the key in the configuration
186
+ - Verify the key is correctly set in the SHODAN_API_KEY environment variable
187
+
188
+ 2. Common Error Codes:
189
+ - 401 Unauthorized: Invalid API key or missing authentication
190
+ - 402 Payment Required: Out of query credits
191
+ - 429 Too Many Requests: Rate limit exceeded
192
+
193
+ 3. Configuration Steps:
194
+ a. Get your API key from [Shodan Account](https://account.shodan.io/)
195
+ b. Add it to your configuration file:
196
+ ```json
197
+ {
198
+ "mcpServers": {
199
+ "shodan": {
200
+ "command": "mcp-shodan",
201
+ "env": {
202
+ "SHODAN_API_KEY": "your-actual-api-key-here"
203
+ }
204
+ }
205
+ }
206
+ }
207
+ ```
208
+ c. Save the config file
209
+ d. Restart Claude Desktop
210
+
211
+ 4. Testing Your Key:
212
+ - Try a simple query first (e.g., dns_lookup for "google.com")
213
+ - Check your [Shodan account dashboard](https://account.shodan.io/) for credit status
214
+ - Verify the key works directly with curl:
215
+ ```bash
216
+ curl "https://api.shodan.io/dns/resolve?hostnames=google.com&key=your-api-key"
217
+ ```
155
218
 
156
219
  ### Module Loading Issues
157
220
 
@@ -180,6 +243,7 @@ The server includes comprehensive error handling for:
180
243
 
181
244
  ## Version History
182
245
 
246
+ - v1.0.12: Added reverse DNS lookup and improved output formatting
183
247
  - v1.0.7: Added CVEs by Product search functionality and renamed vulnerabilities tool to cve_lookup
184
248
  - v1.0.6: Added CVEDB integration for enhanced CVE lookups and CPE search functionality
185
249
  - v1.0.0: Initial release with core functionality
package/build/index.js CHANGED
@@ -33,7 +33,7 @@ function logToFile(message) {
33
33
  const IpLookupArgsSchema = z.object({
34
34
  ip: z.string().describe("The IP address to query."),
35
35
  });
36
- const SearchArgsSchema = z.object({
36
+ const ShodanSearchArgsSchema = z.object({
37
37
  query: z.string().describe("Search query for Shodan."),
38
38
  max_results: z
39
39
  .number()
@@ -49,6 +49,9 @@ const CVELookupArgsSchema = z.object({
49
49
  const DnsLookupArgsSchema = z.object({
50
50
  hostnames: z.array(z.string()).describe("List of hostnames to resolve."),
51
51
  });
52
+ const ReverseDnsLookupArgsSchema = z.object({
53
+ ips: z.array(z.string()).describe("List of IP addresses to perform reverse DNS lookup on."),
54
+ });
52
55
  const CpeLookupArgsSchema = z.object({
53
56
  product: z.string().describe("The name of the product to search for CPEs."),
54
57
  count: z.boolean().optional().default(false).describe("If true, returns only the count of matching CPEs."),
@@ -151,7 +154,14 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
151
154
  name: "shodan-mcp",
152
155
  version: "1.0.0",
153
156
  },
154
- instructions: "This server provides tools for querying Shodan, including IP lookups, searches, CVE lookups, CPE lookups, and CVE searches by product/CPE.",
157
+ instructions: `This MCP server provides comprehensive access to Shodan's network intelligence and security services:
158
+
159
+ - Network Reconnaissance: Query detailed information about IP addresses, including open ports, services, and vulnerabilities
160
+ - DNS Operations: Forward and reverse DNS lookups for domains and IP addresses
161
+ - Vulnerability Intelligence: Access to Shodan's CVEDB for detailed vulnerability information, CPE lookups, and product-specific CVE tracking
162
+ - Device Discovery: Search Shodan's database of internet-connected devices with advanced filtering
163
+
164
+ Each tool provides structured, formatted output for easy analysis and integration.`,
155
165
  };
156
166
  });
157
167
  // Register Tools
@@ -159,34 +169,39 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
159
169
  const tools = [
160
170
  {
161
171
  name: "ip_lookup",
162
- description: "Retrieve information about an IP address.",
172
+ description: "Retrieve comprehensive information about an IP address, including geolocation, open ports, running services, SSL certificates, hostnames, and cloud provider details if available. Returns service banners and HTTP server information when present.",
163
173
  inputSchema: zodToJsonSchema(IpLookupArgsSchema),
164
174
  },
165
175
  {
166
- name: "search",
167
- description: "Search for devices on Shodan.",
168
- inputSchema: zodToJsonSchema(SearchArgsSchema),
176
+ name: "shodan_search",
177
+ description: "Search Shodan's database of internet-connected devices. Returns detailed information about matching devices including services, vulnerabilities, and geographic distribution. Supports advanced search filters and returns country-based statistics.",
178
+ inputSchema: zodToJsonSchema(ShodanSearchArgsSchema),
169
179
  },
170
180
  {
171
181
  name: "cve_lookup",
172
- description: "Retrieve vulnerability information for a CVE. Use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)",
182
+ description: "Query detailed vulnerability information from Shodan's CVEDB. Returns comprehensive CVE details including CVSS scores (v2/v3), EPSS probability and ranking, KEV status, proposed mitigations, ransomware associations, and affected products (CPEs).",
173
183
  inputSchema: zodToJsonSchema(CVELookupArgsSchema),
174
184
  },
175
185
  {
176
186
  name: "dns_lookup",
177
- description: "Perform DNS lookups using Shodan.",
187
+ description: "Resolve domain names to IP addresses using Shodan's DNS service. Supports batch resolution of multiple hostnames in a single query. Returns IP addresses mapped to their corresponding hostnames.",
178
188
  inputSchema: zodToJsonSchema(DnsLookupArgsSchema),
179
189
  },
180
190
  {
181
191
  name: "cpe_lookup",
182
- description: "Search for Common Platform Enumeration (CPE) entries by product name.",
192
+ description: "Search for Common Platform Enumeration (CPE) entries by product name in Shodan's CVEDB. Supports pagination and can return either full CPE details or just the total count. Useful for identifying specific versions and configurations of software and hardware.",
183
193
  inputSchema: zodToJsonSchema(CpeLookupArgsSchema),
184
194
  },
185
195
  {
186
196
  name: "cves_by_product",
187
- description: "Search for CVEs affecting a specific product or CPE. Provide either product name or CPE 2.3 identifier.",
197
+ description: "Search for vulnerabilities affecting specific products or CPEs. Supports filtering by KEV status, sorting by EPSS score, date ranges, and pagination. Can search by product name or CPE 2.3 identifier. Returns detailed vulnerability information including severity scores and impact assessments.",
188
198
  inputSchema: zodToJsonSchema(CVEsByProductArgsSchema),
189
199
  },
200
+ {
201
+ name: "reverse_dns_lookup",
202
+ description: "Perform reverse DNS lookups to find hostnames associated with IP addresses. Supports batch lookups of multiple IP addresses in a single query. Returns all known hostnames for each IP address, with clear indication when no hostnames are found.",
203
+ inputSchema: zodToJsonSchema(ReverseDnsLookupArgsSchema),
204
+ },
190
205
  ];
191
206
  logToFile("Registered tools.");
192
207
  return { tools };
@@ -203,17 +218,55 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
203
218
  throw new Error("Invalid ip_lookup arguments");
204
219
  }
205
220
  const result = await queryShodan(`/shodan/host/${parsedIpArgs.data.ip}`, {});
221
+ // Format the response in a user-friendly way
222
+ const formattedResult = {
223
+ "IP Information": {
224
+ "IP Address": result.ip_str,
225
+ "Organization": result.org,
226
+ "ISP": result.isp,
227
+ "ASN": result.asn,
228
+ "Last Update": result.last_update
229
+ },
230
+ "Location": {
231
+ "Country": result.country_name,
232
+ "City": result.city,
233
+ "Coordinates": `${result.latitude}, ${result.longitude}`,
234
+ "Region": result.region_code
235
+ },
236
+ "Services": result.ports.map((port) => {
237
+ const service = result.data.find((d) => d.port === port);
238
+ return {
239
+ "Port": port,
240
+ "Protocol": service?.transport || "unknown",
241
+ "Service": service?.data?.trim() || "No banner",
242
+ ...(service?.http ? {
243
+ "HTTP": {
244
+ "Server": service.http.server,
245
+ "Title": service.http.title,
246
+ }
247
+ } : {})
248
+ };
249
+ }),
250
+ "Cloud Provider": result.data[0]?.cloud ? {
251
+ "Provider": result.data[0].cloud.provider,
252
+ "Service": result.data[0].cloud.service,
253
+ "Region": result.data[0].cloud.region
254
+ } : "Not detected",
255
+ "Hostnames": result.hostnames || [],
256
+ "Domains": result.domains || [],
257
+ "Tags": result.tags || []
258
+ };
206
259
  return {
207
260
  content: [
208
261
  {
209
262
  type: "text",
210
- text: JSON.stringify(result, null, 2),
263
+ text: JSON.stringify(formattedResult, null, 2),
211
264
  },
212
265
  ],
213
266
  };
214
267
  }
215
- case "search": {
216
- const parsedSearchArgs = SearchArgsSchema.safeParse(args);
268
+ case "shodan_search": {
269
+ const parsedSearchArgs = ShodanSearchArgsSchema.safeParse(args);
217
270
  if (!parsedSearchArgs.success) {
218
271
  throw new Error("Invalid search arguments");
219
272
  }
@@ -221,11 +274,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
221
274
  query: parsedSearchArgs.data.query,
222
275
  limit: parsedSearchArgs.data.max_results,
223
276
  });
277
+ // Format the response in a user-friendly way
278
+ const formattedResult = {
279
+ "Search Summary": {
280
+ "Query": parsedSearchArgs.data.query,
281
+ "Total Results": result.total,
282
+ "Results Returned": result.matches.length
283
+ },
284
+ "Country Distribution": result.facets?.country?.map(country => ({
285
+ "Country": country.value,
286
+ "Count": country.count,
287
+ "Percentage": `${((country.count / result.total) * 100).toFixed(2)}%`
288
+ })) || [],
289
+ "Matches": result.matches.map(match => ({
290
+ "Basic Information": {
291
+ "IP Address": match.ip_str,
292
+ "Organization": match.org,
293
+ "ISP": match.isp,
294
+ "ASN": match.asn,
295
+ "Last Update": match.timestamp
296
+ },
297
+ "Location": {
298
+ "Country": match.location.country_name,
299
+ "City": match.location.city || "Unknown",
300
+ "Region": match.location.region_code || "Unknown",
301
+ "Coordinates": `${match.location.latitude}, ${match.location.longitude}`
302
+ },
303
+ "Service Details": {
304
+ "Port": match.port,
305
+ "Transport": match.transport,
306
+ "Product": match.product || "Unknown",
307
+ "Version": match.version || "Unknown",
308
+ "CPE": match.cpe || []
309
+ },
310
+ "Web Information": match.http ? {
311
+ "Server": match.http.server,
312
+ "Title": match.http.title,
313
+ "Robots.txt": match.http.robots ? "Present" : "Not found",
314
+ "Sitemap": match.http.sitemap ? "Present" : "Not found"
315
+ } : "No HTTP information",
316
+ "Hostnames": match.hostnames,
317
+ "Domains": match.domains
318
+ }))
319
+ };
224
320
  return {
225
321
  content: [
226
322
  {
227
323
  type: "text",
228
- text: JSON.stringify(result, null, 2),
324
+ text: JSON.stringify(formattedResult, null, 2),
229
325
  },
230
326
  ],
231
327
  };
@@ -239,24 +335,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
239
335
  logToFile(`Looking up CVE: ${cveId}`);
240
336
  try {
241
337
  const result = await queryCVEDB(cveId);
338
+ // Helper function to format CVSS score severity
339
+ const getCvssSeverity = (score) => {
340
+ if (score >= 9.0)
341
+ return "Critical";
342
+ if (score >= 7.0)
343
+ return "High";
344
+ if (score >= 4.0)
345
+ return "Medium";
346
+ if (score >= 0.1)
347
+ return "Low";
348
+ return "None";
349
+ };
350
+ // Format the response in a user-friendly way
351
+ const formattedResult = {
352
+ "Basic Information": {
353
+ "CVE ID": result.cve_id,
354
+ "Published": new Date(result.published_time).toLocaleString(),
355
+ "Summary": result.summary
356
+ },
357
+ "Severity Scores": {
358
+ "CVSS v3": result.cvss_v3 ? {
359
+ "Score": result.cvss_v3,
360
+ "Severity": getCvssSeverity(result.cvss_v3)
361
+ } : "Not available",
362
+ "CVSS v2": result.cvss_v2 ? {
363
+ "Score": result.cvss_v2,
364
+ "Severity": getCvssSeverity(result.cvss_v2)
365
+ } : "Not available",
366
+ "EPSS": result.epss ? {
367
+ "Score": `${(result.epss * 100).toFixed(2)}%`,
368
+ "Ranking": `Top ${(result.ranking_epss * 100).toFixed(2)}%`
369
+ } : "Not available"
370
+ },
371
+ "Impact Assessment": {
372
+ "Known Exploited Vulnerability": result.kev ? "Yes" : "No",
373
+ "Proposed Action": result.propose_action || "No specific action proposed",
374
+ "Ransomware Campaign": result.ransomware_campaign || "No known ransomware campaigns"
375
+ },
376
+ "Affected Products": result.cpes?.length > 0 ? result.cpes : ["No specific products listed"],
377
+ "Additional Information": {
378
+ "References": result.references?.length > 0 ? result.references : ["No references provided"]
379
+ }
380
+ };
242
381
  return {
243
382
  content: [
244
383
  {
245
384
  type: "text",
246
- text: JSON.stringify({
247
- cve_id: result.cve_id,
248
- summary: result.summary,
249
- cvss_v3: result.cvss_v3,
250
- cvss_v2: result.cvss_v2,
251
- epss: result.epss,
252
- ranking_epss: result.ranking_epss,
253
- kev: result.kev,
254
- propose_action: result.propose_action,
255
- ransomware_campaign: result.ransomware_campaign,
256
- published: result.published_time,
257
- references: result.references,
258
- affected_products: result.cpes
259
- }, null, 2),
385
+ text: JSON.stringify(formattedResult, null, 2),
260
386
  },
261
387
  ],
262
388
  };
@@ -278,20 +404,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
278
404
  if (!parsedDnsArgs.success) {
279
405
  throw new Error("Invalid dns_lookup arguments");
280
406
  }
281
- // Ensure proper formatting of hostnames for the API request
407
+ // Join hostnames with commas for the API request
282
408
  const hostnamesString = parsedDnsArgs.data.hostnames.join(",");
283
- // Log the request parameters for debugging
284
- logToFile(`DNS lookup request parameters: ${JSON.stringify({ hostnames: hostnamesString })}`);
285
409
  const result = await queryShodan("/dns/resolve", {
286
410
  hostnames: hostnamesString
287
411
  });
288
- // Log the raw response for debugging
289
- logToFile(`DNS lookup raw response: ${JSON.stringify(result)}`);
412
+ // Format the response in a user-friendly way
413
+ const formattedResult = {
414
+ "DNS Resolutions": Object.entries(result).map(([hostname, ip]) => ({
415
+ "Hostname": hostname,
416
+ "IP Address": ip
417
+ })),
418
+ "Summary": {
419
+ "Total Lookups": Object.keys(result).length,
420
+ "Queried Hostnames": parsedDnsArgs.data.hostnames
421
+ }
422
+ };
290
423
  return {
291
424
  content: [
292
425
  {
293
426
  type: "text",
294
- text: JSON.stringify(result, null, 2)
427
+ text: JSON.stringify(formattedResult, null, 2)
295
428
  },
296
429
  ],
297
430
  };
@@ -355,22 +488,74 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
355
488
  start_date: parsedArgs.data.start_date,
356
489
  end_date: parsedArgs.data.end_date
357
490
  });
491
+ // Helper function to format CVSS score severity
492
+ const getCvssSeverity = (score) => {
493
+ if (score >= 9.0)
494
+ return "Critical";
495
+ if (score >= 7.0)
496
+ return "High";
497
+ if (score >= 4.0)
498
+ return "Medium";
499
+ if (score >= 0.1)
500
+ return "Low";
501
+ return "None";
502
+ };
358
503
  // Format the response based on whether it's a count request or full CVE list
359
504
  const formattedResult = parsedArgs.data.count
360
- ? { total_cves: result.total }
361
- : {
362
- cves: result.cves,
363
- skip: parsedArgs.data.skip,
364
- limit: parsedArgs.data.limit,
365
- total_returned: result.cves.length,
366
- query_params: {
367
- cpe23: parsedArgs.data.cpe23,
368
- product: parsedArgs.data.product,
369
- is_kev: parsedArgs.data.is_kev,
370
- sort_by_epss: parsedArgs.data.sort_by_epss,
371
- start_date: parsedArgs.data.start_date,
372
- end_date: parsedArgs.data.end_date
505
+ ? {
506
+ "Query Information": {
507
+ "Product": parsedArgs.data.product || "N/A",
508
+ "CPE 2.3": parsedArgs.data.cpe23 || "N/A",
509
+ "KEV Only": parsedArgs.data.is_kev ? "Yes" : "No",
510
+ "Sort by EPSS": parsedArgs.data.sort_by_epss ? "Yes" : "No"
511
+ },
512
+ "Results": {
513
+ "Total CVEs Found": result.total
373
514
  }
515
+ }
516
+ : {
517
+ "Query Information": {
518
+ "Product": parsedArgs.data.product || "N/A",
519
+ "CPE 2.3": parsedArgs.data.cpe23 || "N/A",
520
+ "KEV Only": parsedArgs.data.is_kev ? "Yes" : "No",
521
+ "Sort by EPSS": parsedArgs.data.sort_by_epss ? "Yes" : "No",
522
+ "Date Range": parsedArgs.data.start_date ?
523
+ `${parsedArgs.data.start_date} to ${parsedArgs.data.end_date || 'now'}` :
524
+ "All dates"
525
+ },
526
+ "Results Summary": {
527
+ "Total CVEs Found": result.total,
528
+ "CVEs Returned": result.cves.length,
529
+ "Page": `${Math.floor(parsedArgs.data.skip / parsedArgs.data.limit) + 1}`,
530
+ "CVEs per Page": parsedArgs.data.limit
531
+ },
532
+ "Vulnerabilities": result.cves.map((cve) => ({
533
+ "Basic Information": {
534
+ "CVE ID": cve.cve_id,
535
+ "Published": new Date(cve.published_time).toLocaleString(),
536
+ "Summary": cve.summary
537
+ },
538
+ "Severity Scores": {
539
+ "CVSS v3": cve.cvss_v3 ? {
540
+ "Score": cve.cvss_v3,
541
+ "Severity": getCvssSeverity(cve.cvss_v3)
542
+ } : "Not available",
543
+ "CVSS v2": cve.cvss_v2 ? {
544
+ "Score": cve.cvss_v2,
545
+ "Severity": getCvssSeverity(cve.cvss_v2)
546
+ } : "Not available",
547
+ "EPSS": cve.epss ? {
548
+ "Score": `${(cve.epss * 100).toFixed(2)}%`,
549
+ "Ranking": `Top ${(cve.ranking_epss * 100).toFixed(2)}%`
550
+ } : "Not available"
551
+ },
552
+ "Impact Assessment": {
553
+ "Known Exploited Vulnerability": cve.kev ? "Yes" : "No",
554
+ "Proposed Action": cve.propose_action || "No specific action proposed",
555
+ "Ransomware Campaign": cve.ransomware_campaign || "No known ransomware campaigns"
556
+ },
557
+ "References": cve.references?.length > 0 ? cve.references : ["No references provided"]
558
+ }))
374
559
  };
375
560
  return {
376
561
  content: [
@@ -393,6 +578,37 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
393
578
  };
394
579
  }
395
580
  }
581
+ case "reverse_dns_lookup": {
582
+ const parsedArgs = ReverseDnsLookupArgsSchema.safeParse(args);
583
+ if (!parsedArgs.success) {
584
+ throw new Error("Invalid reverse_dns_lookup arguments");
585
+ }
586
+ // Join IPs with commas for the API request
587
+ const ipsString = parsedArgs.data.ips.join(",");
588
+ const result = await queryShodan("/dns/reverse", {
589
+ ips: ipsString
590
+ });
591
+ // Format the response in a user-friendly way
592
+ const formattedResult = {
593
+ "Reverse DNS Resolutions": Object.entries(result).map(([ip, hostnames]) => ({
594
+ "IP Address": ip,
595
+ "Hostnames": hostnames.length > 0 ? hostnames : ["No hostnames found"]
596
+ })),
597
+ "Summary": {
598
+ "Total IPs Queried": parsedArgs.data.ips.length,
599
+ "IPs with Results": Object.keys(result).length,
600
+ "Queried IP Addresses": parsedArgs.data.ips
601
+ }
602
+ };
603
+ return {
604
+ content: [
605
+ {
606
+ type: "text",
607
+ text: JSON.stringify(formattedResult, null, 2)
608
+ },
609
+ ],
610
+ };
611
+ }
396
612
  default:
397
613
  throw new Error(`Unknown tool: ${name}`);
398
614
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@burtthecoder/mcp-shodan",
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "description": "A Model Context Protocol server for Shodan API queries.",
6
6
  "main": "build/index.js",
7
7
  "bin": {