fix(filesystem): normalize path separators in search_files results#3965
fix(filesystem): normalize path separators in search_files results#3965ianliuy wants to merge 1 commit intomodelcontextprotocol:mainfrom
Conversation
On Windows, path.relative() returns backslash-separated paths (e.g.,
src\index.ts), but minimatch expects forward slashes for glob pattern
matching (e.g., **/*.ts). This causes search_files and directory_tree
exclude patterns to fail on Windows.
Fix by normalizing relativePath to use forward slashes via
.split(path.sep).join('/') before passing to minimatch in both
searchFilesWithValidation (lib.ts) and buildTree (index.ts).
Fixes modelcontextprotocol#3517
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Yiyang Liu <37043548+ianliuy@users.noreply.github.com>
|
@claude review |
|
Claude finished @cliffhall's task in 1m 18s —— View job Code Review
Summary: This is a correct, minimal, low-risk fix for a real Windows-only bug. The approach is idiomatic and appropriate. What the PR does
The fix in both locations: // Before
const relativePath = path.relative(rootPath, fullPath);
// After
const relativePath = path.relative(rootPath, fullPath).split(path.sep).join('/');On Linux/macOS What's good
Suggestions1. Missing test for the Windows path normalization scenario The existing tests mock the filesystem at a POSIX level, so on Linux CI it('matches patterns correctly even when relativePath contains backslashes', async () => {
// Simulate the Windows path.relative() output by mocking path.sep
const originalSep = path.sep;
Object.defineProperty(path, 'sep', { value: '\\', configurable: true });
try {
// ... set up mocks with backslash paths and assert minimatch matches correctly
} finally {
Object.defineProperty(path, 'sep', { value: originalSep, configurable: true });
}
});This would make the fix verifiable in CI on all platforms. 2. Consider
VerdictThe fix is correct and safe to merge. The only real gap is the lack of a platform-simulating test, but that's a "nice to have" rather than a blocker given how straightforward and well-understood the normalization is. |
What's broken?
The filesystem server's
search_filestool anddirectory_treeexclude patterns return inconsistent results across platforms. On Windows, glob patterns like**/*.tsfail to match because paths use backslashes internally.Who is affected?
Anyone using the filesystem MCP server on Windows. Linux/macOS users are unaffected since
path.sepis already/.When does it trigger?
Every time
search_filesordirectory_tree(with exclude patterns) is called on Windows. The glob patterns silently fail to match, returning incorrect results.Where is the bug?
src/filesystem/lib.ts—searchFilesWithValidation(), line computingrelativePathsrc/filesystem/index.ts—buildTree(), line computingrelativePathBoth use
path.relative()which returns backslash-separated paths on Windows (e.g.,src\index.ts), then pass them directly tominimatchwhich expects forward slashes.Why does it happen?
path.relative()uses the OS-native separator (\on Windows,/on Linux).minimatchis a glob library that operates on forward-slash paths. When backslash paths are passed to minimatch on Windows, patterns like**/*.tsdon't matchsrc\index.ts.How did we fix it?
Normalize
relativePathto forward slashes immediately after computing it:This is applied in both locations. The fix is minimal (2 lines changed) and only affects the path format used for glob matching — the returned full paths from
search_filesremain OS-native.How do we know it works?
All 57 related tests pass (lib.test.ts, directory-tree.test.ts, structured-content.test.ts including the
search_filestest). The.split(path.sep).join('/')pattern is a no-op on Linux/macOS (wherepath.sepis already/), so there's zero risk of regression on those platforms.Fixes #3517