mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-17 23:53:24 +02:00
fix(filesystem): resolve symlinked allowed directories to both forms
On macOS, /tmp is a symlink to /private/tmp. When users specify /tmp as an allowed directory, the server was resolving it to /private/tmp during startup but then rejecting paths like /tmp/file.txt because they dont start with /private/tmp. This fix stores BOTH the original normalized path AND the resolved path in allowedDirectories, so users can access files through either form. For example, with /tmp as allowed directory, both /tmp/file.txt and /private/tmp/file.txt will now be accepted. Fixes #3253
This commit is contained in:
@@ -39,22 +39,32 @@ if (args.length === 0) {
|
||||
}
|
||||
|
||||
// Store allowed directories in normalized and resolved form
|
||||
let allowedDirectories = await Promise.all(
|
||||
// We store BOTH the original path AND the resolved path to handle symlinks correctly
|
||||
// This fixes the macOS /tmp -> /private/tmp symlink issue where users specify /tmp
|
||||
// but the resolved path is /private/tmp
|
||||
let allowedDirectories = (await Promise.all(
|
||||
args.map(async (dir) => {
|
||||
const expanded = expandHome(dir);
|
||||
const absolute = path.resolve(expanded);
|
||||
const normalizedOriginal = normalizePath(absolute);
|
||||
try {
|
||||
// Security: Resolve symlinks in allowed directories during startup
|
||||
// This ensures we know the real paths and can validate against them later
|
||||
const resolved = await fs.realpath(absolute);
|
||||
return normalizePath(resolved);
|
||||
const normalizedResolved = normalizePath(resolved);
|
||||
// Return both original and resolved paths if they differ
|
||||
// This allows matching against either /tmp or /private/tmp on macOS
|
||||
if (normalizedOriginal !== normalizedResolved) {
|
||||
return [normalizedOriginal, normalizedResolved];
|
||||
}
|
||||
return [normalizedResolved];
|
||||
} catch (error) {
|
||||
// If we can't resolve (doesn't exist), use the normalized absolute path
|
||||
// This allows configuring allowed dirs that will be created later
|
||||
return normalizePath(absolute);
|
||||
return [normalizedOriginal];
|
||||
}
|
||||
})
|
||||
);
|
||||
)).flat();
|
||||
|
||||
// Validate that all directories exist and are accessible
|
||||
await Promise.all(allowedDirectories.map(async (dir) => {
|
||||
|
||||
Reference in New Issue
Block a user