Skip to main content
Glama

Unrestricted Development MCP Server

shell.ts8.04 kB
import { z } from 'zod'; import { exec, spawn } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); /** * Shell Tools * Provides unrestricted shell command execution with full system access * Supports sudo, background processes, environment variables, and streaming output */ // ========== TOOL SCHEMAS ========== export const executeCommandSchema = z.object({ command: z.string().describe('The shell command to execute'), cwd: z.string().optional().describe('Working directory for the command (defaults to current directory)'), env: z.record(z.string()).optional().describe('Environment variables to set for the command'), timeout: z.number().optional().describe('Timeout in milliseconds (default: 30000ms)'), shell: z.string().optional().describe('Shell to use (default: /bin/bash)'), sudo: z.boolean().default(false).describe('Execute with sudo privileges') }); export const executeStreamingCommandSchema = z.object({ command: z.string().describe('The shell command to execute with streaming output'), cwd: z.string().optional().describe('Working directory for the command'), env: z.record(z.string()).optional().describe('Environment variables to set for the command'), shell: z.string().optional().describe('Shell to use (default: /bin/bash)'), sudo: z.boolean().default(false).describe('Execute with sudo privileges') }); // ========== TOOL IMPLEMENTATIONS ========== type ToolResponse = { content: Array<{ type: "text"; text: string }>; isError?: boolean; }; export async function executeCommand(args: z.infer<typeof executeCommandSchema>): Promise<ToolResponse> { try { // For sudo commands, wrap the entire command in a shell to ensure all parts run with sudo const command = args.sudo ? `sudo bash -c ${JSON.stringify(args.command)}` : args.command; const timeout = args.timeout || 30000; const { stdout, stderr } = await execAsync(command, { cwd: args.cwd, env: args.env ? { ...process.env, ...args.env } : process.env, shell: args.shell || '/bin/bash', timeout: timeout, maxBuffer: 10 * 1024 * 1024 // 10MB buffer }); return { content: [ { type: "text" as const, text: JSON.stringify({ success: true, command: command, stdout: stdout, stderr: stderr, exitCode: 0 }, null, 2) } ] }; } catch (error: any) { // Even if command fails, return the output const command = args.sudo ? `sudo bash -c ${JSON.stringify(args.command)}` : args.command; return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, command: command, stdout: error.stdout || '', stderr: error.stderr || error.message, exitCode: error.code || 1, signal: error.signal, timedOut: error.killed && error.signal === 'SIGTERM' }, null, 2) } ], isError: true }; } } export async function executeStreamingCommand(args: z.infer<typeof executeStreamingCommandSchema>): Promise<ToolResponse> { try { // For sudo commands, wrap the entire command in a shell to ensure all parts run with sudo const command = args.sudo ? `sudo bash -c ${JSON.stringify(args.command)}` : args.command; return new Promise((resolve) => { const child = spawn(command, { cwd: args.cwd, env: args.env ? { ...process.env, ...args.env } : process.env, shell: args.shell || '/bin/bash', stdio: ['ignore', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; child.stdout?.on('data', (data) => { stdout += data.toString(); }); child.stderr?.on('data', (data) => { stderr += data.toString(); }); child.on('close', (code, signal) => { resolve({ content: [ { type: "text" as const, text: JSON.stringify({ success: code === 0, command: command, stdout: stdout, stderr: stderr, exitCode: code, signal: signal }, null, 2) } ], isError: code !== 0 }); }); child.on('error', (error) => { resolve({ content: [ { type: "text" as const, text: JSON.stringify({ success: false, command: command, stdout: stdout, stderr: stderr + '\n' + error.message, error: error.message }, null, 2) } ], isError: true }); }); }); } catch (error) { return { content: [ { type: "text" as const, text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) } ], isError: true }; } } // ========== TOOL DEFINITIONS FOR MCP ========== export const shellTools = [ { name: 'shell_execute', description: `Execute a shell command with full system access. Supports sudo for privileged operations. Use this for: - Running system commands (apt, brew, yum, dnf, pacman, etc.) - Installing packages and dependencies - Managing services (systemctl, service, etc.) - File operations via shell utilities - Network operations (curl, wget, ssh, scp, etc.) - Git operations - Docker commands - Any other shell command The command runs in /bin/bash by default. Output is captured and returned after completion. For long-running commands, use shell_execute_streaming instead.`, inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'The shell command to execute' }, cwd: { type: 'string', description: 'Working directory for the command (defaults to current directory)' }, env: { type: 'object', additionalProperties: { type: 'string' }, description: 'Environment variables to set for the command' }, timeout: { type: 'number', description: 'Timeout in milliseconds (default: 30000ms)' }, shell: { type: 'string', description: 'Shell to use (default: /bin/bash)' }, sudo: { type: 'boolean', default: false, description: 'Execute with sudo privileges. Use this for system-level operations like installing packages.' } }, required: ['command'] } }, { name: 'shell_execute_streaming', description: `Execute a long-running shell command with streaming output support. Captures output as it's produced. Use this for: - Build processes (npm build, cargo build, etc.) - Long-running scripts - Services that produce continuous output - Commands that take significant time to complete The command runs in /bin/bash by default. Output is streamed and returned when complete.`, inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'The shell command to execute with streaming output' }, cwd: { type: 'string', description: 'Working directory for the command' }, env: { type: 'object', additionalProperties: { type: 'string' }, description: 'Environment variables to set for the command' }, shell: { type: 'string', description: 'Shell to use (default: /bin/bash)' }, sudo: { type: 'boolean', default: false, description: 'Execute with sudo privileges' } }, required: ['command'] } } ];

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/ConnorBoetig-dev/mcp2'

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