Skip to main content
Glama
arjshiv

Local Utilities MCP Server

by arjshiv
port-checker.ts3.76 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { exec } from 'child_process'; import { promisify } from 'util'; import { z } from 'zod'; const execPromise = promisify(exec); // Define a more specific type for the result (optional but good practice) interface PortCheckResult { message: string; processes?: Array<{ [key: string]: string }>; raw?: string[]; // For Windows } /** * Checks what process is using a specific port * @param port The port number to check * @returns Information about the process using the port */ export async function checkPort(port: number): Promise<PortCheckResult> { // Export and use specific type let command = ''; if (process.platform === 'win32') { command = `netstat -ano | findstr :${port}`; } else if (process.platform === 'darwin') { command = `lsof -i :${port} -P -n -sTCP:LISTEN`; } else { command = `lsof -i :${port} -P -n | grep LISTEN`; } try { const { stdout } = await execPromise(command); if (!stdout.trim()) { return { message: `No process found using port ${port}` }; } // Parse the output based on the platform let result: PortCheckResult; if (process.platform === 'win32') { const lines = stdout.trim().split('\n'); result = { raw: lines, message: `Found ${lines.length} connection(s) on port ${port}` }; } else { const lines = stdout.trim().split('\n'); const processes = lines.map(line => { const parts = line.trim().split(/\s+/); // Basic parsing, might need adjustment based on actual lsof output variations return { command: parts[0] || 'N/A', pid: parts[1] || 'N/A', user: parts[2] || 'N/A', fd: parts[3] || 'N/A', type: parts[4] || 'N/A', device: parts[5] || 'N/A', size: parts[6] || 'N/A', node: parts[7] || 'N/A', name: parts.slice(8).join(' ') || 'N/A' // Handle names with spaces }; }); result = { processes, message: `Found ${processes.length} process(es) using port ${port}` }; } return result; } catch (error: any) { // If the command fails (e.g., port not used), lsof/netstat often exit with error code. // Check the error output or code if necessary, but often it just means no process found. // For simplicity, we assume command failure implies no process found. console.debug(`Port check command for ${port} failed (likely no process found):`, error.message); return { message: `No process found using port ${port}` }; // Re-throw only if it's an unexpected error (optional) // if (!error.message.includes('Command failed')) { throw error; } } } // Define the Zod schema for the port parameter const PortSchema = z.union([ z.number().int().min(1).max(65535), z.string().transform((val, ctx) => { const parsed = parseInt(val, 10); if (isNaN(parsed) || parsed < 1 || parsed > 65535) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Port must be a number between 1 and 65535" }); return z.NEVER; // Indicates validation failure } return parsed; }) ]).describe("Port number to check (1-65535)"); export function registerPortCheckerTool(server: McpServer): void { server.tool( "check_port", { port: PortSchema }, async (params) => { // Let SDK handle errors from checkPort if they are re-thrown // and Zod handle parameter validation errors. const result = await checkPort(params.port); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } ); }

Implementation Reference

Latest Blog Posts

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/arjshiv/localutils-mcp-server'

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