|
| 1 | +--- |
| 2 | +title: "SEP-2084: Untitled" |
| 3 | +sidebarTitle: "SEP-2084: Untitled" |
| 4 | +description: "Untitled" |
| 5 | +--- |
| 6 | + |
| 7 | +import { Badge } from "/snippets/badge.mdx"; |
| 8 | + |
| 9 | +<div className="flex items-center gap-2 mb-4"> |
| 10 | + <Badge color="gray">Unknown</Badge> |
| 11 | + <Badge color="gray">Unknown</Badge> |
| 12 | +</div> |
| 13 | + |
| 14 | +| Field | Value | |
| 15 | +| ------------- | ------------------------------------------------------------------------ | |
| 16 | +| **SEP** | 2084 | |
| 17 | +| **Title** | Untitled | |
| 18 | +| **Status** | Unknown | |
| 19 | +| **Type** | Unknown | |
| 20 | +| **Created** | Unknown | |
| 21 | +| **Author(s)** | Unknown | |
| 22 | +| **Sponsor** | None | |
| 23 | +| **PR** | [#2084](https://github.com/modelcontextprotocol/specification/pull/2084) | |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Abstract |
| 28 | + |
| 29 | +This SEP proposes Groups, a new server capability and primitive, to organize tools, prompts, resources, tasks, and groups themselves, into named collections. |
| 30 | + |
| 31 | +## Motivation |
| 32 | + |
| 33 | +### What are Groups? |
| 34 | + |
| 35 | +Groups are named collections of MCP primitives: tools, prompts, resources, tasks, and other groups, organized by use cases, functionality, etc. |
| 36 | + |
| 37 | +- A productivity server could organize groups such as Email or Calendar, and present related tools, e.g. Email: ["Draft Email", "Spell Check", "Send Email"], Calendar: ["Add Participants", "Find Open Time", "Create Appointment"] |
| 38 | +- A server with many tools could separate them by functionality such as "Pull Requests", "Issues", "Actions". |
| 39 | +- A server with various reference programming resources could separate them by language, like "Python", "TypeScript, and "Kotlin". |
| 40 | + |
| 41 | +#### Groups are overlapping sets NOT hierarchies |
| 42 | + |
| 43 | +- Primitives can belong to multiple groups; for instance, if tools are grouped by use case, a `spell_check` tool might appear in both `compose_email` and `compose_document` groups. |
| 44 | +- Since groups are a primitive, they may belong to multiple groups, and so the result is **not a hierarchy** but rather, potentially overlapping sets. |
| 45 | +- Server developers should take care to avoid cyclic graphs — e.g., a group belonging to itself or to a child. |
| 46 | + |
| 47 | +#### Transitivity |
| 48 | + |
| 49 | +- Primitive A is in group B. Group B is in group C. Is primitive A implicitly in group C also? |
| 50 | +- The Transitivity of groups is a matter of client interpretation. |
| 51 | + - In the TypeScript reference implementation, the `communications` group contains `email` and `calendar` groups. |
| 52 | + - When listing the primitives in the `communications` group, I chose to have it display the contents of both children. |
| 53 | + - So `email_thank_contributor` would appear in both `email` and `communications`. |
| 54 | + - Some clients might wish to only show direct children of a group. |
| 55 | + - If a server contained cyclic graphs, configuring the client to only show the direct children of a group would short circuit the graph traversal, unless the group contains itself as a direct child, which would be an obvious mistake on the server developer's part that would likely never happen in production. |
| 56 | + |
| 57 | +#### Visibility of Groups to LLMs |
| 58 | + |
| 59 | +- Groups are simply an organizational tool available to the server developer. |
| 60 | +- It is up to clients to decide how to interpret and make use of them, e.g., for deciding what primitives to expose to LLMs or simply ignoring them. |
| 61 | +- Server developers cannot expect that clients will pass any group information to LLMs, although they may. |
| 62 | + |
| 63 | +### Why use Groups? |
| 64 | + |
| 65 | +Organizing a server's primitives by functionality or use case enables richer client workflows, wherein certain operations or settings can be applied to multiple primitives concurrently. Some use cases [identified by the community](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/1772) include: |
| 66 | + |
| 67 | +#### Client-Side & User Organization |
| 68 | + |
| 69 | +- **Client-side Filtering:** Client UIs could display a list of groups and allow users to select/deselect specific groups to interact with or ignore. Primitives from deselected groups would not be presented to the LLM. |
| 70 | + |
| 71 | +- **Library Management:** Enabling users to create and manage organized Prompt and Resource libraries that can be shared or reused across different sessions. |
| 72 | + |
| 73 | +- **Presentation and Search:** Improving how humans and AI models look up and discover tools. Grouping helps organize the interface so that relevant tools are easier to find among hundreds of options. |
| 74 | + |
| 75 | +- **Workflow-Specific Context:** Providing a model with a "set" of tools and tasks specifically curated for a particular workflow, rather than overwhelming it with every available primitive. |
| 76 | + |
| 77 | +#### Server-Side & Architectural Patterns |
| 78 | + |
| 79 | +- **Gateway Facades:** Using a Gateway Server to wrap various backend services (REST APIs, databases, or legacy systems) into a single cohesive facade. For example, a group might dynamically expose a mix of tools from different MCP servers, APIs, REST services, etc. |
| 80 | + |
| 81 | +- **Dynamic Orchestration:** Supporting the ability to add or remove groups and tools without restarting the server, which is essential for high-availability gateway environments. |
| 82 | + |
| 83 | +- **Task Management:** Grouping the new Task primitive alongside tools and prompts to manage long-running workflows, sequencing, and concurrency. |
| 84 | + |
| 85 | +#### Governance & Development Lifecycle |
| 86 | + |
| 87 | +- **Governance and Security:** Providing a standardized mechanism for server-side governance of who can access specific sets of tools and resources. |
| 88 | + |
| 89 | +- **Ecosystem Tooling:** Supporting broader developer workflows such as debugging, automated testing, and documentation by grouping related diagnostic tools together. |
| 90 | + |
| 91 | +## Specification |
| 92 | + |
| 93 | +**Recommendation:** Groups are implemented as new MCP primitive, alongside the existing ones (i.e., tools, resources, prompts, and tasks). The new primitive will have a similar schema, list method, and list changed notification. Additionally, all MCP primitives, including groups, use a new reserved `_meta` key to list the groups to which they belong. |
| 94 | + |
| 95 | +### Capability |
| 96 | + |
| 97 | +Servers that support groups MUST declare the capability during initialization, including whether list change notifications are supported. Group lists can change at runtime, and so support for listChanged notifications for each is included. |
| 98 | + |
| 99 | +```json |
| 100 | +{ |
| 101 | + "capabilities": { |
| 102 | + "groups": { |
| 103 | + "listChanged": true |
| 104 | + } |
| 105 | + } |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +### Schema |
| 110 | + |
| 111 | +```json |
| 112 | +"Group": { |
| 113 | + "properties": { |
| 114 | + "name": { |
| 115 | + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present). Must be unique.", |
| 116 | + "type": "string" |
| 117 | + }, |
| 118 | + "title": { |
| 119 | + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood.", |
| 120 | + "type": "string" |
| 121 | + }, |
| 122 | + "description": { |
| 123 | + "description": "A full, human-readable description of the group.", |
| 124 | + "type": "string" |
| 125 | + }, |
| 126 | + "_meta": { |
| 127 | + "additionalProperties": {}, |
| 128 | + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", |
| 129 | + "io.modelcontextprotocol/groups": { |
| 130 | + "description": "A list of group names containing this group.", |
| 131 | + "items": { |
| 132 | + "type": "string" |
| 133 | + }, |
| 134 | + "type": "array" |
| 135 | + }, |
| 136 | + "type": "object", |
| 137 | + }, |
| 138 | + "annotations": { |
| 139 | + "$ref": "#/$defs/Annotation", |
| 140 | + "description": "Optional additional group information.\n\nDisplay name precedence order is: title, annotations.title, then name." |
| 141 | + }, |
| 142 | + "icons": { |
| 143 | + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", |
| 144 | + "items": { |
| 145 | + "$ref": "#/$defs/Icon" |
| 146 | + }, |
| 147 | + "type": "array" |
| 148 | + } |
| 149 | + }, |
| 150 | + "required": [ |
| 151 | + "name" |
| 152 | + ], |
| 153 | + "type": "object" |
| 154 | +} |
| 155 | +``` |
| 156 | + |
| 157 | +### Reserved `_meta` Property for All Primitives |
| 158 | + |
| 159 | +Grouping of all primitives is handled in the same way, including groups themselves. |
| 160 | + |
| 161 | +For groups, tools, resources, prompts, and tasks, an optional reserved `_meta` key is used to present the list of group names to which the primitive instance belongs. |
| 162 | + |
| 163 | +By listing a primitive's groups in a reserved `_meta` property, we ensure backward compatibility. |
| 164 | + |
| 165 | +```json |
| 166 | + "io.modelcontextprotocol/groups": { |
| 167 | + "description": "A list of group names containing this [primitive name].", |
| 168 | + "items": { |
| 169 | + "type": "string" |
| 170 | + }, |
| 171 | + "type": "array" |
| 172 | + }, |
| 173 | +``` |
| 174 | + |
| 175 | +### Groups Discovery Method: groups/list |
| 176 | + |
| 177 | +Request: |
| 178 | + |
| 179 | +```json |
| 180 | +{ |
| 181 | + "jsonrpc": "2.0", |
| 182 | + "id": 2, |
| 183 | + "method": "groups/list" |
| 184 | +} |
| 185 | +``` |
| 186 | + |
| 187 | +Response: |
| 188 | + |
| 189 | +```json |
| 190 | +{ |
| 191 | + "jsonrpc": "2.0", |
| 192 | + "id": 2, |
| 193 | + "result": { |
| 194 | + "groups": [ |
| 195 | + { |
| 196 | + "name": "user", |
| 197 | + "title": "User Management Tools", |
| 198 | + "description": "Tools used for managing user accounts within the system." |
| 199 | + }, |
| 200 | + { |
| 201 | + "name": "mapping", |
| 202 | + "title": "Geospatial Mapping Tools", |
| 203 | + "description": "Tools used for map rendering, geocoding, and spatial analysis." |
| 204 | + } |
| 205 | + ] |
| 206 | + } |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +### Changes to Response Formats |
| 211 | + |
| 212 | +As mentioned above, all primitives have a new property that appears in their list result. This includes `tools/list`, `resources/list`, `resources/templates/list`, `prompts/list`, `tasks/list`. |
| 213 | +Here is an example tool definition from `tools/list` response with new groups property: |
| 214 | + |
| 215 | +```json |
| 216 | +{ |
| 217 | + "name": "calculator", |
| 218 | + "title": "Arithmetic Calculator", |
| 219 | + "description": "Perform mathematical calculations on arithmetic expressions", |
| 220 | + "inputSchema": { |
| 221 | + "type": "object", |
| 222 | + "properties": { |
| 223 | + "expression": { |
| 224 | + "type": "string", |
| 225 | + "description": "Expression to evaluate (e.g., '2 + 3 * 4')" |
| 226 | + } |
| 227 | + }, |
| 228 | + "required": ["expression"] |
| 229 | + }, |
| 230 | + "_meta": { |
| 231 | + "io.modelcontextprotocol/groups": ["arithmetic"] |
| 232 | + } |
| 233 | +} |
| 234 | +``` |
| 235 | + |
| 236 | +### Notifications |
| 237 | + |
| 238 | +#### List Changed |
| 239 | + |
| 240 | +When the list of available groups changes, servers that declared the listChanged capability SHOULD send a notification: |
| 241 | + |
| 242 | +```json |
| 243 | +{ |
| 244 | + "jsonrpc": "2.0", |
| 245 | + "method": "notifications/groups/list_changed" |
| 246 | +} |
| 247 | +``` |
| 248 | + |
| 249 | +#### Membership Changed |
| 250 | + |
| 251 | +If a primitive is added (or removed) from a group, the server SHOULD send the `list_changed` notification appropriate for that primitive. |
| 252 | + |
| 253 | +## Rationale |
| 254 | + |
| 255 | +This specification proposal was selected for its ease of understanding since it mirrors the other MCP primitives. |
| 256 | + |
| 257 | +### Alternatives Considered |
| 258 | + |
| 259 | +- **Groups as MCP Resources instead of new primitive:** A completely separate proposal where the group metadata is declared in MCP resources with a specific schema and mimeType, referenced by their URIs, e.g., `mcp://groups/{groupId}`. Servers MAY publish the group index at a URI which MUST be defined in the capabilities object during the server initialization. This proposal could reduce spec changes and implementation effort significantly, but it was not considered as intuitive. |
| 260 | + |
| 261 | +- **Primitive's group list passed in a first class `groups` property:** A variation of the proposed specification, but the list of groups to which a primitive instance belongs would be presented by a `groups` property added to the top level of each primitive's schema. |
| 262 | + This idea was discarded because it could lead to backward compatibility issues. For instance, if a server returned a tool, resource, etc, with this property to an older client which validated it against a strict schema that did not contain this property, it would most likely cause an error. |
| 263 | + Since this proposal spans all primitives, such a compatibility failure would be unacceptable. We could require SDK developers to implement a "feature flag" that suppresses the top-level groups field in all primitives after protocol version negotiation takes place if there is a mismatch. However, that would be more effort and complexity than simply using a reserved metadata key to pass the primitive's group list, which older clients would simply ignore. |
| 264 | + |
| 265 | +- **Primitive's group list as an array of Group instances not names:** A variation of the proposed specification, but the schema would reference the Groups definition instead of declaring a string (group name). This means that full Group instances would appear in the primitive's group list, significantly increasing the token count when passed to an LLM without modification. Also, beacuse groups belong to other groups, every child of a given group would carry a duplicate of the parent instance. There was discussion of mitigating the duplication on the line using libraries that perform a marshalling on send/receive, replacing the parent with a pointer to a single copy of the parent instance. This would put an unnecessary burden on SDK developers for no clear benefit, when a client can easily look up a group by name in its cached `groups/list` result. |
| 266 | + More information on this approach can be found in @scottslewis's [proposal](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/1567). |
| 267 | + |
| 268 | +- **No Grouping of Groups** - A variation of the proposed specification, but Groups cannot have a group list. Avoids any worry of graphs — e.g., a group belonging to itself or to a child. Makes groups a flat list. |
| 269 | + |
| 270 | +## Security Implications |
| 271 | + |
| 272 | +No serious implications identified. |
| 273 | + |
| 274 | +We do wish to point out that use of groups for controlling access to a set of primitives, while a stated use case, could have security implications if groups change dynamically. |
| 275 | + |
| 276 | +## Reference Implementation |
| 277 | + |
| 278 | +- **Schema Changes:** [PR #2110](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2110) |
| 279 | +- **TypeScript SDK:** [PR #1399](https://github.com/modelcontextprotocol/typescript-sdk/pull/1399) - Fully implemented with unit tests and documented client/server examples. |
| 280 | + |
| 281 | +The reference implementation's example client and server demonstrate how groups, tools, prompts, and resources can be grouped on the server, and the client can filter them by group. It manually demonstrates how an agent using the server could easily reduce the tokens placed into an LLM's context by only including the primitives in one or more groups rather than providing the full list. |
| 282 | + |
| 283 | +Note: Tasks are not included in the example as they are ephemeral, but the SDK changes do support grouping of tasks. |
| 284 | + |
| 285 | +## Acknowledgements |
| 286 | + |
| 287 | +- @cliffhall and @chughtapan thank @patwhite for his earlier work on [SEP-1300](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1300) where a version of this grouping approach was first proposed. |
| 288 | +- And thanks to @scottslewis for rounding up [use cases](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/1772) for grouping and providing input on alternative implementations. |
| 289 | +- Thanks also to @bdoyle0182, @LucaButBoring, and @SamMorrowDrums for providing feedback and opinions in Discord and meetings. |
0 commit comments