@burtthecoder/mcp-shodan 1.0.5 → 1.0.7

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 +35 -10
  2. package/build/index.js +128 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # Shodan MCP Server
2
2
 
3
- A Model Context Protocol (MCP) server for querying the [Shodan API](https://shodan.io). This server provides tools for IP lookups, device searches, DNS lookups, vulnerability queries, 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 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).
4
4
 
5
5
  ## Features
6
6
 
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 information about known vulnerabilities (CVE)
10
+ - **Vulnerabilities**: Fetch detailed information about CVEs using Shodan's CVEDB
11
+ - **CPE Lookup**: Search for Common Platform Enumeration (CPE) entries by product name
11
12
  - **DNS Lookup**: Resolve hostnames to IP addresses
12
13
 
13
14
  ## Tools
@@ -27,11 +28,32 @@ A Model Context Protocol (MCP) server for querying the [Shodan API](https://shod
27
28
 
28
29
  ### 3. Vulnerabilities Tool
29
30
  - Name: `vulnerabilities`
30
- - Description: Fetch information about known vulnerabilities
31
+ - Description: Fetch detailed information about CVEs using Shodan's CVEDB
31
32
  - Parameters:
32
- * `cve` (required): CVE identifier
33
-
34
- ### 4. DNS Lookup Tool
33
+ * `cve` (required): CVE identifier in format CVE-YYYY-NNNNN (e.g., CVE-2021-44228)
34
+ - Returns:
35
+ * CVE details including:
36
+ - CVSS v2 and v3 scores
37
+ - EPSS score and ranking
38
+ - KEV status
39
+ - Proposed action
40
+ - Ransomware campaign information
41
+ - Affected products (CPEs)
42
+ - References
43
+
44
+ ### 4. CPE Lookup Tool
45
+ - Name: `cpe_lookup`
46
+ - Description: Search for Common Platform Enumeration (CPE) entries by product name
47
+ - Parameters:
48
+ * `product` (required): Name of the product to search for
49
+ * `count` (optional, default: false): If true, returns only the count of matching CPEs
50
+ * `skip` (optional, default: 0): Number of CPEs to skip (for pagination)
51
+ * `limit` (optional, default: 1000): Maximum number of CPEs to return
52
+ - Returns:
53
+ * When count is true: Total number of matching CPEs
54
+ * When count is false: List of CPEs with pagination details
55
+
56
+ ### 5. DNS Lookup Tool
35
57
  - Name: `dns_lookup`
36
58
  - Description: Resolve hostnames to IP addresses
37
59
  - Parameters:
@@ -91,8 +113,8 @@ There are two ways to configure the Shodan MCP server in Claude Desktop:
91
113
  {
92
114
  "mcpServers": {
93
115
  "shodan-mcp": {
94
- "command": "npx",
95
- "args": ["@burtthecoder/mcp-shodan"],
116
+ "command": "npm",
117
+ "args": ["exec", "@burtthecoder/mcp-shodan"],
96
118
  "env": {
97
119
  "SHODAN_API_KEY": "your_shodan_api_key",
98
120
  "DEBUG": "*"
@@ -102,7 +124,7 @@ There are two ways to configure the Shodan MCP server in Claude Desktop:
102
124
  }
103
125
  ```
104
126
 
105
- The npx method automatically downloads and runs the latest version of the package from npm.
127
+ The npm exec method automatically downloads and runs the latest version of the package from npm.
106
128
 
107
129
  Configuration file location:
108
130
 
@@ -133,9 +155,12 @@ The server includes comprehensive error handling for:
133
155
  - Rate limiting
134
156
  - Network errors
135
157
  - Invalid input parameters
158
+ - Invalid CVE formats
159
+ - Invalid CPE lookup parameters
136
160
 
137
161
  ## Version History
138
162
 
163
+ - v1.0.6: Added CVEDB integration for enhanced CVE lookups and CPE search functionality
139
164
  - v1.0.0: Initial release with core functionality
140
165
 
141
166
  ## Contributing
@@ -148,4 +173,4 @@ The server includes comprehensive error handling for:
148
173
 
149
174
  ## License
150
175
 
151
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
176
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/build/index.js CHANGED
@@ -10,13 +10,13 @@ import fs from "fs";
10
10
  import path from "path";
11
11
  import os from "os";
12
12
  dotenv.config();
13
- // Use os.tmpdir() for the log file to ensure we have write permissions
14
13
  const logFilePath = path.join(os.tmpdir(), "mcp-shodan-server.log");
15
14
  const SHODAN_API_KEY = process.env.SHODAN_API_KEY;
16
15
  if (!SHODAN_API_KEY) {
17
16
  throw new Error("SHODAN_API_KEY environment variable is required.");
18
17
  }
19
18
  const API_BASE_URL = "https://api.shodan.io";
19
+ const CVEDB_API_URL = "https://cvedb.shodan.io";
20
20
  // Logging Helper Function
21
21
  function logToFile(message) {
22
22
  try {
@@ -42,11 +42,19 @@ const SearchArgsSchema = z.object({
42
42
  .describe("Maximum results to return."),
43
43
  });
44
44
  const VulnerabilitiesArgsSchema = z.object({
45
- cve: z.string().describe("The CVE identifier to query."),
45
+ cve: z.string()
46
+ .regex(/^CVE-\d{4}-\d{4,}$/i, "Must be a valid CVE ID format (e.g., CVE-2021-44228)")
47
+ .describe("The CVE identifier to query (format: CVE-YYYY-NNNNN)."),
46
48
  });
47
49
  const DnsLookupArgsSchema = z.object({
48
50
  hostnames: z.array(z.string()).describe("List of hostnames to resolve."),
49
51
  });
52
+ const CpeLookupArgsSchema = z.object({
53
+ product: z.string().describe("The name of the product to search for CPEs."),
54
+ count: z.boolean().optional().default(false).describe("If true, returns only the count of matching CPEs."),
55
+ skip: z.number().optional().default(0).describe("Number of CPEs to skip (for pagination)."),
56
+ limit: z.number().optional().default(1000).describe("Maximum number of CPEs to return (max 1000)."),
57
+ });
50
58
  // Helper Function to Query Shodan API
51
59
  async function queryShodan(endpoint, params) {
52
60
  try {
@@ -62,6 +70,37 @@ async function queryShodan(endpoint, params) {
62
70
  throw new Error(`Shodan API error: ${errorMessage}`);
63
71
  }
64
72
  }
73
+ // Helper Function for CVE lookups using CVEDB
74
+ async function queryCVEDB(cveId) {
75
+ try {
76
+ logToFile(`Querying CVEDB for: ${cveId}`);
77
+ const response = await axios.get(`${CVEDB_API_URL}/cve/${cveId}`);
78
+ return response.data;
79
+ }
80
+ catch (error) {
81
+ if (error.response?.status === 422) {
82
+ throw new Error(`Invalid CVE ID format: ${cveId}`);
83
+ }
84
+ if (error.response?.status === 404) {
85
+ throw new Error(`CVE not found: ${cveId}`);
86
+ }
87
+ throw new Error(`CVEDB API error: ${error.message}`);
88
+ }
89
+ }
90
+ // Helper Function for CPE lookups using CVEDB
91
+ async function queryCPEDB(params) {
92
+ try {
93
+ logToFile(`Querying CVEDB for CPEs with params: ${JSON.stringify(params)}`);
94
+ const response = await axios.get(`${CVEDB_API_URL}/cpes`, { params });
95
+ return response.data;
96
+ }
97
+ catch (error) {
98
+ if (error.response?.status === 422) {
99
+ throw new Error(`Invalid parameters: ${error.response.data?.detail || error.message}`);
100
+ }
101
+ throw new Error(`CVEDB API error: ${error.message}`);
102
+ }
103
+ }
65
104
  // Server Setup
66
105
  const server = new Server({
67
106
  name: "shodan-mcp",
@@ -87,7 +126,7 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
87
126
  name: "shodan-mcp",
88
127
  version: "1.0.0",
89
128
  },
90
- instructions: "This server provides tools for querying Shodan, including IP lookups, searches, and vulnerabilities.",
129
+ instructions: "This server provides tools for querying Shodan, including IP lookups, searches, vulnerabilities, and CPE lookups.",
91
130
  };
92
131
  });
93
132
  // Register Tools
@@ -105,7 +144,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
105
144
  },
106
145
  {
107
146
  name: "vulnerabilities",
108
- description: "Retrieve vulnerability information for a CVE.",
147
+ description: "Retrieve vulnerability information for a CVE. Use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)",
109
148
  inputSchema: zodToJsonSchema(VulnerabilitiesArgsSchema),
110
149
  },
111
150
  {
@@ -113,6 +152,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
113
152
  description: "Perform DNS lookups using Shodan.",
114
153
  inputSchema: zodToJsonSchema(DnsLookupArgsSchema),
115
154
  },
155
+ {
156
+ name: "cpe_lookup",
157
+ description: "Search for Common Platform Enumeration (CPE) entries by product name.",
158
+ inputSchema: zodToJsonSchema(CpeLookupArgsSchema),
159
+ },
116
160
  ];
117
161
  logToFile("Registered tools.");
118
162
  return { tools };
@@ -159,17 +203,45 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
159
203
  case "vulnerabilities": {
160
204
  const parsedVulnArgs = VulnerabilitiesArgsSchema.safeParse(args);
161
205
  if (!parsedVulnArgs.success) {
162
- throw new Error("Invalid vulnerabilities arguments");
206
+ throw new Error("Invalid CVE format. Please use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)");
207
+ }
208
+ const cveId = parsedVulnArgs.data.cve.toUpperCase();
209
+ logToFile(`Looking up CVE: ${cveId}`);
210
+ try {
211
+ const result = await queryCVEDB(cveId);
212
+ return {
213
+ content: [
214
+ {
215
+ type: "text",
216
+ text: JSON.stringify({
217
+ cve_id: result.cve_id,
218
+ summary: result.summary,
219
+ cvss_v3: result.cvss_v3,
220
+ cvss_v2: result.cvss_v2,
221
+ epss: result.epss,
222
+ ranking_epss: result.ranking_epss,
223
+ kev: result.kev,
224
+ propose_action: result.propose_action,
225
+ ransomware_campaign: result.ransomware_campaign,
226
+ published: result.published_time,
227
+ references: result.references,
228
+ affected_products: result.cpes
229
+ }, null, 2),
230
+ },
231
+ ],
232
+ };
233
+ }
234
+ catch (error) {
235
+ return {
236
+ content: [
237
+ {
238
+ type: "text",
239
+ text: error.message,
240
+ },
241
+ ],
242
+ isError: true,
243
+ };
163
244
  }
164
- const result = await queryShodan(`/shodan/cve/${parsedVulnArgs.data.cve}`, {});
165
- return {
166
- content: [
167
- {
168
- type: "text",
169
- text: JSON.stringify(result, null, 2),
170
- },
171
- ],
172
- };
173
245
  }
174
246
  case "dns_lookup": {
175
247
  const parsedDnsArgs = DnsLookupArgsSchema.safeParse(args);
@@ -194,6 +266,48 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
194
266
  ],
195
267
  };
196
268
  }
269
+ case "cpe_lookup": {
270
+ const parsedCpeArgs = CpeLookupArgsSchema.safeParse(args);
271
+ if (!parsedCpeArgs.success) {
272
+ throw new Error("Invalid cpe_lookup arguments");
273
+ }
274
+ try {
275
+ const result = await queryCPEDB({
276
+ product: parsedCpeArgs.data.product,
277
+ count: parsedCpeArgs.data.count,
278
+ skip: parsedCpeArgs.data.skip,
279
+ limit: parsedCpeArgs.data.limit
280
+ });
281
+ // Format the response based on whether it's a count request or full CPE list
282
+ const formattedResult = parsedCpeArgs.data.count
283
+ ? { total_cpes: result.total }
284
+ : {
285
+ cpes: result.cpes,
286
+ skip: parsedCpeArgs.data.skip,
287
+ limit: parsedCpeArgs.data.limit,
288
+ total_returned: result.cpes.length
289
+ };
290
+ return {
291
+ content: [
292
+ {
293
+ type: "text",
294
+ text: JSON.stringify(formattedResult, null, 2),
295
+ },
296
+ ],
297
+ };
298
+ }
299
+ catch (error) {
300
+ return {
301
+ content: [
302
+ {
303
+ type: "text",
304
+ text: error.message,
305
+ },
306
+ ],
307
+ isError: true,
308
+ };
309
+ }
310
+ }
197
311
  default:
198
312
  throw new Error(`Unknown tool: ${name}`);
199
313
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@burtthecoder/mcp-shodan",
4
- "version": "1.0.5",
4
+ "version": "1.0.7",
5
5
  "description": "A Model Context Protocol server for Shodan API queries.",
6
6
  "main": "./build/index.js",
7
7
  "bin": {