Skip to main content
Glama

ToolBox MCP Server

cli_tool.ts4.6 kB
import { spawn, SpawnOptions } from 'child_process'; import { platform } from 'os'; export const schema = { name: "cli_tool", description: "执行CLI命令,支持同步/异步模式、超时和安全过滤。", type: "object", properties: { command: { type: "string", description: "要执行的单行命令" }, commands: { type: "array", items: { type: "string" }, description: "要执行的多行命令序列 (与 'command' 互斥)" }, mode: { type: "string", enum: ["sync", "async"], default: "sync", description: "执行模式: sync (同步阻塞), async (异步非阻塞)" }, timeout: { type: "number", minimum: 1, default: 60, description: "命令执行的超时时间(秒)" }, cwd: { type: "string", description: "命令执行的工作目录 (绝对路径)" }, platform: { type: "string", enum: ["auto", "win32", "linux", "darwin"], default: "auto", description: "强制指定执行命令的操作系统环境" }, safe_mode: { type: "boolean", default: true, description: "是否启用危险命令过滤" } }, required: [] }; const dangerousCommandPatterns = [ /^sudo\s+rm\s+-rf\s+\//, /^\s*rm\s+-rf\s+\//, /^sudo\s+chmod\s+(777|-R\s+777)\s+\//, ]; function isCommandDangerous(command: string): boolean { return dangerousCommandPatterns.some(pattern => pattern.test(command)); } async function executeCommand(command: string, options: any): Promise<{ stdout: string; stderr: string; code: number | null }> { return new Promise((resolve, reject) => { const shell = options.platform === 'win32' ? 'cmd.exe' : '/bin/bash'; const shellArg = options.platform === 'win32' ? '/c' : '-c'; const spawnOptions: SpawnOptions = { cwd: options.cwd, env: process.env, shell: true, timeout: options.timeout * 1000 // 将秒转换为毫秒 }; const child = spawn(shell, [shellArg, command], spawnOptions); let stdout = ''; let stderr = ''; child.stdout?.on('data', (data) => { stdout += data.toString(); }); child.stderr?.on('data', (data) => { stderr += data.toString(); }); child.on('close', (code) => { resolve({ stdout, stderr, code }); }); child.on('error', (err) => { if ((err as any).code === 'ETIMEDOUT') { reject(new Error(`命令执行超时 (超过 ${options.timeout} 秒)`)); } else { reject(err); } }); }); } export default async function (request: any) { try { const { command, commands, mode, timeout, cwd, platform: requestedPlatform, safe_mode } = request.params.arguments; if (!command && !commands) { throw new Error("必须提供 'command' 或 'commands' 参数之一。"); } if (command && commands) { throw new Error("'command' 和 'commands' 参数不能同时提供。"); } const osPlatform = requestedPlatform === 'auto' ? platform() : requestedPlatform; const options = { cwd: cwd || process.cwd(), timeout: timeout || 60, platform: osPlatform }; const allCommands = command ? [command] : (commands || []); if (safe_mode) { for (const cmd of allCommands) { if (isCommandDangerous(cmd)) { throw new Error(`命令 "${cmd}" 被安全模式阻止。`); } } } if (mode === 'sync') { const results = []; for (const cmd of allCommands) { const { stdout, stderr, code } = await executeCommand(cmd, options); results.push({ type: "text", text: JSON.stringify({ command: cmd, stdout, stderr, code }, null, 2) }); } return { content: results }; } else { // async mode for (const cmd of allCommands) { executeCommand(cmd, options).catch(error => { // 异步错误不会直接返回给用户,但会被框架的日志系统捕获 console.error(`异步命令执行失败: ${cmd}`, error); }); } return { content: [{ type: "text", text: `已为 ${allCommands.length} 个命令启动异步执行。请检查系统日志以了解完成状态。` }] }; } } catch (error) { return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` } ], isError: true }; } } export async function destroy() { console.log("Destroy cli_tool tool"); }

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/xiaoguomeiyitian/ToolBox'

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