MCP Roots

MCP

Definition

A client-declared filesystem scoping mechanism. The MCP client specifies which file:// URI paths (roots) a server may access. Servers declare which roots they need; clients grant a subset. Roots are a protocol-level declaration enforced by server compliance, not by OS sandboxing.

Example Usage

Declare roots: ["/home/user/project"] to limit a file-system MCP server to the workspace — preventing it from reading ~/.ssh or any path outside the project.

Why It Matters for the CCA-F Exam

CCA-F exam questions on MCP Roots test the security model, not the API. Expect scenario questions where an MCP server is given broad filesystem access and the question asks what mechanism should limit this — the answer is roots combined with least-privilege scoping. Questions also probe the limits: candidates should know that roots are a declaration/compliance mechanism, NOT a hard OS-enforced sandbox.

In Depth

MCP Roots are a filesystem scoping primitive built into the MCP protocol. They answer the question: *which parts of the filesystem is this server allowed to touch?* Understanding their security model — and their limits — is what the exam tests.

How the Declaration Works

Roots are negotiated during the MCP session. The MCP client includes a roots capability in the initialize handshake, and can call roots/list at any time to tell the server the current set of allowed paths. Each root is a URI — almost always a file:// URI for local paths. The server's code is expected to restrict all filesystem operations to within these declared roots.

Example roots declaration in a client config:

{
  "mcpServers": {
    "code-review-server": {
      "command": "node",
      "args": ["./mcp-servers/code-review/index.js"],
      "roots": [
        "file:///home/user/projects/my-app",
        "file:///home/user/projects/shared-lib"
      ]
    }
  }
}

The server may read and operate on files under /home/user/projects/my-app and /home/user/projects/shared-lib. Paths like /home/user/.ssh/id_rsa, /etc/passwd, or anything else outside those two trees are out of scope.

Concrete Path Examples

ScenarioRoots to declare
Single-repo code reviewfile:///home/user/projects/my-app
Monorepo with multiple packagesfile:///home/user/mono/packages/api, file:///home/user/mono/packages/web
Read-only build artifact serverfile:///home/user/projects/my-app/dist
Deny all filesystem access(omit roots entirely or provide an empty list)

The Critical Limit: Declared, Not OS-Enforced

This is the most exam-tested nuance. Roots are a protocol-level declaration that a *compliant* server promises to respect. They are not enforced by the operating system. A malicious or buggy server could ignore declared roots and attempt to access /etc/passwd — the OS will not stop it if the process has read permission there.

The guarantee is: a compliant, trustworthy server will stay within roots. For production environments, OS-level isolation (containers, chroot jails, network namespaces) provides the hard enforcement layer that roots cannot replace. Roots are defense-in-depth, not a security perimeter.

Dynamic Root Updates

Roots can change after the session starts. If the user opens a second project folder, the client sends a roots/list_changed notification. A well-implemented server updates its access scope without a full reconnect. This makes roots practical for multi-workspace editors where the accessible paths evolve during a session.

Frequently Asked Questions

Do roots apply to all MCP primitives, or only to resource access?

Roots are a general filesystem boundary declaration. They are most obviously relevant to Resource primitives that reference file URIs, but a Tool that reads or writes files should also respect declared roots when resolving paths. The protocol does not restrict roots to one primitive type — they define the server's allowed filesystem scope across all operations.

What happens if a server requests a root the client is unwilling to grant?

The client simply does not include the disputed path in its roots list. The server proceeds with only the roots the client provided. If the server cannot function without a denied root, it should surface a clear error in its tool or resource responses rather than silently failing or attempting to access the path anyway.

Can roots be updated after the initial connection?

Yes — the MCP protocol supports a roots list change notification. If the user's workspace changes (for example, they open a second project folder), the client sends a roots_list_changed notification, and a well-implemented server updates its access scope accordingly without requiring a full reconnect.