From b1690aaf3c69c281187e6f4a2354bdc1986af251 Mon Sep 17 00:00:00 2001 From: Tapan Chugh Date: Mon, 29 Sep 2025 23:22:23 -0700 Subject: [PATCH 1/2] Making roots a server capability (GH Issue #1410) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace notification-based roots with synchronous roots/set method - Move roots from ClientCapabilities to ServerCapabilities - Remove roots/list and notifications/roots/list_changed - Add client-to-server roots/set request that returns EmptyResult 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/specification/draft/schema.mdx | 30 ++----- schema/draft/schema.json | 131 ++++++++-------------------- schema/draft/schema.ts | 65 ++++---------- 3 files changed, 64 insertions(+), 162 deletions(-) diff --git a/docs/specification/draft/schema.mdx b/docs/specification/draft/schema.mdx index 04274ce88..fa789b2a8 100644 --- a/docs/specification/draft/schema.mdx +++ b/docs/specification/draft/schema.mdx @@ -27,7 +27,7 @@ the data is entirely optional.

interface ClientCapabilities {
  elicitation?: object;
  experimental?: { [key: string]: object };
  roots?: { listChanged?: boolean };
  sampling?: object;
}

Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.

elicitation?: object

Present if the client supports elicitation from the server.

experimental?: { [key: string]: object }

Experimental, non-standard capabilities that the client supports.

roots?: { listChanged?: boolean }

Present if the client supports listing roots.

Type declaration
  • OptionallistChanged?: boolean

    Whether the client supports notifications for changes to the roots list.

sampling?: object

Present if the client supports sampling from an LLM.

+
interface ClientCapabilities {
  elicitation?: object;
  experimental?: { [key: string]: object };
  sampling?: object;
}

Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.

elicitation?: object

Present if the client supports elicitation from the server.

experimental?: { [key: string]: object }

Experimental, non-standard capabilities that the client supports.

sampling?: object

Present if the client supports sampling from an LLM.

### `ContentBlock` @@ -198,7 +198,7 @@ other URI schemes.

interface ServerCapabilities {
  completions?: object;
  experimental?: { [key: string]: object };
  logging?: object;
  prompts?: { listChanged?: boolean };
  resources?: { listChanged?: boolean; subscribe?: boolean };
  tools?: { listChanged?: boolean };
}

Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.

completions?: object

Present if the server supports argument autocompletion suggestions.

experimental?: { [key: string]: object }

Experimental, non-standard capabilities that the server supports.

logging?: object

Present if the server supports sending log messages to the client.

prompts?: { listChanged?: boolean }

Present if the server offers any prompt templates.

Type declaration
  • OptionallistChanged?: boolean

    Whether this server supports notifications for changes to the prompt list.

resources?: { listChanged?: boolean; subscribe?: boolean }

Present if the server offers any resources to read.

Type declaration
  • OptionallistChanged?: boolean

    Whether this server supports notifications for changes to the resource list.

  • Optionalsubscribe?: boolean

    Whether this server supports subscribing to resource updates.

tools?: { listChanged?: boolean }

Present if the server offers any tools to call.

Type declaration
  • OptionallistChanged?: boolean

    Whether this server supports notifications for changes to the tool list.

+
interface ServerCapabilities {
  completions?: object;
  experimental?: { [key: string]: object };
  logging?: object;
  prompts?: { listChanged?: boolean };
  resources?: { listChanged?: boolean; subscribe?: boolean };
  roots?: object;
  tools?: { listChanged?: boolean };
}

Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.

completions?: object

Present if the server supports argument autocompletion suggestions.

experimental?: { [key: string]: object }

Experimental, non-standard capabilities that the server supports.

logging?: object

Present if the server supports sending log messages to the client.

prompts?: { listChanged?: boolean }

Present if the server offers any prompt templates.

Type declaration
  • OptionallistChanged?: boolean

    Whether this server supports notifications for changes to the prompt list.

resources?: { listChanged?: boolean; subscribe?: boolean }

Present if the server offers any resources to read.

Type declaration
  • OptionallistChanged?: boolean

    Whether this server supports notifications for changes to the resource list.

  • Optionalsubscribe?: boolean

    Whether this server supports subscribing to resource updates.

roots?: object

Present if the server supports accepting roots from the client.

tools?: { listChanged?: boolean }

Present if the server offers any tools to call.

Type declaration
  • OptionallistChanged?: boolean

    Whether this server supports notifications for changes to the tool list.

### `StringSchema` @@ -312,14 +312,6 @@ Contains values matching the requested schema.

interface ResourceUpdatedNotification {
  method: "notifications/resources/updated";
  params: { uri: string };
}

A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.

params: { uri: string }
Type declaration
  • uri: string

    The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.

-## `notifications/roots/list_changed` - -### `RootsListChangedNotification` - -
interface RootsListChangedNotification {
  method: "notifications/roots/list_changed";
  params?: { _meta?: { [key: string]: unknown }; [key: string]: unknown };
}

A notification from the client to the server, informing it that the list of roots has changed. -This notification should be sent whenever the client adds, removes, or modifies any root. -The server should then request an updated list of roots using the ListRootsRequest.

params?: { _meta?: { [key: string]: unknown }; [key: string]: unknown }
Type declaration
  • [key: string]: unknown
  • Optional_meta?: { [key: string]: unknown }

    See General fields: _meta for notes on _meta usage.

- ## `notifications/tools/list_changed` ### `ToolListChangedNotification` @@ -400,21 +392,13 @@ If present, there may be more results available.

interface UnsubscribeRequest {
  method: "resources/unsubscribe";
  params: { uri: string };
}

Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.

params: { uri: string }
Type declaration
  • uri: string

    The URI of the resource to unsubscribe from.

-## `roots/list` - -### `ListRootsRequest` - -
interface ListRootsRequest {
  method: "roots/list";
  params?: {
    _meta?: { progressToken?: ProgressToken; [key: string]: unknown };
    [key: string]: unknown;
  };
}

Sent from the server to request a list of root URIs from the client. Roots allow -servers to ask for specific directories or files to operate on. A common example -for roots is providing a set of repositories or directories a server should operate -on.

This request is typically used when the server needs to understand the file system -structure or access specific locations that the client has permission to read from.

params?: {
  _meta?: { progressToken?: ProgressToken; [key: string]: unknown };
  [key: string]: unknown;
}
Type declaration
  • [key: string]: unknown
  • Optional_meta?: { progressToken?: ProgressToken; [key: string]: unknown }

    See General fields: _meta for notes on _meta usage.

    • OptionalprogressToken?: ProgressToken

      If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.

+## `roots/set` -### `ListRootsResult` +### `SetRootsRequest` -
interface ListRootsResult {
  _meta?: { [key: string]: unknown };
  roots: Root[];
  [key: string]: unknown;
}

The client's response to a roots/list request from the server. -This result contains an array of Root objects, each representing a root directory -or file that the server can operate on.

_meta?: { [key: string]: unknown }

See General fields: _meta for notes on _meta usage.

+
interface SetRootsRequest {
  method: "roots/set";
  params: { roots: Root[] };
}

Sent from the client to the server to set the root directories or files that the server can operate on. +This replaces the entire list of roots with the new set provided. +The server responds with EmptyResult to acknowledge the roots have been set.

params: { roots: Root[] }
Type declaration
  • roots: Root[]

    The new list of roots to set. This replaces any existing roots.

## `sampling/createMessage` diff --git a/schema/draft/schema.json b/schema/draft/schema.json index 52b0b2f02..25b541b4e 100644 --- a/schema/draft/schema.json +++ b/schema/draft/schema.json @@ -230,16 +230,6 @@ "description": "Experimental, non-standard capabilities that the client supports.", "type": "object" }, - "roots": { - "description": "Present if the client supports listing roots.", - "properties": { - "listChanged": { - "description": "Whether the client supports notifications for changes to the roots list.", - "type": "boolean" - } - }, - "type": "object" - }, "sampling": { "additionalProperties": true, "description": "Present if the client supports sampling from an LLM.", @@ -259,9 +249,6 @@ }, { "$ref": "#/definitions/ProgressNotification" - }, - { - "$ref": "#/definitions/RootsListChangedNotification" } ] }, @@ -305,6 +292,9 @@ }, { "$ref": "#/definitions/CompleteRequest" + }, + { + "$ref": "#/definitions/SetRootsRequest" } ] }, @@ -316,9 +306,6 @@ { "$ref": "#/definitions/CreateMessageResult" }, - { - "$ref": "#/definitions/ListRootsResult" - }, { "$ref": "#/definitions/ElicitResult" } @@ -1186,56 +1173,6 @@ ], "type": "object" }, - "ListRootsRequest": { - "description": "Sent from the server to request a list of root URIs from the client. Roots allow\nservers to ask for specific directories or files to operate on. A common example\nfor roots is providing a set of repositories or directories a server should operate\non.\n\nThis request is typically used when the server needs to understand the file system\nstructure or access specific locations that the client has permission to read from.", - "properties": { - "method": { - "const": "roots/list", - "type": "string" - }, - "params": { - "additionalProperties": {}, - "properties": { - "_meta": { - "additionalProperties": {}, - "description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.", - "properties": { - "progressToken": { - "$ref": "#/definitions/ProgressToken", - "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." - } - }, - "type": "object" - } - }, - "type": "object" - } - }, - "required": [ - "method" - ], - "type": "object" - }, - "ListRootsResult": { - "description": "The client's response to a roots/list request from the server.\nThis result contains an array of Root objects, each representing a root directory\nor file that the server can operate on.", - "properties": { - "_meta": { - "additionalProperties": {}, - "description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.", - "type": "object" - }, - "roots": { - "items": { - "$ref": "#/definitions/Root" - }, - "type": "array" - } - }, - "required": [ - "roots" - ], - "type": "object" - }, "ListToolsRequest": { "description": "Sent from the client to request a list of tools the server has.", "properties": { @@ -2024,30 +1961,6 @@ ], "type": "object" }, - "RootsListChangedNotification": { - "description": "A notification from the client to the server, informing it that the list of roots has changed.\nThis notification should be sent whenever the client adds, removes, or modifies any root.\nThe server should then request an updated list of roots using the ListRootsRequest.", - "properties": { - "method": { - "const": "notifications/roots/list_changed", - "type": "string" - }, - "params": { - "additionalProperties": {}, - "properties": { - "_meta": { - "additionalProperties": {}, - "description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.", - "type": "object" - } - }, - "type": "object" - } - }, - "required": [ - "method" - ], - "type": "object" - }, "SamplingMessage": { "description": "Describes a message issued to or received from an LLM API.", "properties": { @@ -2122,6 +2035,12 @@ }, "type": "object" }, + "roots": { + "additionalProperties": true, + "description": "Present if the server supports accepting roots from the client.", + "properties": {}, + "type": "object" + }, "tools": { "description": "Present if the server offers any tools to call.", "properties": { @@ -2168,9 +2087,6 @@ { "$ref": "#/definitions/CreateMessageRequest" }, - { - "$ref": "#/definitions/ListRootsRequest" - }, { "$ref": "#/definitions/ElicitRequest" } @@ -2236,6 +2152,35 @@ ], "type": "object" }, + "SetRootsRequest": { + "description": "Sent from the client to the server to set the root directories or files that the server can operate on.\nThis replaces the entire list of roots with the new set provided.\nThe server responds with EmptyResult to acknowledge the roots have been set.", + "properties": { + "method": { + "const": "roots/set", + "type": "string" + }, + "params": { + "properties": { + "roots": { + "description": "The new list of roots to set. This replaces any existing roots.", + "items": { + "$ref": "#/definitions/Root" + }, + "type": "array" + } + }, + "required": [ + "roots" + ], + "type": "object" + } + }, + "required": [ + "method", + "params" + ], + "type": "object" + }, "StringSchema": { "properties": { "description": { diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts index 379e75f83..9c9596f6b 100644 --- a/schema/draft/schema.ts +++ b/schema/draft/schema.ts @@ -218,15 +218,6 @@ export interface ClientCapabilities { * Experimental, non-standard capabilities that the client supports. */ experimental?: { [key: string]: object }; - /** - * Present if the client supports listing roots. - */ - roots?: { - /** - * Whether the client supports notifications for changes to the roots list. - */ - listChanged?: boolean; - }; /** * Present if the client supports sampling from an LLM. */ @@ -245,6 +236,10 @@ export interface ServerCapabilities { * Experimental, non-standard capabilities that the server supports. */ experimental?: { [key: string]: object }; + /** + * Present if the server supports accepting roots from the client. + */ + roots?: object; /** * Present if the server supports sending log messages to the client. */ @@ -1321,29 +1316,20 @@ export interface PromptReference extends BaseMetadata { /* Roots */ /** - * Sent from the server to request a list of root URIs from the client. Roots allow - * servers to ask for specific directories or files to operate on. A common example - * for roots is providing a set of repositories or directories a server should operate - * on. - * - * This request is typically used when the server needs to understand the file system - * structure or access specific locations that the client has permission to read from. + * Sent from the client to the server to set the root directories or files that the server can operate on. + * This replaces the entire list of roots with the new set provided. + * The server responds with EmptyResult to acknowledge the roots have been set. * - * @category roots/list + * @category roots/set */ -export interface ListRootsRequest extends Request { - method: "roots/list"; -} - -/** - * The client's response to a roots/list request from the server. - * This result contains an array of Root objects, each representing a root directory - * or file that the server can operate on. - * - * @category roots/list - */ -export interface ListRootsResult extends Result { - roots: Root[]; +export interface SetRootsRequest extends Request { + method: "roots/set"; + params: { + /** + * The new list of roots to set. This replaces any existing roots. + */ + roots: Root[]; + }; } /** @@ -1371,17 +1357,6 @@ export interface Root { _meta?: { [key: string]: unknown }; } -/** - * A notification from the client to the server, informing it that the list of roots has changed. - * This notification should be sent whenever the client adds, removes, or modifies any root. - * The server should then request an updated list of roots using the ListRootsRequest. - * - * @category notifications/roots/list_changed - */ -export interface RootsListChangedNotification extends Notification { - method: "notifications/roots/list_changed"; -} - /** * A request from the server to elicit additional information from the user via the client. * @@ -1486,20 +1461,19 @@ export type ClientRequest = | SubscribeRequest | UnsubscribeRequest | CallToolRequest - | ListToolsRequest; + | ListToolsRequest + | SetRootsRequest; /** @internal */ export type ClientNotification = | CancelledNotification | ProgressNotification - | InitializedNotification - | RootsListChangedNotification; + | InitializedNotification; /** @internal */ export type ClientResult = | EmptyResult | CreateMessageResult - | ListRootsResult | ElicitResult; /* Server messages */ @@ -1507,7 +1481,6 @@ export type ClientResult = export type ServerRequest = | PingRequest | CreateMessageRequest - | ListRootsRequest | ElicitRequest; /** @internal */ From c98443e10b3e09ca95cfee69642592c644425443 Mon Sep 17 00:00:00 2001 From: Tapan Chugh Date: Tue, 30 Sep 2025 17:18:55 -0700 Subject: [PATCH 2/2] Add ListRootsRequest and ListRootsResult to schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for clients to query the current roots from the server. - Add ListRootsRequest interface for client → server query - Add ListRootsResult interface for server response with roots array - Add ListRootsRequest to ClientRequest union - Add ListRootsResult to ServerResult union This completes the roots protocol where: - Clients set roots via SetRootsRequest (already existed) - Clients query roots via ListRootsRequest (new) - Server stores roots and returns them via ListRootsResult (new) --- schema/draft/schema.json | 56 ++++++++++++++++++++++++++++++++++++++++ schema/draft/schema.ts | 27 +++++++++++++++++-- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/schema/draft/schema.json b/schema/draft/schema.json index 25b541b4e..7302af058 100644 --- a/schema/draft/schema.json +++ b/schema/draft/schema.json @@ -295,6 +295,9 @@ }, { "$ref": "#/definitions/SetRootsRequest" + }, + { + "$ref": "#/definitions/ListRootsRequest" } ] }, @@ -1173,6 +1176,56 @@ ], "type": "object" }, + "ListRootsRequest": { + "description": "Sent from the client to query the list of root URIs currently set on the server.\nThe server responds with the list of roots that were previously set via SetRootsRequest.", + "properties": { + "method": { + "const": "roots/list", + "type": "string" + }, + "params": { + "additionalProperties": {}, + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/definitions/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "method" + ], + "type": "object" + }, + "ListRootsResult": { + "description": "The server's response to a roots/list request from the client.\nThis result contains an array of Root objects representing the root directories\nor files currently configured on the server.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "roots": { + "items": { + "$ref": "#/definitions/Root" + }, + "type": "array" + } + }, + "required": [ + "roots" + ], + "type": "object" + }, "ListToolsRequest": { "description": "Sent from the client to request a list of tools the server has.", "properties": { @@ -2123,6 +2176,9 @@ }, { "$ref": "#/definitions/CompleteResult" + }, + { + "$ref": "#/definitions/ListRootsResult" } ] }, diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts index 9c9596f6b..16edf7762 100644 --- a/schema/draft/schema.ts +++ b/schema/draft/schema.ts @@ -1332,6 +1332,27 @@ export interface SetRootsRequest extends Request { }; } +/** + * Sent from the client to query the list of root URIs currently set on the server. + * The server responds with the list of roots that were previously set via SetRootsRequest. + * + * @category roots/list + */ +export interface ListRootsRequest extends Request { + method: "roots/list"; +} + +/** + * The server's response to a roots/list request from the client. + * This result contains an array of Root objects representing the root directories + * or files currently configured on the server. + * + * @category roots/list + */ +export interface ListRootsResult extends Result { + roots: Root[]; +} + /** * Represents a root directory or file that the server can operate on. */ @@ -1462,7 +1483,8 @@ export type ClientRequest = | UnsubscribeRequest | CallToolRequest | ListToolsRequest - | SetRootsRequest; + | SetRootsRequest + | ListRootsRequest; /** @internal */ export type ClientNotification = @@ -1504,4 +1526,5 @@ export type ServerResult = | ListResourcesResult | ReadResourceResult | CallToolResult - | ListToolsResult; + | ListToolsResult + | ListRootsResult;