Tool Definition & Lifecycle
An MCP server declares `roots` that grant access to broad filesystem paths (`/`, `~`, `*`) instead of a narrow project directory, expanding the blast radius of any tool bug.
MCP's `roots` declaration is the server's contract with the client about which paths it intends to access. When the contract is wide open, a path-traversal bug or prompt-injected file read becomes a full-system read instead of a directory-scoped one. Roots like `file:///` or `file:///home` mean every readable file on the host is in scope.
Clients use `roots` to gate confirmation prompts and to decide what to permit. A server that requests `/` is requesting the maximum privilege the client knows how to grant. Writing the manifest narrowly (`file:///srv/notes`) is the cheapest defense in depth available — and the one most often skipped during early development.
from mcp.server.fastmcp import FastMCP |
mcp = FastMCP( |
"notes-server", |
roots=["file:///"], # Whole filesystem in scope |
) |
from mcp.server.fastmcp import FastMCP |
from pathlib import Path |
NOTES_DIR = Path("~/notes").expanduser().resolve() |
mcp = FastMCP( |
"notes-server", |
roots=[f"file://{NOTES_DIR}"], |
) |
MCPSafe parses the `roots` argument to `FastMCP`, `McpServer`, or the equivalent SDK constructor and flags root URIs that resolve to `/`, `~`, `~/`, drive roots (`C:\\`), or contain glob characters. Roots scoped to a named subdirectory are accepted.
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now