What is Root?
A `Root` is the unit of scope that a client communicates to servers during a session. Each root holds exactly two fields: a mandatory `uri` (typically a `file://` path, but any URI scheme is legal) and an optional human-readable `name`. Together, a list of roots forms the bounding box for everything the server is expected to care about — the open project folders, a mounted network share, or a custom `workspace://` scheme are all valid shapes. The interface lives in `modelcontextprotocol/types` and is returned as `Root[]` through the `roots/list` request.
In the MCP message flow, roots enter the picture after `initialize` completes. The server calls `roots/list` (a server-to-client request, unusually) to retrieve the current list, caches it, and uses those prefixes when deciding which paths to surface as resources and which tool arguments to accept. If the client declared `roots.listChanged: true` in its capabilities, it will emit `notifications/roots/list_changed` whenever the workspace changes — for example when the user opens or closes a folder — and the server should re-call `roots/list` at that point.
The design is deliberately minimal. There is no nesting, no glob syntax, and no permission level attached to a root. A single `uri` + optional `name` tuple keeps parsing trivial and the protocol transport lightweight. This simplicity is intentional: the spec explicitly frames roots as advisory hints, not an access-control layer. The host process owns enforcement; the server is only expected to be a good citizen and stay within the hinted scope.
When to use
Whenever the client wants to scope server access to specific paths.
When NOT to use
As a security mechanism — use sandboxing or process isolation.
Notes
Roots are advisory, not a security boundary
Servers that read `uri` and use it as a trust perimeter are misconfigured. A malicious or buggy server can ignore roots entirely and attempt to access any path it has OS-level permission to reach. The host process — via OS sandboxing, chroot, or virtual filesystem — is the correct enforcement layer. Never rely on a server honouring roots for confidentiality or integrity guarantees.
URI scheme is not restricted to file://
The spec allows any URI scheme in `uri`, so clients can expose `workspace://`, `git://`, or custom schemes to servers that understand them. In practice, nearly all deployed clients today send `file://` paths. Servers that only understand `file://` should silently skip roots with unrecognised schemes rather than erroring, because clients are free to mix schemes in one session.
Cache roots; do not re-fetch on every request
The `roots/list` round-trip adds latency and the response is stable between `notifications/roots/list_changed` events. Production servers should fetch once post-initialize, store the list in session state, and invalidate only on the change notification. Fetching roots inside a hot tool call path is a common early implementation mistake that shows up as measurable p99 latency spikes.
listChanged capability must be declared before emitting the notification
Clients that send `notifications/roots/list_changed` without advertising `roots: { listChanged: true }` in their `ClientCapabilities` violate the protocol. Servers are entitled to ignore or log-and-discard that notification if the capability was absent during `initialize`. When writing a client, always mirror the `listChanged` flag in `ClientCapabilities.roots` when you plan to emit the notification.
name field affects UX, not routing
The optional `name` string is purely presentational — IDEs pass the project name here so servers can surface it in progress messages or resource titles. It has no semantic role in URI matching or scope calculations. Some SDK wrappers default to the last path segment of `uri` when `name` is omitted, which is fine for display but you should not parse `name` to reconstruct the path.
Fields
| Field | Type | Required | Purpose |
|---|---|---|---|
| uri | string | yes | Root URI (often file:// or a custom scheme). |
| name | string? | no | Friendly label. |
Examples
Workspace root
{ "uri": "file:///Users/alice/projects/myapp", "name": "myapp" }
Common mistakes
❌ Relying on roots for security
✅ Roots are advisory — enforce boundaries in the host process.