Skip to content

feat(filesystem): add --follow-symlinks and --symlink-depth options#3678

Open
CodeForgeNet wants to merge 3 commits intomodelcontextprotocol:mainfrom
CodeForgeNet:feat/filesystem-follow-symlinks
Open

feat(filesystem): add --follow-symlinks and --symlink-depth options#3678
CodeForgeNet wants to merge 3 commits intomodelcontextprotocol:mainfrom
CodeForgeNet:feat/filesystem-follow-symlinks

Conversation

@CodeForgeNet
Copy link

Closes #3457

The filesystem server currently blocks any symlink whose resolved target
falls outside the allowed directories -- no exceptions. This works well
as a default but is too rigid for common Unix workflows where symlinks
point to external storage, shared mounts, or locations managed outside
the server's root.

This PR adds two optional CLI flags: --follow-symlinks to opt in to
cross-boundary symlink resolution, and --symlink-depth=N to cap how
many hops outside allowed directories are permitted (default: 1).

The default behavior is unchanged. If you're not using these flags,
nothing about path validation is different.

Server Details

  • Server: filesystem
  • Changes to: path validation logic, CLI argument parsing, documentation

Motivation and Context

Users with symlinks into mounted drives, shared NFS paths, or external
directories kept having to add those paths to their allowed list manually.
The request was for an opt-in way to follow symlinks outside the boundary
without giving up all security enforcement.

The depth limit keeps it bounded: you choose how many hops outside the
allowed directories are acceptable before the server blocks access.

How Has This Been Tested?

13 new test cases in __tests__/symlinks.test.ts covering:

  • Symlink within allowed dir (existing behavior, unaffected)
  • Symlink outside allowed dir with flag off (existing hard block, unaffected)
  • Symlink outside allowed dir with flag on, within depth limit
  • Symlink chain exceeding max depth
  • Symlink that routes back into an allowed dir after an outside hop
  • Circular symlink detection

All existing tests (53 in path-validation.test.ts) still pass.

Breaking Changes

None. The flags are opt-in. Existing configs work exactly as before.

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the MCP Protocol Documentation
  • My changes follows MCP security best practices
  • I have updated the server's README accordingly
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

Circular symlinks are detected via a visited Set and throw a clear error
rather than looping. The depth counter only increments for hops that land
outside allowed directories -- hops within allowed dirs don't count against
the limit.

Closes modelcontextprotocol#3457

- Add followSymlinks and symlinkMaxDepth policy to lib.ts
- Modify validatePath() to use lstat + hop-by-hop resolution when enabled
- Circular symlink detection via visited Set
- Filter -- flags from dirArgs before building allowedDirectories
- 13 new test cases covering all symlink scenarios
- Default behavior unchanged (followSymlinks: false)
@CodeForgeNet
Copy link
Author

This implements the feature requested in #3457. Happy to make any changes based on feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Filesystem MCP follow symlinks option

1 participant