@burtthecoder/mcp-shodan 1.0.11 → 1.0.13
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.
- package/README.md +101 -39
- package/build/index.js +264 -47
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
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
4
|
|
|
5
5
|
## Quick Start (Recommended)
|
|
6
6
|
|
|
@@ -58,45 +58,78 @@ npm run build
|
|
|
58
58
|
|
|
59
59
|
## Features
|
|
60
60
|
|
|
61
|
-
- **
|
|
62
|
-
- **
|
|
63
|
-
- **
|
|
64
|
-
- **
|
|
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
|
|
61
|
+
- **Network Reconnaissance**: Query detailed information about IP addresses, including open ports, services, and vulnerabilities
|
|
62
|
+
- **DNS Operations**: Forward and reverse DNS lookups for domains and IP addresses
|
|
63
|
+
- **Vulnerability Intelligence**: Access to Shodan's CVEDB for detailed vulnerability information, CPE lookups, and product-specific CVE tracking
|
|
64
|
+
- **Device Discovery**: Search Shodan's database of internet-connected devices with advanced filtering
|
|
68
65
|
|
|
69
66
|
## Tools
|
|
70
67
|
|
|
71
68
|
### 1. IP Lookup Tool
|
|
72
69
|
- Name: `ip_lookup`
|
|
73
|
-
- Description: Retrieve
|
|
70
|
+
- Description: Retrieve comprehensive information about an IP address, including geolocation, open ports, running services, SSL certificates, hostnames, and cloud provider details if available
|
|
74
71
|
- Parameters:
|
|
75
72
|
* `ip` (required): IP address to lookup
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
- Returns:
|
|
74
|
+
* IP Information (address, organization, ISP, ASN)
|
|
75
|
+
* Location (country, city, coordinates)
|
|
76
|
+
* Services (ports, protocols, banners)
|
|
77
|
+
* Cloud Provider details (if available)
|
|
78
|
+
* Associated hostnames and domains
|
|
79
|
+
* Tags
|
|
80
|
+
|
|
81
|
+
### 2. Shodan Search Tool
|
|
82
|
+
- Name: `shodan_search`
|
|
83
|
+
- Description: Search Shodan's database of internet-connected devices
|
|
80
84
|
- Parameters:
|
|
81
85
|
* `query` (required): Shodan search query
|
|
82
86
|
* `max_results` (optional, default: 10): Number of results to return
|
|
87
|
+
- Returns:
|
|
88
|
+
* Search summary with total results
|
|
89
|
+
* Country-based distribution statistics
|
|
90
|
+
* Detailed device information including:
|
|
91
|
+
- Basic information (IP, organization, ISP)
|
|
92
|
+
- Location data
|
|
93
|
+
- Service details
|
|
94
|
+
- Web server information
|
|
95
|
+
- Associated hostnames and domains
|
|
83
96
|
|
|
84
97
|
### 3. CVE Lookup Tool
|
|
85
98
|
- Name: `cve_lookup`
|
|
86
|
-
- Description:
|
|
99
|
+
- Description: Query detailed vulnerability information from Shodan's CVEDB
|
|
87
100
|
- Parameters:
|
|
88
101
|
* `cve` (required): CVE identifier in format CVE-YYYY-NNNNN (e.g., CVE-2021-44228)
|
|
89
102
|
- Returns:
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
-
|
|
103
|
+
* Basic Information (ID, published date, summary)
|
|
104
|
+
* Severity Scores:
|
|
105
|
+
- CVSS v2 and v3 with severity levels
|
|
106
|
+
- EPSS probability and ranking
|
|
107
|
+
* Impact Assessment:
|
|
93
108
|
- KEV status
|
|
94
|
-
- Proposed
|
|
95
|
-
- Ransomware
|
|
96
|
-
|
|
97
|
-
|
|
109
|
+
- Proposed mitigations
|
|
110
|
+
- Ransomware associations
|
|
111
|
+
* Affected products (CPEs)
|
|
112
|
+
* References
|
|
113
|
+
|
|
114
|
+
### 4. DNS Lookup Tool
|
|
115
|
+
- Name: `dns_lookup`
|
|
116
|
+
- Description: Resolve domain names to IP addresses using Shodan's DNS service
|
|
117
|
+
- Parameters:
|
|
118
|
+
* `hostnames` (required): Array of hostnames to resolve
|
|
119
|
+
- Returns:
|
|
120
|
+
* DNS resolutions mapping hostnames to IPs
|
|
121
|
+
* Summary of total lookups and queried hostnames
|
|
98
122
|
|
|
99
|
-
###
|
|
123
|
+
### 5. Reverse DNS Lookup Tool
|
|
124
|
+
- Name: `reverse_dns_lookup`
|
|
125
|
+
- Description: Perform reverse DNS lookups to find hostnames associated with IP addresses
|
|
126
|
+
- Parameters:
|
|
127
|
+
* `ips` (required): Array of IP addresses to lookup
|
|
128
|
+
- Returns:
|
|
129
|
+
* Reverse DNS resolutions mapping IPs to hostnames
|
|
130
|
+
* Summary of total lookups and results
|
|
131
|
+
|
|
132
|
+
### 6. CPE Lookup Tool
|
|
100
133
|
- Name: `cpe_lookup`
|
|
101
134
|
- Description: Search for Common Platform Enumeration (CPE) entries by product name
|
|
102
135
|
- Parameters:
|
|
@@ -108,9 +141,9 @@ npm run build
|
|
|
108
141
|
* When count is true: Total number of matching CPEs
|
|
109
142
|
* When count is false: List of CPEs with pagination details
|
|
110
143
|
|
|
111
|
-
###
|
|
144
|
+
### 7. CVEs by Product Tool
|
|
112
145
|
- Name: `cves_by_product`
|
|
113
|
-
- Description: Search for
|
|
146
|
+
- Description: Search for vulnerabilities affecting specific products or CPEs
|
|
114
147
|
- Parameters:
|
|
115
148
|
* `cpe23` (optional): CPE 2.3 identifier (format: cpe:2.3:part:vendor:product:version)
|
|
116
149
|
* `product` (optional): Name of the product to search for CVEs
|
|
@@ -125,14 +158,13 @@ npm run build
|
|
|
125
158
|
* Must provide either cpe23 or product, but not both
|
|
126
159
|
* Date filtering uses published time of CVEs
|
|
127
160
|
- Returns:
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
* `hostnames` (required): Array of hostnames to resolve
|
|
161
|
+
* Query information
|
|
162
|
+
* Results summary with pagination details
|
|
163
|
+
* Detailed vulnerability information including:
|
|
164
|
+
- Basic information
|
|
165
|
+
- Severity scores
|
|
166
|
+
- Impact assessments
|
|
167
|
+
- References
|
|
136
168
|
|
|
137
169
|
## Requirements
|
|
138
170
|
|
|
@@ -143,15 +175,44 @@ npm run build
|
|
|
143
175
|
|
|
144
176
|
### API Key Issues
|
|
145
177
|
|
|
146
|
-
If you see API key related errors:
|
|
178
|
+
If you see API key related errors (e.g., "Request failed with status code 401"):
|
|
147
179
|
|
|
148
180
|
1. Verify your API key:
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
181
|
+
- Must be a valid Shodan API key from your [account settings](https://account.shodan.io/)
|
|
182
|
+
- Ensure the key has sufficient credits/permissions for the operation
|
|
183
|
+
- Check for extra spaces or quotes around the key in the configuration
|
|
184
|
+
- Verify the key is correctly set in the SHODAN_API_KEY environment variable
|
|
185
|
+
|
|
186
|
+
2. Common Error Codes:
|
|
187
|
+
- 401 Unauthorized: Invalid API key or missing authentication
|
|
188
|
+
- 402 Payment Required: Out of query credits
|
|
189
|
+
- 429 Too Many Requests: Rate limit exceeded
|
|
190
|
+
|
|
191
|
+
3. Configuration Steps:
|
|
192
|
+
a. Get your API key from [Shodan Account](https://account.shodan.io/)
|
|
193
|
+
b. Add it to your configuration file:
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"mcpServers": {
|
|
197
|
+
"shodan": {
|
|
198
|
+
"command": "mcp-shodan",
|
|
199
|
+
"env": {
|
|
200
|
+
"SHODAN_API_KEY": "your-actual-api-key-here"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
c. Save the config file
|
|
207
|
+
d. Restart Claude Desktop
|
|
208
|
+
|
|
209
|
+
4. Testing Your Key:
|
|
210
|
+
- Try a simple query first (e.g., dns_lookup for "google.com")
|
|
211
|
+
- Check your [Shodan account dashboard](https://account.shodan.io/) for credit status
|
|
212
|
+
- Verify the key works directly with curl:
|
|
213
|
+
```bash
|
|
214
|
+
curl "https://api.shodan.io/dns/resolve?hostnames=google.com&key=your-api-key"
|
|
215
|
+
```
|
|
155
216
|
|
|
156
217
|
### Module Loading Issues
|
|
157
218
|
|
|
@@ -180,6 +241,7 @@ The server includes comprehensive error handling for:
|
|
|
180
241
|
|
|
181
242
|
## Version History
|
|
182
243
|
|
|
244
|
+
- v1.0.12: Added reverse DNS lookup and improved output formatting
|
|
183
245
|
- v1.0.7: Added CVEs by Product search functionality and renamed vulnerabilities tool to cve_lookup
|
|
184
246
|
- v1.0.6: Added CVEDB integration for enhanced CVE lookups and CPE search functionality
|
|
185
247
|
- v1.0.0: Initial release with core functionality
|
package/build/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, InitializeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -32,7 +33,7 @@ function logToFile(message) {
|
|
|
32
33
|
const IpLookupArgsSchema = z.object({
|
|
33
34
|
ip: z.string().describe("The IP address to query."),
|
|
34
35
|
});
|
|
35
|
-
const
|
|
36
|
+
const ShodanSearchArgsSchema = z.object({
|
|
36
37
|
query: z.string().describe("Search query for Shodan."),
|
|
37
38
|
max_results: z
|
|
38
39
|
.number()
|
|
@@ -48,6 +49,9 @@ const CVELookupArgsSchema = z.object({
|
|
|
48
49
|
const DnsLookupArgsSchema = z.object({
|
|
49
50
|
hostnames: z.array(z.string()).describe("List of hostnames to resolve."),
|
|
50
51
|
});
|
|
52
|
+
const ReverseDnsLookupArgsSchema = z.object({
|
|
53
|
+
ips: z.array(z.string()).describe("List of IP addresses to perform reverse DNS lookup on."),
|
|
54
|
+
});
|
|
51
55
|
const CpeLookupArgsSchema = z.object({
|
|
52
56
|
product: z.string().describe("The name of the product to search for CPEs."),
|
|
53
57
|
count: z.boolean().optional().default(false).describe("If true, returns only the count of matching CPEs."),
|
|
@@ -150,7 +154,14 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
|
|
|
150
154
|
name: "shodan-mcp",
|
|
151
155
|
version: "1.0.0",
|
|
152
156
|
},
|
|
153
|
-
instructions:
|
|
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.`,
|
|
154
165
|
};
|
|
155
166
|
});
|
|
156
167
|
// Register Tools
|
|
@@ -158,34 +169,39 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
158
169
|
const tools = [
|
|
159
170
|
{
|
|
160
171
|
name: "ip_lookup",
|
|
161
|
-
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.",
|
|
162
173
|
inputSchema: zodToJsonSchema(IpLookupArgsSchema),
|
|
163
174
|
},
|
|
164
175
|
{
|
|
165
|
-
name: "
|
|
166
|
-
description: "Search
|
|
167
|
-
inputSchema: zodToJsonSchema(
|
|
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),
|
|
168
179
|
},
|
|
169
180
|
{
|
|
170
181
|
name: "cve_lookup",
|
|
171
|
-
description: "
|
|
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).",
|
|
172
183
|
inputSchema: zodToJsonSchema(CVELookupArgsSchema),
|
|
173
184
|
},
|
|
174
185
|
{
|
|
175
186
|
name: "dns_lookup",
|
|
176
|
-
description: "
|
|
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.",
|
|
177
188
|
inputSchema: zodToJsonSchema(DnsLookupArgsSchema),
|
|
178
189
|
},
|
|
179
190
|
{
|
|
180
191
|
name: "cpe_lookup",
|
|
181
|
-
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.",
|
|
182
193
|
inputSchema: zodToJsonSchema(CpeLookupArgsSchema),
|
|
183
194
|
},
|
|
184
195
|
{
|
|
185
196
|
name: "cves_by_product",
|
|
186
|
-
description: "Search for
|
|
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.",
|
|
187
198
|
inputSchema: zodToJsonSchema(CVEsByProductArgsSchema),
|
|
188
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
|
+
},
|
|
189
205
|
];
|
|
190
206
|
logToFile("Registered tools.");
|
|
191
207
|
return { tools };
|
|
@@ -202,17 +218,55 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
202
218
|
throw new Error("Invalid ip_lookup arguments");
|
|
203
219
|
}
|
|
204
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
|
+
};
|
|
205
259
|
return {
|
|
206
260
|
content: [
|
|
207
261
|
{
|
|
208
262
|
type: "text",
|
|
209
|
-
text: JSON.stringify(
|
|
263
|
+
text: JSON.stringify(formattedResult, null, 2),
|
|
210
264
|
},
|
|
211
265
|
],
|
|
212
266
|
};
|
|
213
267
|
}
|
|
214
|
-
case "
|
|
215
|
-
const parsedSearchArgs =
|
|
268
|
+
case "shodan_search": {
|
|
269
|
+
const parsedSearchArgs = ShodanSearchArgsSchema.safeParse(args);
|
|
216
270
|
if (!parsedSearchArgs.success) {
|
|
217
271
|
throw new Error("Invalid search arguments");
|
|
218
272
|
}
|
|
@@ -220,11 +274,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
220
274
|
query: parsedSearchArgs.data.query,
|
|
221
275
|
limit: parsedSearchArgs.data.max_results,
|
|
222
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
|
+
};
|
|
223
320
|
return {
|
|
224
321
|
content: [
|
|
225
322
|
{
|
|
226
323
|
type: "text",
|
|
227
|
-
text: JSON.stringify(
|
|
324
|
+
text: JSON.stringify(formattedResult, null, 2),
|
|
228
325
|
},
|
|
229
326
|
],
|
|
230
327
|
};
|
|
@@ -238,24 +335,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
238
335
|
logToFile(`Looking up CVE: ${cveId}`);
|
|
239
336
|
try {
|
|
240
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
|
+
};
|
|
241
381
|
return {
|
|
242
382
|
content: [
|
|
243
383
|
{
|
|
244
384
|
type: "text",
|
|
245
|
-
text: JSON.stringify(
|
|
246
|
-
cve_id: result.cve_id,
|
|
247
|
-
summary: result.summary,
|
|
248
|
-
cvss_v3: result.cvss_v3,
|
|
249
|
-
cvss_v2: result.cvss_v2,
|
|
250
|
-
epss: result.epss,
|
|
251
|
-
ranking_epss: result.ranking_epss,
|
|
252
|
-
kev: result.kev,
|
|
253
|
-
propose_action: result.propose_action,
|
|
254
|
-
ransomware_campaign: result.ransomware_campaign,
|
|
255
|
-
published: result.published_time,
|
|
256
|
-
references: result.references,
|
|
257
|
-
affected_products: result.cpes
|
|
258
|
-
}, null, 2),
|
|
385
|
+
text: JSON.stringify(formattedResult, null, 2),
|
|
259
386
|
},
|
|
260
387
|
],
|
|
261
388
|
};
|
|
@@ -277,20 +404,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
277
404
|
if (!parsedDnsArgs.success) {
|
|
278
405
|
throw new Error("Invalid dns_lookup arguments");
|
|
279
406
|
}
|
|
280
|
-
//
|
|
407
|
+
// Join hostnames with commas for the API request
|
|
281
408
|
const hostnamesString = parsedDnsArgs.data.hostnames.join(",");
|
|
282
|
-
// Log the request parameters for debugging
|
|
283
|
-
logToFile(`DNS lookup request parameters: ${JSON.stringify({ hostnames: hostnamesString })}`);
|
|
284
409
|
const result = await queryShodan("/dns/resolve", {
|
|
285
410
|
hostnames: hostnamesString
|
|
286
411
|
});
|
|
287
|
-
//
|
|
288
|
-
|
|
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
|
+
};
|
|
289
423
|
return {
|
|
290
424
|
content: [
|
|
291
425
|
{
|
|
292
426
|
type: "text",
|
|
293
|
-
text: JSON.stringify(
|
|
427
|
+
text: JSON.stringify(formattedResult, null, 2)
|
|
294
428
|
},
|
|
295
429
|
],
|
|
296
430
|
};
|
|
@@ -354,22 +488,74 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
354
488
|
start_date: parsedArgs.data.start_date,
|
|
355
489
|
end_date: parsedArgs.data.end_date
|
|
356
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
|
+
};
|
|
357
503
|
// Format the response based on whether it's a count request or full CVE list
|
|
358
504
|
const formattedResult = parsedArgs.data.count
|
|
359
|
-
? {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
is_kev: parsedArgs.data.is_kev,
|
|
369
|
-
sort_by_epss: parsedArgs.data.sort_by_epss,
|
|
370
|
-
start_date: parsedArgs.data.start_date,
|
|
371
|
-
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
|
|
372
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
|
+
}))
|
|
373
559
|
};
|
|
374
560
|
return {
|
|
375
561
|
content: [
|
|
@@ -392,6 +578,37 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
392
578
|
};
|
|
393
579
|
}
|
|
394
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
|
+
}
|
|
395
612
|
default:
|
|
396
613
|
throw new Error(`Unknown tool: ${name}`);
|
|
397
614
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@burtthecoder/mcp-shodan",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.13",
|
|
5
5
|
"description": "A Model Context Protocol server for Shodan API queries.",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"mcp-shodan": "build/index.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsc &&
|
|
11
|
+
"build": "tsc && chmod +x build/index.js",
|
|
12
12
|
"prepublishOnly": "npm run build"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|