roots.md

June 25, 2026 · View on GitHub

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—the client declares its root URIs during initialization, and the server can request them to understand the working context.

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:

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 — it is not available in stateless mode.

[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:

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:

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 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 — which includes every Streamable HTTP server under 2026-07-28 once that revision is forced to stateless-only in a future PR. Stdio servers and current-protocol stateful Streamable HTTP servers continue to work via the legacy server-to-client roots/list request flow. For code that needs to run on stateless servers — including all 2026-07-28 Streamable HTTP servers going forward — throw InputRequiredException from your handler instead. It works under both protocols and both session modes.

For example:

[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 current-protocol session).";
    }

    // 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

See Multi Round-Trip Requests (MRTR) for the full protocol details, including load shedding, multiple round trips, and the compatibility matrix.