feat(mcpserver): add Context.assert_within_roots for server-side roots enforcement#2468
Open
NeelakandanNC wants to merge 2 commits intomodelcontextprotocol:mainfrom
Open
feat(mcpserver): add Context.assert_within_roots for server-side roots enforcement#2468NeelakandanNC wants to merge 2 commits intomodelcontextprotocol:mainfrom
NeelakandanNC wants to merge 2 commits intomodelcontextprotocol:mainfrom
Conversation
…s enforcement MCP clients declare filesystem boundaries via the Roots capability, but the SDK has never enforced them server-side. Any tool could access any path regardless of declared roots — a security gap addressed by this change. Adds assert_within_roots(path) as an async method on Context. Developers call it at the start of any tool accepting a user-provided path; it raises PermissionError if the path is outside every declared root, or if no roots are declared. Github-Issue: modelcontextprotocol#2453
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2453.
Adds
assert_within_roots(path)as an async method on theContextclass, so any FastMCP/MCPServer tool can enforce that a user-provided path stays within the filesystem boundaries the client declared via the Roots capability.Motivation and Context
MCP clients can declare roots, but the SDK never enforces them server-side. Any tool can open any path regardless of what the client declared — the check is left entirely to the tool author. This is a real security gap for filesystem-exposing servers and easy to forget.
The reference
@modelcontextprotocol/server-filesystemhas enforcement baked in, but anyone building a custom FastMCP/MCPServer doesn't get that for free.On the API design — responding to feedback on #2425: an earlier attempt at this was closed with the feedback that the proposed API (a
@within_roots_checkdecorator in a separate utility module) was "not easy to use." This PR takes a different approach based on that feedback:Contextalongsidectx.report_progress,ctx.read_resource,ctx.elicit, so it's discoverable by anyone already writing tools that take aContextPermissionErrorwith the offending path, no configuration, no opt-inBehavior:
pathlib.Path.resolve()— symlinks and relative segments are normalized before comparisonself.request_context.session.list_roots()and accepts the path if it falls within any of themPermissionErrorif the path is outside every declared root, or if no roots are declared (fail-closed)urllib.request.url2pathnameto convertfile://URIs — works on both POSIX and WindowsHow Has This Been Tested?
Five new tests in
tests/server/mcpserver/test_roots.py, exercising the real client/server path (no mocks onlist_roots):.resolve()behavior)All five pass locally. Full suite (
pytest tests/) is also green — 1166 passed, 98 skipped, 1 xfailed (existing state, unchanged by this PR).Breaking Changes
None. This is a purely additive change — a new method on an existing class. Existing tools are unaffected; the check is opt-in per tool.
Types of changes
Checklist
Additional context
The docstring on
assert_within_rootsincludes a full usage example that matches the patterns already used inreport_progress,read_resource, etc., so the method is self-documenting for anyone using hover tooltips or generated API docs.