Roots let clients expose approved filesystem boundaries to servers. They are especially important for coding assistants and other file-aware tools because they communicate scope explicitly.
Roots are not blanket trust. They help define context and intent, but servers still need to behave responsibly inside those boundaries.
A root says, "this part of the filesystem is in scope for the current work." It is not the same thing as "do anything you want with this machine."
A file-oriented server needs to know what the user is currently working on. Roots provide that scope. In many hosts, roots are set automatically from opened folders or workspaces. In others, users or admins may configure them directly.
This keeps file-aware operations grounded in current work instead of turning every request into an unbounded scan of local storage.
In the current specification, roots are represented as file URIs. Clients that support roots declare the capability during initialization and can answer roots/list requests from servers.
Clients may also send notifications when the root list changes, which matters for IDEs and desktop apps where users switch projects or open new workspaces frequently.
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"roots": [
{
"uri": "file:///C:/Users/dev/projects/portal",
"name": "portal"
}
]
}
}
Roots often shape what context a host chooses to gather or summarize for the model. If a coding assistant opens one repository, the server can scope file search, resource listing, and prompt suggestions to that repository instead of mixing in unrelated code.
This is why roots matter even when the server could technically access more. Good MCP systems use the current work boundary to reduce noise and improve trust.
The official client concepts documentation makes an important distinction: servers should respect roots, but roots are not a magic sandbox enforced by the protocol itself. A malicious or poorly written server can still behave badly if you run it.
That means roots help honest implementations act correctly and help hosts communicate scope, but they do not replace host trust decisions, code review, or local machine security.
Roots tell a server which workspace boundaries the client has approved. That sounds simple, but it is one of the most important safety ideas in local MCP systems. A server should not infer that it can inspect the whole machine just because it runs locally. It should treat the root list as the outer boundary of allowed work.
The practical mental model is a workspace envelope. Inside the envelope, the server may still need path validation, ignore rules, file-size limits, binary-file handling, and permission checks. Outside the envelope, the correct behavior is refusal. This prevents accidental leakage from home directories, credential files, neighboring repositories, and unrelated client workspaces.
Roots also help the model reason about context. Instead of saying "search my computer," the host can present a bounded project, document folder, or repository. The server can then return file paths relative to that root, which makes results easier to understand and safer to display.
A root is not a command to load every file into the model. It is permission to operate within a boundary. The server and host still need a context-selection strategy: search first, read only relevant files, summarize large directories, and ask for clarification when the requested scope is ambiguous.
For code and document work, store provenance with every returned result. A model answer that says "the config enables production mode" should be backed by the specific file, line, document version, or resource URI that provided the evidence. This keeps root-aware workflows auditable instead of turning them into hidden filesystem scraping.
A roots-aware server must defend path boundaries carefully. String-prefix checks are not enough because relative paths, symlinks, drive-letter differences, casing differences, and path traversal can all create surprises. Resolve the final path, normalize it, and verify that it remains inside an approved root before reading.
Apply deny rules inside the root as well. A user may approve a repository root, but that does not mean the server should read `.env`, private keys, dependency caches, build artifacts, or large binary files. Use ignore patterns and size limits so local context stays useful and safe.
When multiple roots exist, ask the host or user to clarify rather than guessing. A request like "summarize the config" may match several workspaces. Guessing the wrong root can leak unrelated project context or produce an incorrect answer.
Root changes should invalidate caches. If a user opens a different workspace or removes a root, old indexes and file references should not remain available as if permission still exists.
A root gives permission to operate within a boundary; it does not mean every file should enter the context window. The server should select context based on the task: search first, read targeted files, summarize large folders, and cite exact locations. This keeps answers grounded and reduces cost.
For code work, combine lexical search, file metadata, and limited reads. For document work, combine titles, headings, sections, and summaries. For mixed repositories, avoid reading dependencies and generated artifacts unless the user explicitly asks for them.
Context selection should be reproducible. Store search queries, selected paths, snippets, and versions in the trace. If the agent changes code or answers a question, reviewers should know which files influenced the decision.
Finally, remember that local files can contain prompt injection too. A README can ask the model to reveal secrets or ignore policy. Roots grant access to content, not authority to obey content.
Test a roots-aware server with normal paths, relative paths, symlinks, parent-directory traversal, large files, ignored files, and multiple workspace roots. The goal is to prove that the server reads only what the client approved and only what the task requires.
Then review context selection. Ask whether the server searches before reading, cites selected files, avoids dependency folders, and handles ambiguous workspace requests. A root boundary is useful only when context selection remains disciplined inside it.
Finally, change the root list during a session. Remove a root, add another, and verify that indexes, caches, and path references update correctly. Stale root permissions are a subtle but serious safety bug.
Roots tell a filesystem-aware server which workspaces the user approved.
{
"roots": [
{
"uri": "file:///workspace/project-a",
"name": "Project A"
}
]
}
Yes. Multi-repo and multi-folder workflows often expose several roots in a single session.
For file-sensitive workflows, often yes. Failing closed is usually better than guessing a broad scope.
Explore 500+ free tutorials across 20+ languages and frameworks.