What are roots in MCP, and how do they let a client scope a server's filesystem access?

5 minintermediatemcprootsfilesystemscoping

Quick Answer

Roots are a way for a client to tell a server which directories (or, more generally, URI-addressable boundaries) it's allowed to operate within — for example, a client might expose only file:///home/user/projects/my-app as a root, signaling that a filesystem server should treat that as the boundary of what it should read from or write to, rather than the entire filesystem. The client responds to a server's roots/list request with its current roots, and can send notifications/roots/list_changed if the set changes (e.g., the user opens a different project folder). Roots are a hint the server is expected to respect, not an enforced sandbox — the actual OS-level access control (what the server process can technically read/write) still has to come from wherever the server runs, so roots communicate intended scope, they don't substitute for real filesystem permissions.

Detailed Answer

Roots answer a specific, narrow question. When a server operates on a filesystem-like resource, what part of it is actually the user's business?

The exchange

// Server -> Client
{"method": "roots/list"}

// Client -> Server
{"result": {"roots": [
  {"uri": "file:///home/user/projects/my-app", "name": "my-app"}
]}}

A filesystem-oriented server receiving this should treat file:///home/user/projects/my-app as its working boundary. Listing, reading, or writing files outside it means operating outside what the user intended to expose, even if the server process technically has OS-level permission to do so.

Notifying about changes

// User switches to a different project folder in the host's UI
{"method": "notifications/roots/list_changed"}
// Server should call roots/list again to get the updated set

Why "hint," not "sandbox"

Roots travel over the same JSON-RPC channel as everything else. A server has no technical mechanism forcing it to respect them — a poorly written or malicious server could simply ignore the declared roots and read files anywhere its OS-level permissions allow. Real filesystem safety for an untrusted server has to come from actual OS-level sandboxing: containerization, a restricted user account, a chroot-like boundary. Roots communicate the user's intent about scope, which a well-behaved server should honor. They aren't a substitute for genuine access control when a server isn't fully trusted.

A concrete use case

A code-editing host with multiple project folders open might expose only the currently active project as a root. Say the user asks the assistant to "find all TODO comments." A filesystem MCP server receiving that root list knows to search within that one project, rather than scanning every folder the host happens to have open. Results stay scoped to what's actually relevant, avoiding an accidental cross-project leak of file contents into an unrelated conversation.

Related Resources