@gabrielmaialva33/mcp-filesystem
Version:
MCP server for secure filesystem access
108 lines • 3.2 kB
JavaScript
import { exec } from 'node:child_process';
import { promisify } from 'node:util';
import { logger } from '../../logger/index.js';
import { FileSystemError } from '../../errors/index.js';
const execPromise = promisify(exec);
const DEFAULT_TIMEOUT_MS = 30000;
const SAFE_COMMAND_REGEX = /^[a-zA-Z0-9_\-./\s]+$/;
const FORBIDDEN_COMMANDS = [
'rm -rf',
'rm -r',
'rmdir',
'dd',
'mkfs',
'format',
'wget',
'curl -O',
'curl --output',
'chmod 777',
'chmod -R 777',
'sudo',
'su',
];
export function isCommandSafe(command) {
if (FORBIDDEN_COMMANDS.some((forbidden) => command.includes(forbidden))) {
return false;
}
if (!SAFE_COMMAND_REGEX.test(command)) {
return false;
}
return true;
}
export async function executeBashCommand(command, options = {}) {
if (!isCommandSafe(command)) {
throw new FileSystemError(`Command contains forbidden operations or unsafe characters: ${command}`, 'UNSAFE_COMMAND', undefined, { command });
}
const execOptions = {
cwd: options.workingDir || process.cwd(),
timeout: options.timeout || DEFAULT_TIMEOUT_MS,
env: options.env ? { ...process.env, ...options.env } : process.env,
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024,
};
try {
await logger.debug(`Executing bash command: ${command}`, {
workingDir: execOptions.cwd,
timeout: execOptions.timeout,
});
const { stdout, stderr } = await execPromise(command, execOptions);
return {
stdout,
stderr,
exitCode: 0,
};
}
catch (error) {
await logger.warn(`Command execution failed: ${command}`, {
error: error.message,
stderr: error.stderr,
code: error.code,
});
return {
stdout: error.stdout || '',
stderr: error.stderr || error.message || 'Unknown error',
exitCode: error.code || 1,
};
}
}
export const BashCommandArgsSchema = {
type: 'object',
properties: {
command: {
type: 'string',
description: 'The bash command to execute',
},
workingDir: {
type: 'string',
description: 'Working directory for command execution (must be within allowed directories)',
},
timeout: {
type: 'number',
description: 'Maximum execution time in milliseconds (max 30s)',
},
env: {
type: 'object',
description: 'Additional environment variables for the command',
},
},
required: ['command'],
};
export async function handleBashCommand(args) {
const result = await executeBashCommand(args.command, {
workingDir: args.workingDir,
timeout: args.timeout,
env: args.env,
});
const output = [
`Command: ${args.command}`,
`Exit Code: ${result.exitCode}`,
'',
'STDOUT:',
result.stdout || '(empty)',
'',
'STDERR:',
result.stderr || '(empty)',
].join('\n');
return output;
}
//# sourceMappingURL=index.js.map