@burtthecoder/mcp-shodan 1.0.7 → 1.0.8

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 CHANGED
@@ -7,8 +7,9 @@ A Model Context Protocol (MCP) server for querying the [Shodan API](https://shod
7
7
  - **IP Lookup**: Retrieve detailed information about an IP address
8
8
  - **Search**: Search for devices on Shodan matching specific queries
9
9
  - **Ports**: Get a list of ports that Shodan is scanning
10
- - **Vulnerabilities**: Fetch detailed information about CVEs using Shodan's CVEDB
10
+ - **CVE Lookup**: Fetch detailed information about specific CVEs using Shodan's CVEDB
11
11
  - **CPE Lookup**: Search for Common Platform Enumeration (CPE) entries by product name
12
+ - **CVEs by Product**: Search for all CVEs affecting a specific product or CPE
12
13
  - **DNS Lookup**: Resolve hostnames to IP addresses
13
14
 
14
15
  ## Tools
@@ -26,8 +27,8 @@ A Model Context Protocol (MCP) server for querying the [Shodan API](https://shod
26
27
  * `query` (required): Shodan search query
27
28
  * `max_results` (optional, default: 10): Number of results to return
28
29
 
29
- ### 3. Vulnerabilities Tool
30
- - Name: `vulnerabilities`
30
+ ### 3. CVE Lookup Tool
31
+ - Name: `cve_lookup`
31
32
  - Description: Fetch detailed information about CVEs using Shodan's CVEDB
32
33
  - Parameters:
33
34
  * `cve` (required): CVE identifier in format CVE-YYYY-NNNNN (e.g., CVE-2021-44228)
@@ -53,7 +54,27 @@ A Model Context Protocol (MCP) server for querying the [Shodan API](https://shod
53
54
  * When count is true: Total number of matching CPEs
54
55
  * When count is false: List of CPEs with pagination details
55
56
 
56
- ### 5. DNS Lookup Tool
57
+ ### 5. CVEs by Product Tool
58
+ - Name: `cves_by_product`
59
+ - Description: Search for CVEs affecting a specific product or CPE
60
+ - Parameters:
61
+ * `cpe23` (optional): CPE 2.3 identifier (format: cpe:2.3:part:vendor:product:version)
62
+ * `product` (optional): Name of the product to search for CVEs
63
+ * `count` (optional, default: false): If true, returns only the count of matching CVEs
64
+ * `is_kev` (optional, default: false): If true, returns only CVEs with KEV flag set
65
+ * `sort_by_epss` (optional, default: false): If true, sorts CVEs by EPSS score
66
+ * `skip` (optional, default: 0): Number of CVEs to skip (for pagination)
67
+ * `limit` (optional, default: 1000): Maximum number of CVEs to return
68
+ * `start_date` (optional): Start date for filtering CVEs (format: YYYY-MM-DDTHH:MM:SS)
69
+ * `end_date` (optional): End date for filtering CVEs (format: YYYY-MM-DDTHH:MM:SS)
70
+ - Notes:
71
+ * Must provide either cpe23 or product, but not both
72
+ * Date filtering uses published time of CVEs
73
+ - Returns:
74
+ * When count is true: Total number of matching CVEs
75
+ * When count is false: List of CVEs with pagination details and query parameters
76
+
77
+ ### 6. DNS Lookup Tool
57
78
  - Name: `dns_lookup`
58
79
  - Description: Resolve hostnames to IP addresses
59
80
  - Parameters:
@@ -157,9 +178,12 @@ The server includes comprehensive error handling for:
157
178
  - Invalid input parameters
158
179
  - Invalid CVE formats
159
180
  - Invalid CPE lookup parameters
181
+ - Invalid date formats
182
+ - Mutually exclusive parameter validation
160
183
 
161
184
  ## Version History
162
185
 
186
+ - v1.0.7: Added CVEs by Product search functionality and renamed vulnerabilities tool to cve_lookup
163
187
  - v1.0.6: Added CVEDB integration for enhanced CVE lookups and CPE search functionality
164
188
  - v1.0.0: Initial release with core functionality
165
189
 
package/build/index.js CHANGED
@@ -41,7 +41,7 @@ const SearchArgsSchema = z.object({
41
41
  .default(10)
42
42
  .describe("Maximum results to return."),
43
43
  });
44
- const VulnerabilitiesArgsSchema = z.object({
44
+ const CVELookupArgsSchema = z.object({
45
45
  cve: z.string()
46
46
  .regex(/^CVE-\d{4}-\d{4,}$/i, "Must be a valid CVE ID format (e.g., CVE-2021-44228)")
47
47
  .describe("The CVE identifier to query (format: CVE-YYYY-NNNNN)."),
@@ -55,6 +55,17 @@ const CpeLookupArgsSchema = z.object({
55
55
  skip: z.number().optional().default(0).describe("Number of CPEs to skip (for pagination)."),
56
56
  limit: z.number().optional().default(1000).describe("Maximum number of CPEs to return (max 1000)."),
57
57
  });
58
+ const CVEsByProductArgsSchema = z.object({
59
+ cpe23: z.string().optional().describe("The CPE version 2.3 identifier (format: cpe:2.3:part:vendor:product:version)."),
60
+ product: z.string().optional().describe("The name of the product to search for CVEs."),
61
+ count: z.boolean().optional().default(false).describe("If true, returns only the count of matching CVEs."),
62
+ is_kev: z.boolean().optional().default(false).describe("If true, returns only CVEs with the KEV flag set."),
63
+ sort_by_epss: z.boolean().optional().default(false).describe("If true, sorts CVEs by EPSS score in descending order."),
64
+ skip: z.number().optional().default(0).describe("Number of CVEs to skip (for pagination)."),
65
+ limit: z.number().optional().default(1000).describe("Maximum number of CVEs to return (max 1000)."),
66
+ start_date: z.string().optional().describe("Start date for filtering CVEs (format: YYYY-MM-DDTHH:MM:SS)."),
67
+ end_date: z.string().optional().describe("End date for filtering CVEs (format: YYYY-MM-DDTHH:MM:SS).")
68
+ }).refine(data => !(data.cpe23 && data.product), { message: "Cannot specify both cpe23 and product. Use only one." }).refine(data => data.cpe23 || data.product, { message: "Must specify either cpe23 or product." });
58
69
  // Helper Function to Query Shodan API
59
70
  async function queryShodan(endpoint, params) {
60
71
  try {
@@ -101,6 +112,20 @@ async function queryCPEDB(params) {
101
112
  throw new Error(`CVEDB API error: ${error.message}`);
102
113
  }
103
114
  }
115
+ // Helper Function for CVEs by product/CPE lookups using CVEDB
116
+ async function queryCVEsByProduct(params) {
117
+ try {
118
+ logToFile(`Querying CVEDB for CVEs with params: ${JSON.stringify(params)}`);
119
+ const response = await axios.get(`${CVEDB_API_URL}/cves`, { params });
120
+ return response.data;
121
+ }
122
+ catch (error) {
123
+ if (error.response?.status === 422) {
124
+ throw new Error(`Invalid parameters: ${error.response.data?.detail || error.message}`);
125
+ }
126
+ throw new Error(`CVEDB API error: ${error.message}`);
127
+ }
128
+ }
104
129
  // Server Setup
105
130
  const server = new Server({
106
131
  name: "shodan-mcp",
@@ -126,7 +151,7 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
126
151
  name: "shodan-mcp",
127
152
  version: "1.0.0",
128
153
  },
129
- instructions: "This server provides tools for querying Shodan, including IP lookups, searches, vulnerabilities, and CPE lookups.",
154
+ instructions: "This server provides tools for querying Shodan, including IP lookups, searches, CVE lookups, CPE lookups, and CVE searches by product/CPE.",
130
155
  };
131
156
  });
132
157
  // Register Tools
@@ -143,9 +168,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
143
168
  inputSchema: zodToJsonSchema(SearchArgsSchema),
144
169
  },
145
170
  {
146
- name: "vulnerabilities",
171
+ name: "cve_lookup",
147
172
  description: "Retrieve vulnerability information for a CVE. Use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)",
148
- inputSchema: zodToJsonSchema(VulnerabilitiesArgsSchema),
173
+ inputSchema: zodToJsonSchema(CVELookupArgsSchema),
149
174
  },
150
175
  {
151
176
  name: "dns_lookup",
@@ -157,6 +182,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
157
182
  description: "Search for Common Platform Enumeration (CPE) entries by product name.",
158
183
  inputSchema: zodToJsonSchema(CpeLookupArgsSchema),
159
184
  },
185
+ {
186
+ name: "cves_by_product",
187
+ description: "Search for CVEs affecting a specific product or CPE. Provide either product name or CPE 2.3 identifier.",
188
+ inputSchema: zodToJsonSchema(CVEsByProductArgsSchema),
189
+ },
160
190
  ];
161
191
  logToFile("Registered tools.");
162
192
  return { tools };
@@ -200,12 +230,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
200
230
  ],
201
231
  };
202
232
  }
203
- case "vulnerabilities": {
204
- const parsedVulnArgs = VulnerabilitiesArgsSchema.safeParse(args);
205
- if (!parsedVulnArgs.success) {
233
+ case "cve_lookup": {
234
+ const parsedCveArgs = CVELookupArgsSchema.safeParse(args);
235
+ if (!parsedCveArgs.success) {
206
236
  throw new Error("Invalid CVE format. Please use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)");
207
237
  }
208
- const cveId = parsedVulnArgs.data.cve.toUpperCase();
238
+ const cveId = parsedCveArgs.data.cve.toUpperCase();
209
239
  logToFile(`Looking up CVE: ${cveId}`);
210
240
  try {
211
241
  const result = await queryCVEDB(cveId);
@@ -308,6 +338,61 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
308
338
  };
309
339
  }
310
340
  }
341
+ case "cves_by_product": {
342
+ const parsedArgs = CVEsByProductArgsSchema.safeParse(args);
343
+ if (!parsedArgs.success) {
344
+ throw new Error("Invalid arguments. Must provide either cpe23 or product name, but not both.");
345
+ }
346
+ try {
347
+ const result = await queryCVEsByProduct({
348
+ cpe23: parsedArgs.data.cpe23,
349
+ product: parsedArgs.data.product,
350
+ count: parsedArgs.data.count,
351
+ is_kev: parsedArgs.data.is_kev,
352
+ sort_by_epss: parsedArgs.data.sort_by_epss,
353
+ skip: parsedArgs.data.skip,
354
+ limit: parsedArgs.data.limit,
355
+ start_date: parsedArgs.data.start_date,
356
+ end_date: parsedArgs.data.end_date
357
+ });
358
+ // Format the response based on whether it's a count request or full CVE list
359
+ 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
373
+ }
374
+ };
375
+ return {
376
+ content: [
377
+ {
378
+ type: "text",
379
+ text: JSON.stringify(formattedResult, null, 2),
380
+ },
381
+ ],
382
+ };
383
+ }
384
+ catch (error) {
385
+ return {
386
+ content: [
387
+ {
388
+ type: "text",
389
+ text: error.message,
390
+ },
391
+ ],
392
+ isError: true,
393
+ };
394
+ }
395
+ }
311
396
  default:
312
397
  throw new Error(`Unknown tool: ${name}`);
313
398
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@burtthecoder/mcp-shodan",
4
- "version": "1.0.7",
4
+ "version": "1.0.8",
5
5
  "description": "A Model Context Protocol server for Shodan API queries.",
6
6
  "main": "./build/index.js",
7
7
  "bin": {