Skip to content

Commit da695fe

Browse files
committed
cleanup diffs and improve glob matching
1 parent 4e31b9d commit da695fe

File tree

2 files changed

+128
-21
lines changed

2 files changed

+128
-21
lines changed

src/filesystem/README.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,111 @@
1+
# Filesystem MCP Server
2+
3+
Node.js server implementing Model Context Protocol (MCP) for filesystem operations.
4+
5+
## Features
6+
7+
- Read/write files
8+
- Create/list/delete directories
9+
- Move files/directories
10+
- Search files
11+
- Get file metadata
12+
13+
**Note**: The server will only allow operations within directories specified via `args`.
14+
15+
## API
16+
17+
### Resources
18+
19+
- `file://system`: File system operations interface
20+
21+
### Tools
22+
23+
- **read_file**
24+
- Read complete contents of a file
25+
- Input: `path` (string)
26+
- Reads complete file contents with UTF-8 encoding
27+
28+
- **read_multiple_files**
29+
- Read multiple files simultaneously
30+
- Input: `paths` (string[])
31+
- Failed reads won't stop the entire operation
32+
33+
- **write_file**
34+
- Create new file or overwrite existing (exercise caution with this)
35+
- Inputs:
36+
- `path` (string): File location
37+
- `content` (string): File content
38+
39+
- **edit_file**
40+
- Make selective edits using advanced pattern matching and formatting
41+
- Features:
42+
- Line-based and multi-line content matching
43+
- Whitespace normalization with indentation preservation
44+
- Fuzzy matching with confidence scoring
45+
- Multiple simultaneous edits with correct positioning
46+
- Indentation style detection and preservation
47+
- Git-style diff output with context
48+
- Preview changes with dry run mode
49+
- Failed match debugging with confidence scores
50+
- Inputs:
51+
- `path` (string): File to edit
52+
- `edits` (array): List of edit operations
53+
- `oldText` (string): Text to search for (can be substring)
54+
- `newText` (string): Text to replace with
55+
- `dryRun` (boolean): Preview changes without applying (default: false)
56+
- `options` (object): Optional formatting settings
57+
- `preserveIndentation` (boolean): Keep existing indentation (default: true)
58+
- `normalizeWhitespace` (boolean): Normalize spaces while preserving structure (default: true)
59+
- `partialMatch` (boolean): Enable fuzzy matching (default: true)
60+
- Returns detailed diff and match information for dry runs, otherwise applies changes
61+
- Best Practice: Always use dryRun first to preview changes before applying them
62+
63+
- **create_directory**
64+
- Create new directory or ensure it exists
65+
- Input: `path` (string)
66+
- Creates parent directories if needed
67+
- Succeeds silently if directory exists
68+
69+
- **list_directory**
70+
- List directory contents with [FILE] or [DIR] prefixes
71+
- Input: `path` (string)
72+
73+
- **move_file**
74+
- Move or rename files and directories
75+
- Inputs:
76+
- `source` (string)
77+
- `destination` (string)
78+
- Fails if destination exists
79+
80+
- **search_files**
81+
- Recursively search for files/directories
82+
- Inputs:
83+
- `path` (string): Starting directory
84+
- `pattern` (string): Search pattern
85+
- `excludePatterns` (string[]): Exclude any patterns. Glob formats are supported.
86+
- Case-insensitive matching
87+
- Returns full paths to matches
88+
89+
- **get_file_info**
90+
- Get detailed file/directory metadata
91+
- Input: `path` (string)
92+
- Returns:
93+
- Size
94+
- Creation time
95+
- Modified time
96+
- Access time
97+
- Type (file/directory)
98+
- Permissions
99+
100+
- **list_allowed_directories**
101+
- List all directories the server is allowed to access
102+
- No input required
103+
- Returns:
104+
- Directories that this server can read/write from
105+
106+
## Usage with Claude Desktop
107+
Add this to your `claude_desktop_config.json`:
108+
```json
1109
{
2110
"mcpServers": {
3111
"filesystem": {
@@ -11,3 +119,8 @@
11119
}
12120
}
13121
}
122+
```
123+
124+
## License
125+
126+
This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.

src/filesystem/index.ts

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,7 @@ const server = new Server(
163163
},
164164
{
165165
capabilities: {
166-
listChanged: false,
167-
tools: {
168-
search_files: {
169-
description: "Recursively search for files/directories with optional exclude patterns",
170-
inputSchema: zodToJsonSchema(SearchFilesArgsSchema),
171-
},
172-
},
166+
tools: {},
173167
},
174168
},
175169
);
@@ -208,7 +202,7 @@ async function searchFiles(
208202
// Check if path matches any exclude pattern
209203
const relativePath = path.relative(rootPath, fullPath);
210204
const shouldExclude = excludePatterns.some(pattern => {
211-
const globPattern = pattern.startsWith('*') ? pattern : `*/${pattern}/*`;
205+
const globPattern = pattern.includes('*') ? pattern : `**/${pattern}/**`;
212206
return minimatch(relativePath, globPattern, { dot: true });
213207
});
214208

@@ -438,18 +432,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
438432
const { name, arguments: args } = request.params;
439433

440434
switch (name) {
441-
case "search_files": {
442-
const parsed = SearchFilesArgsSchema.safeParse(args);
443-
if (!parsed.success) {
444-
throw new Error(`Invalid arguments for search_files: ${parsed.error}`);
445-
}
446-
const validPath = await validatePath(parsed.data.path);
447-
const results = await searchFiles(validPath, parsed.data.pattern, parsed.data.excludePatterns);
448-
return {
449-
content: [{ type: "text", text: results.length > 0 ? results.join("\n") : "No matches found" }],
450-
};
451-
}
452-
453435
case "read_file": {
454436
const parsed = ReadFileArgsSchema.safeParse(args);
455437
if (!parsed.success) {
@@ -548,6 +530,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
548530
};
549531
}
550532

533+
case "search_files": {
534+
const parsed = SearchFilesArgsSchema.safeParse(args);
535+
if (!parsed.success) {
536+
throw new Error(`Invalid arguments for search_files: ${parsed.error}`);
537+
}
538+
const validPath = await validatePath(parsed.data.path);
539+
const results = await searchFiles(validPath, parsed.data.pattern, parsed.data.excludePatterns);
540+
return {
541+
content: [{ type: "text", text: results.length > 0 ? results.join("\n") : "No matches found" }],
542+
};
543+
}
544+
551545
case "get_file_info": {
552546
const parsed = GetFileInfoArgsSchema.safeParse(args);
553547
if (!parsed.success) {
@@ -592,6 +586,6 @@ async function runServer() {
592586
}
593587

594588
runServer().catch((error) => {
595-
console.error("Server error:", error);
589+
console.error("Fatal error running server:", error);
596590
process.exit(1);
597591
});

0 commit comments

Comments
 (0)