Proposal: Primitive Groups for Tools, Resources, Prompts #1567
Replies: 34 comments 49 replies
-
|
Hi @scottslewis, |
Beta Was this translation helpful? Give feedback.
-
|
One other comment about this:
With the addition of an optional 'group' property to the Tool entity: "Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"group": {
"description": "An optional ToolGroup that this Tool is a member of",
"$ref": "#/definitions/ToolGroup"
},
...With the new ToolGroup entity in spec and server, an mcp client would get any and all ToolGroups for all the tools returned from listTools(). Old clients would ignore the new optional 'group' value, new clients would be able to use the ToolGroup for model or dev tools or etc. New versions of listTools could allow tool group name filters (for example). I'm just pointing out that tool search and filtering could be enhanced via ToolGroups, without introducing new verbs and request response types to the schema like listGroups() would require. |
Beta Was this translation helpful? Give feedback.
-
Summary: ToolGroup entity@chughtapan questioned the need for a new ToolGroups entity, and suggested that all group meta-data could be available via new fields in the existing Tool entities. I think a new entity is appropriate to contain a ToolGroup (containing a set of Tools rather than a single Tool), along with metadata for the ToolGroup itself (description and title suggested in proposal) distinct from the meta-data for the multiple Tools that the ToolGroup contains. Here's a json rendering of my first cut for ToolGroup. See below for discussion of ToolGroup.name. "ToolGroup": {
"properties": {
"name": {
"description": "required ToolGroupName object instance",
"type": "string"
},
"description": {
"description": "A description of the toolgroup intended for model usage/consumption.\n\nThis can be used by clients to improve the LLM's understanding of available toolgroups. It can be thought of like a \"hint\" to the model.",
"type": "string"
},
"title": {
"description": "A human-readable title for this toolgroup",
"type": "string"
},
"_meta": {
"additionalProperties": {},
"description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.",
"type": "object"
}
},
"required": [
"name"
],
"type": "object"
},
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"group": {
"description": "An optional ToolGroup that this Tool is a member of",
"$ref": "#/definitions/ToolGroup"
},
Summary: Names and Hierarchy@chughtapan has suggested that a uri could be used as ToolGroup.name (whether in existing Tool entity or in ToolGroup.name). Limiting to the uri path segment for reasons articulated here, I agree that a hierarchical ToolGroup name could be useful. Naming Conventions vs. SpecificationIt would be possible for a simple string to be used as the ToolGroup.name type, leaving any hierarchical organization to the Tool author/dev community. An obvious problem with this is that clients and servers will both need to be able to parse the name, and will want to use a hierarchical name in different way...e.g. for server-side organization, filtering-search, administration, and security/trust (e.g. gateways with many different tools from different developers exposed to many clients) and for client-side for dev ui/presentation/organization to model interpretation of hierarchy (e.g. the 'meaning' of categories of ToolGroups). In the short term that's why I think that having an optionally-hierarchical namespace called ToolGroupName would allow for both flexibility in ToolGroup naming...and allow conventions to be established by the dev community organically and support a minimal name structure (1 or more name 'segments) without implying a full filesystem path. That's the intended purpose of the ToolGroupName type: "ToolGroupName": {
"properties": {
"segmentName": {
"description": "An identifier for a segment of an optionally-hierarchical name",
"type": "string"
},
"parentName": {
"description": "An optional parent toolgroupname segment",
"$ref": "#/definitions/ToolGroupName"
}
},
"required": [
"segmentName"
],
"type": "object"
}This ToolGroupName could accommodate all of the following names for a ToolGroup without further schema updates: Arithmetic and many others There are limitations of the ToolGroupName. For example, any 'parent' segments (my, famous, tools)...i.e. not at the 'leaf' segment (Arithmetic) would not have any 'description' or 'title' metadata associated with them as the leaf/ToolGroup segment does. If ToolGroupName (or Namespace more generally if desired) was added, then new optional fields...such as and title could be added to ToolGroupName. |
Beta Was this translation helpful? Give feedback.
-
|
After writing the previous summary comments, I had a thought of an alternative design for ToolGroups
2 this allows for a true nested ToolGroup structure, of arbitrary depth, allowing every level of the hierarchy to (optionally) have a description and title. Here's what the schema would look like: "ToolGroup": {
"properties": {
"name": {
"description": "required ToolGroup name",
"type": "string"
},
"parent": {
"$ref": "#/definitions/ToolGroup",
"description": "Optional parent ToolGroup, allowing arbitrary nesting of ToolGroups"
},
"description": {
"description": "A description of the toolgroup intended for model usage/consumption.\n\nThis can be used by clients to improve the LLM's understanding of available toolgroups. It can be thought of like a \"hint\" to the model.",
"type": "string"
},
"title": {
"description": "A human-readable title for this toolgroup",
"type": "string"
},
"_meta": {
"additionalProperties": {},
"description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.",
"type": "object"
}
},
"required": [
"name"
],
"type": "object"
}This ToolGroup entity, along with an optional property Tool.group as described here would be the entire change to the schema. No ToolGroupName type, no namespace type, etc. Just ToolGroup. This would support arbitrary hierarchies of nested ToolGroups...including an optional description and title at all levels, rather than at the leaf ToolGroups as with ToolGroupName. This would also support having Tools associated with any/all points in the hierarchy. |
Beta Was this translation helpful? Give feedback.
-
|
To test the updated schema described in the previous comment, I've implemented in the mcp-java-sdk the ToolGroup type @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ToolGroup( // @formatter:off
@JsonProperty("name") String name,
@JsonProperty("parent") ToolGroup parent,
@JsonProperty("description") String description,
@JsonProperty("title") String title,
@JsonProperty("_meta") Map<String, Object> meta) { // @formatter:on
//Builder code deleted
}The complete file is here To further test this implementation, I've added an @McpToolGroup annotation to the mcp-annotations project @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface McpToolGroup {
/**
* The name of the toolgroup. If not provided, the fully qualified ElementType.TYPE
* will be used.
*/
String name() default "";
/**
* The title of the toolgroup. If not provided, will be empty.
*/
String title() default "";
/**
* The description of the tool. If not provided, will be empty.
*/
String description() default "";
} |
Beta Was this translation helpful? Give feedback.
-
|
Based on the previous comment's additions to the mcp-java-sdk and the mcp-annotations sdk, the toolgroups_name branch on this repo shows how one can dynamically create and add mcp tools in tool groups to async and sync mcp servers. The toolgroup and it's description meta-data are specified by the use of the @McpToolGroup annotation to the ExampleToolGroup class. Using the fully qualified classname (com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup) as the ToolGroup name is an example. With the 'parent' property/field in the ToolGroup entity as above it's possible to support completely different toolgroup namespaces...e.g. com/composent/ai/mcp/examples/toolgroup/api/ExampleToolGroup...or just 1111222233334444, with no further schema changes. |
Beta Was this translation helpful? Give feedback.
-
|
@cliffhall has pointed out that as per the second item in the #1300 maintainer review here that a groups solution should 'Apply to resources and prompts' as well (in addition to tool groups). There was other relevant dialog about applying groups + filtering + search here. Thanks @cliffhall for pointing out this feedback and discussion and it's relevance to Tool Groups. In light of this desired generalization of the concept of Tool Groups, I've modified the ToolGroup entity described here to be renamed simply Group. There are no new or modified fields...just name (req), parent group (opt), description (opt), title (opt), and _meta (opt). I believe that once a Group entity was added to the schema, it could then be used for resources, tools, and prompts by adding optional 'group' properties as shown for Tools here. |
Beta Was this translation helpful? Give feedback.
-
|
Just to be clearer, here is my current proposal linked to in the previous comment "Group": {
"properties": {
"name": {
"description": "required name",
"type": "string"
},
"parent": {
"$ref": "#/definitions/Group",
"description": "Optional parent Group"
},
"description": {
"description": "A description of the group intended for model usage/consumption.\n\nThis can be used by clients to improve the LLM's understanding of available toolgroups. It can be thought of like a \"hint\" to the model.",
"type": "string"
},
"title": {
"description": "A human-readable title for this group",
"type": "string"
},
"_meta": {
"additionalProperties": {},
"description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.",
"type": "object"
}
},
"required": [
"name"
],
"type": "object"
}With this new entity supported in protocol, then Group could be used for defining groupings for Tools, Resource, and Prompts. The use of a recursive definition (opt) for the 'parent' property allows developer-defined hierarchical names/namespaces for Groups. The 'description' property (opt) is intended to allow model-processing of the Group, analogous to but distinct from the Tool/Resource/Prompt description fields. The 'title' property (opt) is intended to allow human-readable names for the group...e.g. 'My Group'. Again analogous to Tool.annotation.title. The '_meta' property is used with other mcp entities to allow for other meta-data associated with a given Group. |
Beta Was this translation helpful? Give feedback.
-
|
In the Group proposal given above the parent field is declared with a recursive reference to the Group type "parent": {
"$ref": "#/definitions/Group",
"description": "Optional parent Group"
},Comments: parent is recursive and optional. This is a powerful mechanism that has several implications: a) Backward compatibility...if a Tool (e.g.) has a group of null/default, then any tools that are put into that group (on Tool construction) can use the Tool.name for server-side lookup and continue to use as tools as it does currently. b) Arbitrary hierarchies of groups in groups can be easily created by developers, with a null Group.parent as terminator. Given that Group.name is the only required Group attribute, this allows a very flexible creation of namespaces for both public and private usage. Existing and new hierarchical name/namespace syntaxes are possible without further protocol change. c) It also allows a definition of namespaces incrementally (e.g. by community convention) rather than limiting to a specific namespace syntax immediately. At some point there may be a desire to standardize namespace syntax (e.g. using a particular naming syntax and a specific Group.name separator...e.g. '/' or '.' or other to represent the hierarchy) but as it is, in the short term the Group.name syntax can be decided by the tool and mcp server and client developers. d) Each Group optionally has a description and title (and _meta as proposed) fields. The description is intended for model/llm clients usage, and title for use by both model/llm and human/client ui. Other Group meta-data could be added, both now and in the future, by having new optional fields, but in keeping with the mcp conventions to this point, description and title seem an appropriate minimal start. e) With the recursive definition of Group.parent, an important aspect is that cycles are not allowed. If group A has parent B, and B has parent A, then there is a cycle. I'm looking at the json schema spec to see if there is a way in spec to restrict/prevent cycle creation with recursive entity definitions, but I haven't found any yet. Preventing the creation of Group->Group cycle detection more generally might be something requiring sdk (implementation) conventions and/or development/tooling conventions, if there is not a way to restrict it in the schema. Any comments or questions are welcome. |
Beta Was this translation helpful? Give feedback.
-
|
Example Usage of Group in Java MCP SDK I've added support for the Group type to a fork of the mcp-java-sdk. Using this new addition to the SDK, I've added an annotation type @McpToolGroup to a fork of the mcp-annotations project. Using both the mcp-java-sdk and the mcp-annotations, here is an example usage for dynamically generating tools meta-data using an interface class (ExampleToolGroup) that defines a tool Group and both sync and async mcp server tools contained within that Group. |
Beta Was this translation helpful? Give feedback.
-
|
Based upon online discussion and further thought, I've enhanced the use of the Group entity defined here. What I mean by 'enhanced the use' is that previously I had thought that Tools, Prompts, Resources entities could optionally be added to a single group through the use of a new, optional 'group' property...e.g. for Tool "Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"group": {
"description": "An optional Group that this Tool is a member of",
"$ref": "#/definitions/Group"
},
"_meta": {
"additionalProperties": {},
"description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.",
"type": "object"
},
...other Tool properties, description, annotations, etcThe addition of an optional 'group' property above is the only thing different from the current released schema. This has a limitation, however, of only allowing a given Tool to be in a single Group (which may be organized into a hierarchy of Groups, but may not be...based upon mcp server-defined Group structure). Allowing a List of Groups, via a 'groups' property makes this much more general and flexible: "Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"groups": {
"items": {
"$ref": "#/definitions/Group"
},
"type": "array"
},
"_meta": {
"additionalProperties": {},
"description": "See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage.",
"type": "object"
},
...other Tool properties, description, annotations, etcThe entire updated Tool schema (with 'groups' definition) is here. I've also added an identical groups property to Prompt, Resource, ResourceTemplate entities in the above draft. Here is an example implementation of this in the mcp-java-sdk. |
Beta Was this translation helpful? Give feedback.
-
|
Summary of Discussion and Proposal Changes on 10/14/2025
For reference, here is the diff between the current draft schema.json and the additions proposed above Comments, questions, or critiques welcome. |
Beta Was this translation helpful? Give feedback.
-
|
As an example of what the proposal summarized in the previous link enables, I've created a working use of dynamically created tool groups in this repo. This example uses
If the server here is started, and the client here is started the json received on the client in the ListToolsResponse is this: {
"jsonrpc": "2.0",
"id": "0fcf2111-3",
"result": {
"tools": [
{
"name": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup.add",
"title": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup.add",
"groups": [
{
"name": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup",
"description": "Arithmetic operations exposed as mcp tools"
}
],
"description": "computes the sum of the two double precision input arguments a and b",
"inputSchema": {
// deleted for brevity
},
"required": [
"x",
"y"
]
},
"annotations": {
"title": "",
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": true
}
},
{
"name": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup.multiply",
"title": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup.multiply",
"groups": [
{
"name": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup",
"description": "Arithmetic operations exposed as mcp tools"
}
],
"description": "return the product of the two given double precision arguments named a and b",
"inputSchema": {
// deleted for brevity
},
"required": [
"x",
"y"
]
},
"annotations": {
"title": "",
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": true
}
}
]
}
}Note the groups property for both tools refers to the same group object "groups": [
{
"name": "com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup",
"description": "Arithmetic operations exposed as mcp tools"
}
}In this example there is no Group.title set by the @McpToolGroup annotation, so the Group.title field is absent in the json. The name for the group in this tool grouping example is fully qualified class/type name i.e. com.composent.ai.mcp.examples.toolgroup.api.ExampleToolGroup that uses reverse dns class name/namespace convention. This Group.name and Tool.name convention is allowed by the mcp-java-sdk and mcp-annotations projects, but other naming conventions can be used for group and tool naming without further schema or impl/sdk changes. Once received by a client that is aware of the Group entity, the Group.description along with Tool.description can be used by models and/or dev tools UI. |
Beta Was this translation helpful? Give feedback.
-
|
Hi my friend, I share a similar idea — building something like a router or gateway, inspired by the wisdom of those who came before us. Did your design take into account the topic mentioned here? #1679 |
Beta Was this translation helpful? Give feedback.
-
|
As proposed here the Group.parent property allows arbitrary nested hierarchies of Group instances defined by an mcp server. With naive json object serialization, this could result in duplication of description and title field (as well as name) Group contents in response to (e.g.) listTools(). For example, if the same nested Group structure is used for 5/many Tool instances, it could result in 5/many copies of the Group,name, Group.description, and Group.title and Group.meta field contents. To avoid this data duplication it would be appropriate to use json references. Json references are used heavily in json schema, and can be used to represent the serialization of object graphs by serializing the first instance, and serializing a json reference to that first instance for all other references. As an example, the mcp-java-sdk currently uses Jackson for it's json serialization. Jackson has an annotation named @JsonIdentityInfo that has the behavior described in above paragraph...i.e. serializing the first instance of a given type, and sending references to that instance (via id) for all other copies, so that upon deserialization (on client) the Group object graph is reconstructed as it existed on the server. Here is the annotation added to the Group type in the mcp-java-sdk. This works as expected in that the server serialization serializes the contents the first time a given Group is encountered, and serializes a json reference for all other occurrences of that Group instance. For other languages, each language's json library may already have similar functionality as Jackson, or it may have to be extended to explicitly support json references. |
Beta Was this translation helpful? Give feedback.
-
|
Comment on Dynamic Groupings for MCP Servers There is an example usage of the proposed group Group primitive at the bottom of this comment and linked directly here. This example was created to show the ability (with the addition of a Groups primitive) to dynamically add and remove tools and their containing Groups to a running mcp server. The groups created in the example are defined via a @McpToolGroup annotation for an ExampleToolGroup interface class (or any type). This is not 'fully dynamic' in the sense that the 'Arithmetic' group, which contains the ('add' and 'multiply' tools), is defined at compile time...and actually built and added to the mcp server via reflection. There are projects in this repo that show the use of a proxy for a remote impl of ExampleToolGroup...for use cases where tools built on one or more networked-or-local-services can be added (and/or removed) from an mcp (gateway) server at runtime. The ability to dynamically create Groups, add/remove tools to or from those groups, and change the Group.parent/child hierarchy on the fly, allows several other use cases:
There are other potential uses of groupings of prompts, resources, and tools...e.g. groupings created for specific single or multi-user workflows. A key capability, however, is that the mcp server can dynamically created, add/remove primitives, and deleted. There are also other uses of Groups for runtime collaboration between the user, application, or model by organizing prompts, resources, and tools in the same group(s). |
Beta Was this translation helpful? Give feedback.
-
|
Summary - 10/31/2025 This proposal boils down to the addition of a single new schema/protocol primitive on par with Tools, Resources, and Prompts called Group. Here is the proposed json schema definition of Group (minus the _meta property): "Group": {
"properties": {
"name": {
"type": "string"
},
"parent": {
"$ref": "#/definitions/Group",
},
"description": {
"type": "string"
},
"title": {
"type": "string"
},
},
"required": [
"name"
],
"type": "object"
}A complete version of the json schema based upon the current draft can be found here. This Group primitive could be used for grouping Tools, Resources, and Prompts individually (e.g. a grouping of multiple Prompts only), and/or groupings of (e.g.) Prompt(s) and Tool(s) in single or multiple Groups...in essence any desired mcp-server-defined grouping of the 3 original primitives. The optional recursive Group.parent property (supporting Group hierarchy and namespaces) is described here. The parent property could be omitted This comment shows proposed a proposed (minimal) implementation of this Group in python, java, and typescript. With a full gateway use case usage of a Group primitive linked to in the same comment. This Group definition isn't meant to be complete, as the introduction of a Group primitive would likely imply new list/search/filtering capabilities for Groups as well as the other primitives. |
Beta Was this translation helpful? Give feedback.
-
|
A use case of grouping we're strugling with is governance. Agent toolkits and frameworks are starting to add governance layers over MCP such as "this agent should not perform DDL but can do DML". Since the only primitive the MCP spec provides today is the individual tools, this causes the frameworks to take hard dependencies upon individual tools. That hard dependency breaks the ability for MCP server owners to evolve tool shapes over time. Since MCP is fundamentally a dynamic protocol, we are seeing this as a significant anti-pattern. We've been hoping for a standardized mechanism to provide stable categories of tools and resources from a governance perspective while retaining the dynamic nature of MCP for future tool evolution. Do you see this groups proposal as the right tool for this problem space? |
Beta Was this translation helpful? Give feedback.
-
|
Example use cases from me. Note that much of these use cases are for human in the loop -> server interaction rather than autonomous agent -> server interaction which is the guideline for prompt / resource primitivies. I am also not deduping use cases have in my head that might already be covered across the broad comms of the groups topic.
Note, I am not arguing for an enterprise to operate out of a single mcp server. But this allows an enterprise to build an mcp server for a specific purpose that all areas of an organization can contribute to and only have to build it one time, abstracting away many other components so each team isn't building and maintaining their own. And assists with the concept of sharing primitives at different levels in the organization. For me, this is the killer use case I'm looking for so that redundant work can be removed requiring teams to deploy and manage repeat servers solving the same thing with tons of redundant logic related to requirements to have the server run in our company's environment.
This use case I want to call out because it could be tricky to implement in mcp clients with multi-groups, there's more things to consider than a traditional hierarchy where an item is a child of only one parent. Just want to make sure this is considered. I do really think that probably the most push back you'll get in review is multi-groups as it adds the most potential long term / tail potential complexity to the protocol, where i could see in the future five years from now a situation where people are saying I wish we didn't do something like multi-groups until we knew more on how we wanted to support it. So my personal leaning is build in a way that could support multi-groups as a future enablement but we don't have it in initial release; i can certainly be swayed though.
|
Beta Was this translation helpful? Give feedback.
-
|
@scottslewis I looked all through this thread and couldn't find a complete example of a group, only the schema, which appears to look like: "Group": {
"properties": {
"name": {
"type": "string"
},
"parent": {
"$ref": "#/definitions/Group",
},
"description": {
"type": "string"
},
"title": {
"type": "string"
},
},
"required": [
"name"
],
"type": "object"
}The problem I have with this is that the Instead, I think we need a unique, required |
Beta Was this translation helpful? Give feedback.
-
|
Summary - 11/25/23025 @chughtapan @cliffhall and @scottslewis discussed at the weekly working group meeting (I'll link to notes here soon) about technical issues wrt this proposal, and I wanted to record my summary of the issues here: Issues with the Recursive Group.parent field With recursive Group.parent, it's possible for mcp server devs to create hierarchies (trees...represented as object graphs in memory) of Groups. Upon json serialization (e.g. in response to mcp client requests) normally this would mean that the entire hierarchy of Groups would be serialized. Two ways to address Efficiency/Scaling issues were discussed in meeting: a) Add a (unique) id property to the Group schema definition (i.e. Group.id) and use it during serialization/deserialization b) Dynamically add a unique '@id' property with references during json serialization. b is the approach taken so far in this proposal, with a working example here uses of @JsonIdentityInfo annotation...and/or jsog or custom equivalent to serialize Groups). With sdk implementation, both a or b could address both issues 1 and 2. |
Beta Was this translation helpful? Give feedback.
-
|
A question was raised at the 11/25/2025 working group meeting : If a primitive Group type is added, how can/should it be hooked into/used by the other primitives (Tools, Resources, Prompts). Two options discussed (there may be others, these were discussed):
For both 1 and 2, this would associate a list of Groups, with the Tool created. And would provide a way for clients to get for every Tool, the object graph of Groups with that Tool (or Prompt, Resource). |
Beta Was this translation helpful? Give feedback.
-
|
Using the new SEPs-submitted as prs process, I've produced a first draft for a Group Primitive proposal Please review and comment at will. |
Beta Was this translation helpful? Give feedback.
-
Comment on SEP-1300: Tool Filtering with Groups and TagsI'd like to provide some additional considerations based on the current proposal: User-Centric, Systematic ApproachWhile the proposed groups and tags approach is valuable, I believe we need a more systematic, user-centric solution. The current proposal puts significant burden on the client/agent to understand and manage the filtering logic. Proposed Alternative Approach: Concern-Based Filtering System
Benefits of This Approach:
Example Workflow:MCP Server → Provides: ["security": "high|medium|low", "cost": "minimal|moderate|high"]
MCP Host → Sets: {"security": "high", "cost": "minimal"}
MCP Server → Returns: Subset of tools/resources/prompts that match high security and minimal cost requirementsThis concern-based approach would complement the groups/tags system by providing a higher-level, user-oriented filtering mechanism while still allowing for the technical organization that groups and tags provide. I believe combining both approaches would give us the best of both worlds: technical organization for developers and intuitive control for users. Note: I haven't been able to check existing comments due to network constraints, so please let me know if similar ideas have already been discussed. |
Beta Was this translation helpful? Give feedback.
-
|
Summary 12/10/2025 The draft pr coming out of this discussion is here. Please review/comment here, OR on the google docs copy. See under 'Groups as Primitive' tab. Also...some work from MS Research on 'Tool Interference' that could be a use case for server-side Groups/grouping |
Beta Was this translation helpful? Give feedback.
-
|
Summary 12/15/2025 @cliffhall , @chughtapan , @LucaButBoring , @a-akimov, @bdoyle0182 To simplify the Group as Primitive proposal I have removed the Group.parent property and associated text from the google doc on the 'Groups as Primitive' tab. The removal of Group.parent leaves four properties in the proposed schema for Group: name - string (unique) The removal of Group.parent property means that Groups of Groups cannot be communicated between the server and client without further schema/protocol additions. Every Group can contain any number of Tools, Resources, and/or Prompts, but cannot have sub (or super) groups. Scott requested that someone in the working group or broader community identify a few use cases (2+) that could be satisfied without hierarchical groups. For reference, here are some of the Grouping use cases publicly recorded by the community so far in a separate discussion.. Several of these use cases, however, implicitly assume trees of Groups, so may not be immediately usable for a Group primitive without hierarchical grouping. Assuming that the initial Group as Primitive SEP were to be adopted, one way to continue standardization would be to have an additional/future SEPs for hierarchical grouping via a new Group property (e.g. Group.parent) or other mechanisms. |
Beta Was this translation helpful? Give feedback.
-
|
Following this with interest. I think the tension between Groups and semantic search points to something deeper: neither quite solves the core problem of LLM decision complexity at scale. Groups organise tools but don't reduce what the LLM sees at decision time. Semantic search adds a discovery layer but that's another LLM inference step. I've been exploring a different angle: composition. What if higher-level skills compose lower-level ones? This gives you:
The hierarchy isn't just folders - it's functional abstraction. A Level 3 workflow composes Level 2 composites, which compose Level 1 atomics. Wrote up the approach here: agentskills/agentskills#13 Curious if this addresses some of the underlying needs driving this discussion. |
Beta Was this translation helpful? Give feedback.
-
|
@chughtapan @cliffhall @edu-ap There has been discussion about use of the recursively defined (in schema) parent field. I've implemented an experimental api that allows the server-side building of dynamic, arbitrary trees of GroupNodes, ToolNodes, ResourceNodes, and PromptNodes. ToolNodes, ResourceNodes, and PromptNodes are 'leaf' nodes (no children themselves), and all have methods for getting and dynamically setting the type-appropriate metadata (title, description, meta, icons for resources, etc). The GroupNode type has methods for adding and removing Group parent and children (tree structure), and children (representing the other primitives in a given Group). Any tree structure built using these classes can be serialized to the Group primitive via a converter. Here is a working example of using these classes for server-side dynamic building a tree of ToolGroups. The that uses the current mcp java sdk...with the hierarchical Group addition. These classes have no dependencies nor java-specific idioms, and so are easy to implement in other object-oriented languages. |
Beta Was this translation helpful? Give feedback.
-
|
Hello, Sorry, arriving a bit late to the conversation. Would it make sense to add an |
Beta Was this translation helpful? Give feedback.
-
|
Json Serialization of Groups/Collections MCP Servers define the Tools, Resources, and Prompts (TRP) that are exposed to clients. Upon client request, the TRP data structures are serialized to JSON and then de-serialized and validated by clients as per the MCP protocol schema. Groups are different from TRPs in that in addition to meta-data about each Group instance (e.g. unique name, title, annotations, icons, meta), Groups represent collections of the other primitives, of any desired combination (e.g. 3 Tools, 2 Resources, 1 Prompt may be defined to be in a single Group). Such collections are usually represented in object oriented programming languages as a class Group, with references to the objects (TRP class instances) currently contained by the Group. Assume we have an MCP Server with the following: 3 Tools: T1, T2, T3...with distinct values for titles, descriptions, input/output schema, annotations, etc) Three Groups: G1, G2, G3...also with appropriate values for meta-data In G1 we have T1 and T2 (collection size=2) When a mcp client connects it may request Tools, Resources, or Prompts via a mcp Request/Response combination (e.g. ListToolsRequest/ListToolsResponse). With TRPs only (no groups) the TRP instances don't refer to each other and are completely independent. As G1, G2, G3 are collections they are by referring to other TRPs: G1: T1, T2 and for G2: T1, T2, T3, R1, R2, P1, G3: R1, R2. The relations/references between Groups and their contained items have to be serialized from mcp servers and deserialized by mcp clients so that the client can reconstitute the server's object graph as given above and make it available to a model, dev, or user. Assuming json serialization, a key question is how to implement communicating TRP references/object graphs to clients. One way is have each TRP include a list of group names of Groups that contain that TRP. For example: T1.groups = ['G1', 'G2'] An important consequence of this approach (unique names) is that the actual retrieval of the Group metadata (title, description, etc) has to be done with at least one additional mcp client -> mcp server round trip. For example, in keeping with the existing primitives, a ListGroupsRequest/ListGroupsResponse message pair could be introduced. This makes it up to the client to make another client <-> server with a new round trip (request/response) to retrieve the Groups (i.e. listGroups()). This requires that the client code for resolving group names (e.g. 'G1' -> Group with all metadata) be sophisticated as mcp request/response messages are asynchronous. Another issue is that a listGroups (without some filtering) will return all groups, even if they are not needed by the client. For example, a client might only be interested in groups associated with tools (G1,G2 in the examples). The name approach also allows the possibility of the client and server to get out of sync, because of the asynchronous nature of client/server communication. Note that with Groups that can contain any of TRPs, a simple single notification (as current is in place for TRPs) will not be sufficient for groups. JSON Serialization of References Another approach would be to serialize the references between TPRGs...serializing in a single response the whole object graph of TPRGs. Most current serialization libs (e.g. pydantic for python, jackson for java, JSON.stringify for Javascript) the lib will serialized an additional copy for each reference. In the example above a ListToolsRequest would result in two copies of G1 and 3 copies of G2. Obviously, this default json 'copy on ref' strategy doesn't scale well because of the duplication created by this approach to serializing to json. It does, however, eliminate the need for additional round trips, as the ListToolsResponse would have all the Groups that all the (e.g.) Tools required (so a listGroups() might not be needed at all). The burden on the client for resolving names to objects is also much lower...i.e. no need to resolve group names into Group instances for TRPs as each of the existing TRP list requests would contain all of the relevant groups. Further, if filtering of TRP list requests were added in the future, no changes would be needed to support groups/grouping. JSON Pointers Part of the JSON specification describes JSON pointers aka rfc6901. This is a specification for sending references/json pointers as part of the json stream. It's used heavily by the json schema specification...e.g. to represent references to other schema-defined types. Apparently, the use of JSON pointers for efficient serialization of object graphs was never added to the json spec wrt serialization. By 'efficient serialization' I mean sending only the first copy of a given object in the object graph, and sending a json pointer for all the > 1 references to a given/named TPRG object graph...thus avoiding the 'copy on ref' problem described above. This is a specification called 'JRef' (JSON Reference) that extends json pointers to accept. See in the Readme.md under 'Fragments' section. JRef was defined to allow an entire URI to be used in a json pointer (with http/https retrieval of external json documents on the web). The use of simple URI fragments '#/foo/bar is all that is needed for doing full object graph serialization in mcp response messages. Here's an example of using JRef/json pointers with local (in document) references (i.e. "$ref"): {
"foo": { "$ref": "#/bar" },
"bar": 42
}Notice the use of the URI fragment identifier '#' for the in-document JRef (no further round trips required to resolve the referent since "bar" is already present in the json document). There are already typescript and python implementations of the JRef json generation/stringify...to create json with references for an object graph, and to parse+validate on the receiver side directly into an object graph. I/Scott have begun using the python JRef implementation to do implement an efficient 'by reference' json serialization of groups in the python mcp sdk. I have the typescript JRef impl also from jdesrosiers/JRef author. I can/will make it available to anyone interested in trying it out. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
There has been much discussion of grouping tools in several contexts...e.g. search/filtering PEP-1300, namespaces, tooling (annotations and decorators) and MCPToolGroups and much online discussion...e.g. discord search-tools-wg. All of these are valuable perspectives.
I think part of the difficulty is that grouping of tools has many use cases...mcp server scaling, server admin, search and filtering, model use of categories, orchestration and modularity, federation, tooling for building tools and admin ui (for human devs like inspector and others). This makes it challenging to address all or even most use cases. My preferred approach to this is take small (hopefully always backward-compatible) steps.
I would like to use this discussion to get to community consensus on what minimal protocol enhancements...now and in future will put the community on a path to supporting as many of these (and others I haven't listed above) use cases as possible.
Summary - 10/9/2025
The discussion below has led to some changes to the initial proposal. Please see this and subsequent comments
Beta Was this translation helpful? Give feedback.
All reactions