csharp-sdk/docs/concepts/roots/roots.md
Jeff Handley ae36026695
Publish multi-version documentation site (#1727)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: bb4b44f0-f505-49c5-9878-76e2b40c7a15
Copilot-Session: 8eac1204-10ae-4319-9333-aee5dd43dcc8
2026-07-24 15:55:35 -07:00

145 lines
6.2 KiB
Markdown

---
title: Roots
author: jeffhandley
description: How to provide filesystem roots from clients to MCP servers.
uid: roots
---
## Roots
MCP [roots] allow clients to inform servers about the relevant locations in the filesystem or other hierarchical data sources. Roots are a client-provided feature&mdash;the client declares its root URIs during initialization, and the server can request them to understand the working context.
[roots]: https://modelcontextprotocol.io/specification/2025-11-25/client/roots
### Overview
Roots provide a mechanism for the client to tell the server which directories, projects, or repositories are relevant to the current session. A server might use roots to:
- Scope file searches to the user's project directories
- Understand which repositories are being worked on
- Focus operations on relevant filesystem locations
Each root is represented by a <xref:ModelContextProtocol.Protocol.Root> with a URI and an optional human-readable name.
### Declaring roots capability on the client
Clients advertise their support for roots in the capabilities sent during initialization. The roots capability is created automatically when a roots handler is provided. Configure the handler through <xref:ModelContextProtocol.Client.McpClientHandlers.RootsHandler>:
```csharp
var options = new McpClientOptions
{
Handlers = new McpClientHandlers
{
RootsHandler = (request, cancellationToken) =>
{
return ValueTask.FromResult(new ListRootsResult
{
Roots =
[
new Root
{
Uri = "file:///home/user/projects/my-app",
Name = "My Application"
},
new Root
{
Uri = "file:///home/user/projects/shared-lib",
Name = "Shared Library"
}
]
});
}
}
};
await using var client = await McpClient.CreateAsync(transport, options);
```
### Requesting roots from the server
Servers can request the client's root list using <xref:ModelContextProtocol.Server.McpServer.RequestRootsAsync*>. This is a server-to-client request, so it requires [stateful mode or stdio](xref:stateless) — it is not available in [stateless mode](xref:stateless#stateless-mode-recommended).
```csharp
[McpServerTool, Description("Lists the user's project roots")]
public static async Task<string> ListProjectRoots(McpServer server, CancellationToken cancellationToken)
{
var result = await server.RequestRootsAsync(new ListRootsRequestParams(), cancellationToken);
var summary = new StringBuilder();
foreach (var root in result.Roots)
{
summary.AppendLine($"- {root.Name ?? root.Uri}: {root.Uri}");
}
return summary.ToString();
}
```
### Roots change notifications
When the set of roots changes (for example, the user opens a new project), the client notifies the server so it can update its understanding of the working context.
#### Sending change notifications from the client
Roots change notifications are automatically sent when the client's roots handler is updated. However, clients can also send the notification explicitly:
```csharp
await mcpClient.SendNotificationAsync(
NotificationMethods.RootsListChangedNotification,
new RootsListChangedNotificationParams());
```
#### Handling change notifications on the server
Servers can register a handler to respond when the client's roots change:
```csharp
server.RegisterNotificationHandler(
NotificationMethods.RootsListChangedNotification,
async (notification, cancellationToken) =>
{
// Re-request the roots list to get the updated set
var result = await server.RequestRootsAsync(new ListRootsRequestParams(), cancellationToken);
Console.WriteLine($"Roots updated. {result.Roots.Count} roots available.");
});
```
### Multi round-trip requests (MRTR)
[MRTR](xref:mrtr) is the SEP-2322 mechanism for server-driven input requests, finalized in protocol revision `2026-07-28`. In that revision, the server-to-client `roots/list` request method is removed; the recommended way to ask the client for its roots from a server handler is to throw <xref:ModelContextProtocol.Protocol.InputRequiredException> and let the SDK emit an <xref:ModelContextProtocol.Protocol.InputRequiredResult> on the wire.
> [!IMPORTANT]
> `RequestRootsAsync` throws `InvalidOperationException("Roots are not supported in stateless mode.")` whenever the server is running stateless — including Streamable HTTP requests served under `2026-07-28` with `Stateless = true`. Stdio servers and initialize-handshake stateful Streamable HTTP sessions continue to work via the initialize-era server-to-client `roots/list` request flow; an HTTP server set to `Stateless = false` refuses `2026-07-28` so dual-path clients can fall back before using that flow. For code that needs to run on stateless servers — including `2026-07-28` Streamable HTTP — throw `InputRequiredException` from your handler instead. It works under both protocols and both session modes.
For example:
```csharp
[McpServerTool, Description("Tool that requests roots via MRTR")]
public static string ListRootsWithMrtr(
McpServer server,
RequestContext<CallToolRequestParams> context)
{
// On retry, process the client's roots response
if (context.Params!.InputResponses?.TryGetValue("get_roots", out var response) is true)
{
var roots = response.Deserialize(InputResponse.ListRootsResultJsonTypeInfo)?.Roots ?? [];
return $"Found {roots.Count} roots: {string.Join(", ", roots.Select(r => r.Uri))}";
}
if (!server.IsMrtrSupported)
{
return "This tool requires MRTR support (2026-07-28, or a stateful session using protocol revision 2025-11-25).";
}
// First call — request the client's root list
throw new InputRequiredException(
inputRequests: new Dictionary<string, InputRequest>
{
["get_roots"] = InputRequest.ForRootsList(new ListRootsRequestParams())
},
requestState: "awaiting-roots");
}
```
> [!TIP]
> For the full protocol details, including load shedding, multiple round trips, and the compatibility matrix, see [Multi Round-Trip Requests (MRTR)](xref:mrtr).