@burtthecoder/mcp-shodan 1.0.5 → 1.0.6

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 (2) hide show
  1. package/build/index.js +61 -14
  2. package/package.json +1 -1
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,7 +42,9 @@ 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."),
@@ -62,6 +64,23 @@ async function queryShodan(endpoint, params) {
62
64
  throw new Error(`Shodan API error: ${errorMessage}`);
63
65
  }
64
66
  }
67
+ // Helper Function for CVE lookups using CVEDB
68
+ async function queryCVEDB(cveId) {
69
+ try {
70
+ logToFile(`Querying CVEDB for: ${cveId}`);
71
+ const response = await axios.get(`${CVEDB_API_URL}/cve/${cveId}`);
72
+ return response.data;
73
+ }
74
+ catch (error) {
75
+ if (error.response?.status === 422) {
76
+ throw new Error(`Invalid CVE ID format: ${cveId}`);
77
+ }
78
+ if (error.response?.status === 404) {
79
+ throw new Error(`CVE not found: ${cveId}`);
80
+ }
81
+ throw new Error(`CVEDB API error: ${error.message}`);
82
+ }
83
+ }
65
84
  // Server Setup
66
85
  const server = new Server({
67
86
  name: "shodan-mcp",
@@ -87,7 +106,7 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
87
106
  name: "shodan-mcp",
88
107
  version: "1.0.0",
89
108
  },
90
- instructions: "This server provides tools for querying Shodan, including IP lookups, searches, and vulnerabilities.",
109
+ instructions: "This server provides tools for querying Shodan, including IP lookups, searches, and vulnerabilities. For CVE lookups, use the format CVE-YYYY-NNNNN (e.g., CVE-2021-44228).",
91
110
  };
92
111
  });
93
112
  // Register Tools
@@ -105,7 +124,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
105
124
  },
106
125
  {
107
126
  name: "vulnerabilities",
108
- description: "Retrieve vulnerability information for a CVE.",
127
+ description: "Retrieve vulnerability information for a CVE. Use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)",
109
128
  inputSchema: zodToJsonSchema(VulnerabilitiesArgsSchema),
110
129
  },
111
130
  {
@@ -159,17 +178,45 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
159
178
  case "vulnerabilities": {
160
179
  const parsedVulnArgs = VulnerabilitiesArgsSchema.safeParse(args);
161
180
  if (!parsedVulnArgs.success) {
162
- throw new Error("Invalid vulnerabilities arguments");
181
+ throw new Error("Invalid CVE format. Please use format: CVE-YYYY-NNNNN (e.g., CVE-2021-44228)");
182
+ }
183
+ const cveId = parsedVulnArgs.data.cve.toUpperCase();
184
+ logToFile(`Looking up CVE: ${cveId}`);
185
+ try {
186
+ const result = await queryCVEDB(cveId);
187
+ return {
188
+ content: [
189
+ {
190
+ type: "text",
191
+ text: JSON.stringify({
192
+ cve_id: result.cve_id,
193
+ summary: result.summary,
194
+ cvss_v3: result.cvss_v3,
195
+ cvss_v2: result.cvss_v2,
196
+ epss: result.epss,
197
+ ranking_epss: result.ranking_epss,
198
+ kev: result.kev,
199
+ propose_action: result.propose_action,
200
+ ransomware_campaign: result.ransomware_campaign,
201
+ published: result.published_time,
202
+ references: result.references,
203
+ affected_products: result.cpes
204
+ }, null, 2),
205
+ },
206
+ ],
207
+ };
208
+ }
209
+ catch (error) {
210
+ return {
211
+ content: [
212
+ {
213
+ type: "text",
214
+ text: error.message,
215
+ },
216
+ ],
217
+ isError: true,
218
+ };
163
219
  }
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
220
  }
174
221
  case "dns_lookup": {
175
222
  const parsedDnsArgs = DnsLookupArgsSchema.safeParse(args);
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.6",
5
5
  "description": "A Model Context Protocol server for Shodan API queries.",
6
6
  "main": "./build/index.js",
7
7
  "bin": {