Skip to main content
Glama

shell_netstat

Display network connection information to monitor active connections and troubleshoot network issues using command-line arguments.

Instructions

Network connection information

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
argsNoCommand arguments

Implementation Reference

  • Registration of the shell.netstat command in allowedCommands object. This config defines the tool's base command ('netstat'), description, allowed arguments for input validation, and execution timeout. The MCP tool name exposed is 'netstat' after stripping 'shell.' prefix.
    'shell.netstat': { command: 'netstat', description: 'Network connection information', allowedArgs: [ '-a', // all connections '-n', // numeric addresses '-t', // TCP '-u', // UDP '-l', // listening '-p', // show process '--help' ], timeout: 3000 },
  • Dynamically generates MCP tool definitions from allowedCommands. For 'shell.netstat', creates tool {name: 'netstat', description: ..., inputSchema: {args: array of strings}}
    const tools: Tool[] = []; const processedNames = new Set<string>(); this.logger.debug('Starting to process tool list', { commandCount: Object.keys(allowedCommands).length }); Object.entries(allowedCommands).forEach(([name, config]) => { const toolName = name.replace('shell.', ''); this.logger.debug('Processing command', { originalName: name, toolName, isProcessed: processedNames.has(toolName) }); if (!processedNames.has(toolName)) { processedNames.add(toolName); tools.push({ name: toolName, description: config.description, inputSchema: { type: "object", properties: { args: { type: "array", items: { type: "string" }, description: "Command arguments" } } } }); } }); this.logger.debug('Tool list processing completed', { toolCount: tools.length, processedNames: Array.from(processedNames) }); this.validateToolNames(tools); return tools; }
  • MCP CallTool request handler. For tool 'netstat', maps to fullCommand 'shell.netstat', retrieves config from allowedCommands, validates args against allowedArgs, executes via executor, collects stdout and returns as text content.
    this.server.setRequestHandler(CallToolRequestSchema, async (request, extra: unknown) => { const ext = extra as Extra; if (!request.params?.name) { throw new ToolError('MISSING_COMMAND', 'Command name is required'); } const command = String(request.params.name); const fullCommand = command.startsWith('shell.') ? command : `shell.${command}`; if (!(fullCommand in allowedCommands)) { throw new ToolError('COMMAND_NOT_FOUND', 'Command not found', { command }); } const config = allowedCommands[fullCommand]; const args = Array.isArray(request.params.arguments?.args) ? request.params.arguments.args.map(String) : []; const context: CommandContext = { requestId: ext.id || 'unknown', command, args, timeout: config.timeout, workDir: config.workDir, env: config.env }; this.logger.info('Starting command execution', context); try { this.validator.validateCommand(command, args); this.logger.debug('Command validation passed', { ...context, config }); const stream = await this.executor.execute(command, args, { timeout: config.timeout, cwd: config.workDir, env: config.env }); ext.onCancel?.(() => { this.logger.info('Received cancel request', context); this.executor.interrupt(); }); const output = await this.collectOutput(stream); this.logger.info('Command execution completed', { ...context, outputLength: output.length }); return { content: [{ type: "text", text: output }] }; } catch (error) { this.logger.error('Command execution failed', { ...context, error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined }); throw new ToolError( 'EXECUTION_FAILED', `Command execution failed: ${error instanceof Error ? error.message : String(error)}`, context ); } });
  • Executes the shell command. For 'shell.netstat', strips to 'netstat' and spawns child_process.spawn('netstat', args, options), returning stdout stream.
    async execute( command: string, args: string[] = [], options: ExecuteOptions = {} ): Promise<{ stdout: Readable }> { const commandKey = `${command} ${args.join(' ')}`; try { // Check security await this.securityChecker.validateCommand(command, args, options); // Check cache const cached = this.cache.get(commandKey); if (cached) { this.logger.debug('Using cached command result', { command, args }); return this.createStreamFromCache(cached); } // Remove 'shell.' prefix for execution const baseCommand = command.replace('shell.', ''); // Execute command this.logger.debug('Starting command execution', { command, args, options }); const childProcess = spawn(baseCommand, args, { stdio: ['ignore', 'pipe', 'pipe'], timeout: options.timeout, cwd: options.cwd, env: { ...process.env, ...options.env }, signal: options.signal }); this.currentProcess = childProcess; // Error handling childProcess.on('error', (error: Error) => { this.logger.error('Command execution error', { command, args, error: error.message }); throw new ToolError( 'PROCESS_ERROR', 'Command execution error', { command, args, error: error.message } ); }); // Timeout handling if (options.timeout) { setTimeout(() => { if (childProcess.exitCode === null) { this.logger.warn('Command execution timeout', { command, args, timeout: options.timeout }); childProcess.kill(); throw new ToolError( 'TIMEOUT', 'Command execution timeout', { command, args, timeout: options.timeout } ); } }, options.timeout); } if (!childProcess.stdout) { throw new ToolError( 'STREAM_ERROR', 'Unable to get command output stream', { command, args } ); } // Monitor process status childProcess.on('exit', (code, signal) => { this.logger.debug('Command execution completed', { command, args, exitCode: code, signal }); }); return { stdout: childProcess.stdout };
  • Validates input arguments for shell commands against the allowedArgs defined in the config for 'shell.netstat'. Ensures only permitted flags and safe paths are used.
    validateCommand( command: string, args: string[] = [], options: CommandOptions = {} ): void { console.log('Validating command:', { command, args, baseCommand: command.replace('shell.', ''), fullCommand: `shell.${command.replace('shell.', '')}`, config: allowedCommands[`shell.${command.replace('shell.', '')}`] }); const baseCommand = command.replace('shell.', ''); if (!(`shell.${baseCommand}` in allowedCommands)) { throw new Error(`Command not allowed: ${command}`); } const config = allowedCommands[`shell.${baseCommand}`]; const allowedArgs = config.allowedArgs || []; console.log('Checking args:', { allowedArgs, hasWildcard: allowedArgs.includes('*') }); args.forEach(arg => { if (arg.startsWith('-')) { if (!allowedArgs.includes(arg)) { console.log('Invalid option:', arg); throw new Error(`Invalid argument: ${arg}`); } } else if (!allowedArgs.includes('*')) { console.log('Path not allowed:', arg); throw new Error(`Invalid argument: ${arg}`); } else { // 檢查路徑參數 this.validatePath(arg); } });

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/kevinwatt/shell-mcp'

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