Skip to main content
Glama
README.md12 kB
# Nmap MCP Server (Smithery SDK) This project implements an MCP-compliant (Model Context Protocol) server using the Smithery SDK. It wraps the Nmap network scanner, exposing its functionality as callable tools within the MCP framework. ## Features - **MCP Standard Endpoint (`/mcp`)**: Interacts with the server using JSON-RPC 2.0 requests. - **`nmapScan` Tool**: Initiates an Nmap scan on a specified target with configurable flags. Returns detailed scan results, including parsed XML output. - **`getInfo` Tool**: Provides basic information about the Nmap service and its capabilities. - Input validation for targets and Nmap flags to enhance security. ## Prerequisites - [Node.js](https://nodejs.org/) (v16.x or later recommended) - [Nmap](https://nmap.org/download.html) installed and available in your system's PATH. ## Installation 1. Clone the repository (or download the source code). 2. Navigate to the project directory: ```bash cd your-project-directory ``` 3. Install dependencies: ```bash npm install ``` ## Running the Server To start the server, run: ```bash npm start ``` By default, the server will listen on `http://localhost:5001`. You can set the `PORT` environment variable to use a different port. ## Interacting with the Server (MCP) All interactions with the server are done via the `/mcp` endpoint using JSON-RPC 2.0. You will send `POST` requests with a `Content-Type: application/json` header. ### Calling the `nmapScan` Tool To initiate an Nmap scan: **Request Body (JSON):** ```json { "jsonrpc": "2.0", "id": 1, // Or any unique request ID "method": "tools/call", "params": { "name": "nmapScan", "arguments": { "target": "scanme.nmap.org", "flags": "-A -T4" // Optional, defaults to "-T4 -p 1-1000" } } } ``` **Example using cURL:** ```bash curl -X POST http://localhost:5001/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "nmapScan", "arguments": { "target": "scanme.nmap.org", "flags": "-A" } } }' ``` **Expected Response Structure (Success):** The server will respond with the results of the Nmap scan. The `content` array will contain a text object with a summary and the full JSON-parsed Nmap XML output. ```json { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "Nmap Scan Results for scanme.nmap.org\n\nScan started: ...\n... (summary of open ports) ...\nScan completed: ...\n\nFull XML Output:\n{\n \"nmaprun\": { ... }\n}" } ] } } ``` If the scan fails or inputs are invalid, the `text` field will contain an error message. ### Calling the `getInfo` Tool To get information about the service: **Request Body (JSON):** ```json { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "getInfo", "arguments": {} } } ``` **Example using cURL:** ```bash curl -X POST http://localhost:5001/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "getInfo", "arguments": {} } }' ``` **Expected Response Structure (Success):** ```json { "jsonrpc": "2.0", "id": 2, "result": { "content": [ { "type": "text", "text": "Nmap Service Information:\n- Service: Network scanning using Nmap\n- Version: 1.0.0\n- Available Tools: nmapScan, getInfo\n- Session ID: N/A\n- Supported Targets: Domain names, IP addresses, CIDR notation\n- Security: Input validation and command sanitization enabled" } ] } } ``` ## Deployment on Smithery To deploy this server on Smithery, you will typically need to: 1. **Ensure Nmap is available in the Smithery execution environment.** This might involve custom Docker images or buildpacks if Nmap isn't pre-installed. 2. **Define the startup command:** Smithery will need to know how to start the application (e.g., `npm start`). 3. **Port configuration:** Smithery will expose the application, usually handling port mapping. Ensure the application listens on the port Smithery expects (often configured via the `PORT` environment variable, which this server supports via the `process.env.PORT || 5001` pattern). 4. **Package the application:** This usually means providing the source code and `package.json` (and `package-lock.json`). Smithery will then build the application, installing dependencies. Refer to the Smithery documentation for specific deployment instructions and how to configure services that adhere to the Model Context Protocol. ## Example MCP Client Below is an example of how to create a client to interact with this Nmap MCP server. You'll need to have the `@modelcontextprotocol/sdk` and `@smithery/sdk` packages installed in your client project. Save the following code as `nmap_mcp_client_example.js`: ```javascript import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { createSmitheryUrl } from "@smithery/sdk/shared/config.js"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; // Ensure you have your Smithery API key for the server in an environment variable const SMITHERY_API_KEY = process.env.SMITHERY_NMAP_API_KEY || "your-smithery-api-key-here"; // Replace with your actual key or ensure env var is set const NMAP_SERVER_URL = "https://server.smithery.ai/@sideffect263/nmap-mcp-server"; // Replace with your server URL if different let clientInstance; let nmapScanTool; let getInfoTool; async function initializeNmapClient() { if (clientInstance) { console.log("Nmap MCP Client already initialized."); return clientInstance; } console.log("Initializing Nmap MCP Client..."); try { const config = {}; // Add any specific config for Smithery if needed const serverUrl = createSmitheryUrl( NMAP_SERVER_URL, { config, apiKey: SMITHERY_API_KEY } ); const transport = new StreamableHTTPClientTransport(serverUrl); clientInstance = new Client({ name: "ExampleNmapClient", version: "1.0.0", }); console.log("Connecting to Nmap MCP server..."); await clientInstance.connect(transport); console.log("Successfully connected to Nmap MCP server."); const toolsResponse = await clientInstance.listTools(); if (toolsResponse && toolsResponse.tools && Array.isArray(toolsResponse.tools)) { console.log(`Available tools: ${toolsResponse.tools.map((t) => t.name).join(", ")}`); nmapScanTool = toolsResponse.tools.find(tool => tool.name === 'nmapScan'); getInfoTool = toolsResponse.tools.find(tool => tool.name === 'getInfo'); } else { throw new Error("Could not list tools from the server."); } if (!nmapScanTool) { throw new Error("Nmap tool ('nmapScan') not found on the MCP server."); } console.log(`Found Nmap tool: ${nmapScanTool.name}`); if (getInfoTool) { console.log(`Found GetInfo tool: ${getInfoTool.name}`); } else { console.warn("GetInfo tool ('getInfo') not found. This might be optional."); } return clientInstance; } catch (error) { console.error("Failed to initialize Nmap MCP client:", error); clientInstance = null; // Reset on failure nmapScanTool = null; getInfoTool = null; throw error; } } /** * Invokes the 'nmapScan' tool on the MCP server. * @param {Object} params - Parameters for the Nmap tool. * @param {string} params.target - The target IP, hostname, or CIDR. * @param {string} params.flags - Nmap flags as a single string (e.g., "-A -T4"). * @returns {Promise<Object>} - The result from the 'nmapScan' tool. */ async function invokeNmapScan(params) { if (!clientInstance || !nmapScanTool) { console.log("Client not ready. Initializing..."); await initializeNmapClient(); if (!clientInstance || !nmapScanTool) { throw new Error("Nmap MCP client is not initialized or nmapScan tool not found."); } } const toolInput = { target: params.target, flags: params.flags }; console.log(\`Invoking Nmap tool "\${nmapScanTool.name}" with params:\`, toolInput); try { const result = await clientInstance.callTool({ name: nmapScanTool.name, arguments: toolInput }); console.log("'nmapScan' tool invocation successful. Result:", JSON.stringify(result, null, 2)); return result; } catch (error) { console.error(\`Error invoking 'nmapScan' tool for target \${params.target}:\`, error); throw error; } } /** * Invokes the 'getInfo' tool on the MCP server. * @returns {Promise<Object>} - The result from the 'getInfo' tool. */ async function invokeGetInfo() { if (!clientInstance || !getInfoTool) { console.log("Client or getInfo tool not ready. Initializing..."); await initializeNmapClient(); if (!clientInstance || !getInfoTool) { throw new Error("Nmap MCP client is not initialized or getInfo tool not found."); } } console.log(\`Invoking GetInfo tool "\${getInfoTool.name}"\`); try { const result = await clientInstance.callTool({ name: getInfoTool.name, arguments: {} // getInfo usually takes no arguments }); console.log("'getInfo' tool invocation successful. Result:", JSON.stringify(result, null, 2)); return result; } catch (error) { console.error("Error invoking 'getInfo' tool:", error); throw error; } } // --- Example Usage --- async function main() { try { await initializeNmapClient(); // Example: Get server info console.log("\\n--- Calling getInfo ---"); const info = await invokeGetInfo(); if (info && info.content && info.content[0] && info.content[0].text) { console.log("Server Info:", info.content[0].text); } // Example: Perform an Nmap scan console.log("\\n--- Calling nmapScan ---"); const scanParams = { target: "scanme.nmap.org", // A safe target for testing flags: "-T4 -F" // Example flags: Fast scan, default timing }; const scanResult = await invokeNmapScan(scanParams); if (scanResult && scanResult.content && scanResult.content[0] && scanResult.content[0].text) { console.log(\`Scan results for \${scanParams.target}:\`, scanResult.content[0].text); } } catch (error) { console.error("\\n--- Example Script Failed ---"); console.error("An error occurred:", error.message); } finally { if (clientInstance) { console.log("\\nDisconnecting client..."); await clientInstance.disconnect(); console.log("Client disconnected."); } } } // Run the example main(); export { initializeNmapClient, invokeNmapScan, invokeGetInfo }; ``` To run this example client: 1. Ensure you have Node.js installed. 2. Create a new directory for your client project. 3. Inside this directory, run `npm init -y` to create a `package.json` file. 4. Install the necessary SDKs: ```bash npm install @modelcontextprotocol/sdk @smithery/sdk ``` 5. Save the code above as `nmap_mcp_client_example.js` in this directory. 6. Modify the `SMITHERY_NMAP_API_KEY` and `NMAP_SERVER_URL` constants in the script with your actual Smithery API key and the URL of your deployed Nmap MCP server. 7. If your `package.json` doesn't already have `"type": "module"`, add it or change the import/export syntax to CommonJS (`require`/`module.exports`). For ES Modules (as written), add: ```json // package.json { // ... other properties "type": "module" } ``` 8. Run the client: ```bash node nmap_mcp_client_example.js ``` This client will connect to your Nmap MCP server, list available tools, call `getInfo` for server information, and then call `nmapScan` to perform a scan on `scanme.nmap.org`.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sideffect263/nmap-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server