Skip to content

Commit 32dd684

Browse files
feat(filesystem): add --ignore-write option to block writes to sensitive files (#1869)
1 parent cf64b23 commit 32dd684

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

src/filesystem/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio
1212

1313
**Note**: The server will only allow operations within directories specified via `args`.
1414

15+
**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.
16+
17+
## Usage
18+
19+
### Command-line Arguments
20+
21+
```
22+
mcp-server-filesystem <allowed-directory> [additional-directories...] [--ignore-write <pattern1> <pattern2> ...]
23+
```
24+
25+
- `<allowed-directory>`: One or more directories the server is allowed to access.
26+
- `--ignore-write <pattern1> <pattern2> ...`: (Optional) List of filenames or glob patterns to block from write operations. Example: `--ignore-write .env .env.* *.secret`
27+
28+
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.
29+
1530
## API
1631

1732
### Resources

src/filesystem/index.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,21 @@ import { minimatch } from 'minimatch';
1717

1818
// Command line argument parsing
1919
const args = process.argv.slice(2);
20-
if (args.length === 0) {
21-
console.error("Usage: mcp-server-filesystem <allowed-directory> [additional-directories...]");
20+
21+
// Support: mcp-server-filesystem <allowed-directory> [additional-directories...] [--ignore-write <pattern1> <pattern2> ...]
22+
let allowedDirs: string[] = [];
23+
let ignoreWritePatterns: string[] = [];
24+
25+
const ignoreFlagIndex = args.indexOf('--ignore-write');
26+
if (ignoreFlagIndex !== -1) {
27+
allowedDirs = args.slice(0, ignoreFlagIndex);
28+
ignoreWritePatterns = args.slice(ignoreFlagIndex + 1);
29+
} else {
30+
allowedDirs = args;
31+
}
32+
33+
if (allowedDirs.length === 0) {
34+
console.error("Usage: mcp-server-filesystem <allowed-directory> [additional-directories...] [--ignore-write <pattern1> <pattern2> ...]");
2235
process.exit(1);
2336
}
2437

@@ -35,7 +48,7 @@ function expandHome(filepath: string): string {
3548
}
3649

3750
// Store allowed directories in normalized form
38-
const allowedDirectories = args.map(dir =>
51+
const allowedDirectories = allowedDirs.map(dir =>
3952
normalizePath(path.resolve(expandHome(dir)))
4053
);
4154

@@ -485,6 +498,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
485498
throw new Error(`Invalid arguments for write_file: ${parsed.error}`);
486499
}
487500
const validPath = await validatePath(parsed.data.path);
501+
// Prevent writing to files matching ignoreWritePatterns
502+
const baseName = path.basename(validPath);
503+
const shouldIgnore = ignoreWritePatterns.some(pattern => {
504+
// Simple glob-like match: support *.env, .env, .env.*, etc.
505+
if (pattern.includes('*')) {
506+
// Convert pattern to regex
507+
const regex = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$');
508+
return regex.test(baseName);
509+
}
510+
return baseName === pattern;
511+
});
512+
if (shouldIgnore) {
513+
throw new Error(`Write operation to file '${baseName}' is not allowed by server policy (matched ignore pattern).`);
514+
}
488515
await fs.writeFile(validPath, parsed.data.content, "utf-8");
489516
return {
490517
content: [{ type: "text", text: `Successfully wrote to ${parsed.data.path}` }],

0 commit comments

Comments
 (0)