From 32dd684e0c5f2d737206c2597b17630a7501b966 Mon Sep 17 00:00:00 2001 From: Sourabh19278 <79500203+SOURABHMISHRA5221@users.noreply.github.com> Date: Sat, 24 May 2025 11:56:59 +0000 Subject: [PATCH] feat(filesystem): add --ignore-write option to block writes to sensitive files (#1869) --- src/filesystem/README.md | 15 +++++++++++++++ src/filesystem/index.ts | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/filesystem/README.md b/src/filesystem/README.md index d1621d1ef3..7e2ba47bba 100644 --- a/src/filesystem/README.md +++ b/src/filesystem/README.md @@ -12,6 +12,21 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio **Note**: The server will only allow operations within directories specified via `args`. +**Security Note**: You can prevent write operations to sensitive files (such as `.env`, `.env.*`, or any custom pattern) by using the `--ignore-write` command-line argument. See below for usage. + +## Usage + +### Command-line Arguments + +``` +mcp-server-filesystem [additional-directories...] [--ignore-write ...] +``` + +- ``: One or more directories the server is allowed to access. +- `--ignore-write ...`: (Optional) List of filenames or glob patterns to block from write operations. Example: `--ignore-write .env .env.* *.secret` + +If a file matches any of the ignore patterns, write operations to that file will be blocked, even if it is inside an allowed directory. + ## API ### Resources diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index c544ff2571..3043e91109 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -17,8 +17,21 @@ import { minimatch } from 'minimatch'; // Command line argument parsing const args = process.argv.slice(2); -if (args.length === 0) { - console.error("Usage: mcp-server-filesystem [additional-directories...]"); + +// Support: mcp-server-filesystem [additional-directories...] [--ignore-write ...] +let allowedDirs: string[] = []; +let ignoreWritePatterns: string[] = []; + +const ignoreFlagIndex = args.indexOf('--ignore-write'); +if (ignoreFlagIndex !== -1) { + allowedDirs = args.slice(0, ignoreFlagIndex); + ignoreWritePatterns = args.slice(ignoreFlagIndex + 1); +} else { + allowedDirs = args; +} + +if (allowedDirs.length === 0) { + console.error("Usage: mcp-server-filesystem [additional-directories...] [--ignore-write ...]"); process.exit(1); } @@ -35,7 +48,7 @@ function expandHome(filepath: string): string { } // Store allowed directories in normalized form -const allowedDirectories = args.map(dir => +const allowedDirectories = allowedDirs.map(dir => normalizePath(path.resolve(expandHome(dir))) ); @@ -485,6 +498,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { throw new Error(`Invalid arguments for write_file: ${parsed.error}`); } const validPath = await validatePath(parsed.data.path); + // Prevent writing to files matching ignoreWritePatterns + const baseName = path.basename(validPath); + const shouldIgnore = ignoreWritePatterns.some(pattern => { + // Simple glob-like match: support *.env, .env, .env.*, etc. + if (pattern.includes('*')) { + // Convert pattern to regex + const regex = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$'); + return regex.test(baseName); + } + return baseName === pattern; + }); + if (shouldIgnore) { + throw new Error(`Write operation to file '${baseName}' is not allowed by server policy (matched ignore pattern).`); + } await fs.writeFile(validPath, parsed.data.content, "utf-8"); return { content: [{ type: "text", text: `Successfully wrote to ${parsed.data.path}` }],