feat(server): add groups/list and groups/get MCP methods - #3583
Conversation
Introduce internal/group as the source of truth for a named collection of tools and prompts. Group.Initialize reuses the toolset/promptset Initialize logic; ToToolset/ToPromptset project the legacy views keyed by the group name. No existing behavior changes yet.
Embed the initialized Toolset and Promptset in Group instead of flattening their fields, so ToToolset/ToPromptset return the views with their lookup sets intact rather than rebuilding them per call.
Replace the toolset/promptset maps with an authoritative groups map and derive the toolset/promptset views from it via ToToolset/ToPromptset. Legacy kind: toolsets configs convert to tools-only groups at init, and the default nameless group holds all tools and prompts. No YAML surface change; kind: groups parsing is deferred to a follow-up.
Add parsing for `kind: group` documents (flat and nested `groups:` blocks) in UnmarshalResourceConfig, returning parsed GroupConfigs. Validate duplicate default/named groups and reject a default group that declares tools or prompts. Wire GroupConfigs through config merge, reload, and initializeGroups so kind: group definitions override same-named toolsets.
The MCP route is /{toolsetName}, so promptsetName was always empty and
GetPromptset("") returned all prompts regardless of the connected group.
Resolve the group by its URL name and use its derived toolset/promptset
views so prompts/list scopes per group.
Expose group introspection across all five protocol versions. groups/list returns named groups with descriptions, omitting the default nameless group. groups/get returns a named group's tools and prompts.
There was a problem hiding this comment.
Code Review
This pull request introduces the groups/list and groups/get MCP methods across multiple API versions, including handlers, types, and corresponding unit tests. Feedback for the vdraft package highlights the need to integrate header and metadata validation for these new endpoints, which requires updating the handler signatures, request structures, and test suites to accept and validate the header parameter.
The vdraft protocol requires every MCP method to validate request headers and metadata. Wire GROUPS_LIST/GROUPS_GET handlers to accept the header, call validateHeader/validateMetadata, and carry RequestParams on their request types.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request implements support for the "groups/list" and "groups/get" Model Context Protocol (MCP) methods across multiple API versions (v20241105, v20250326, v20250618, v20251125, and vdraft). It introduces the corresponding request and response types, registers the new method handlers, and adds comprehensive unit tests to verify their behavior, including header and metadata validation for the draft version. I have no feedback to provide as no review comments were submitted and the implementation is clean and well-tested.
Move groups/list and groups/get result shaping into GenerateListGroupsResult and GenerateGetGroupResult in manifests.go so the handlers stay thin, matching the tools/prompts pattern. Embed PaginatedRequest in ListGroupsRequest for request-type parity across all five protocol versions.
Decouple Group from the legacy tools.Toolset/prompts.Promptset types per review feedback. Group now keeps its own O(1) tool/prompt membership sets and exposes ContainsTool/ContainsPrompt directly, instead of deriving and storing full toolset/promptset views. Per-tool and per-prompt manifests are generated on demand by callers from the resolved tools/prompts maps, so the group no longer needs serverVersion at Initialize.
…ring # Conflicts: # internal/group/group.go
Pass the resolved group.Group through ProcessMethod and the version handlers instead of materialized toolset/promptset views. List handlers now read ToolNames/PromptNames directly from the group, which scopes prompts to a single group and fixes the always-empty promptset lookup.
…trospection # Conflicts: # internal/server/mcp/v20241105/method.go # internal/server/mcp/v20250326/method.go # internal/server/mcp/v20250618/method.go # internal/server/mcp/v20251125/method.go # internal/server/mcp/vdraft/method.go
Yuan325
left a comment
There was a problem hiding this comment.
Tiny feedback :) Others LGTM
…3575) ## Description Adds parsing for `kind: group` configuration documents and wires the parsed groups through initialization. Groups are the source of truth from which toolset and promptset views are derived; this PR lets users declare them directly in config. - `UnmarshalResourceConfig` now parses both flat (`kind: group`) and nested (`groups:`) formats, returning a new `GroupConfigs` value. - Validation: rejects duplicate default (nameless) or named groups, and rejects a default group that declares `tools` or `prompts` (it always contains all configured tools and prompts). - `GroupConfigs` flows through config merge, dynamic reload, and `initializeGroups`; a `kind: group` definition overrides a same-named toolset (with a warning). - Mechanically updated all `UnmarshalResourceConfig` call sites for the new return arity. Stacked on #3569 --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
…at/groups-pr2-prompt-scoping # Conflicts: # cmd/internal/config.go # cmd/internal/config_test.go # internal/server/config.go # internal/server/server.go # internal/server/server_test.go
…ompt-scoping test Rename the toolsetName Go identifier to groupName across the SSE and message handlers and processMcpMessage, since the value now names a group. The "toolsetName" route key and toolset.name telemetry attributes are unchanged. Add a doc comment to TestMcpPromptScopingByGroup clarifying it is an end-to-end test, distinct from the manifests_test.go unit test.
Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
Rename GroupDescription to Group across all five MCP version packages (v20241105, v20250326, v20250618, v20251125, vdraft) to match MCP type conventions, and add prompts-style debug logging to groupsListHandler and groupsGetHandler. Update group handler tests to inject a logger into context.
…rity A base merge reverted the signature to 7 returns (dropping ToolsetConfigs) but left call sites at the stale 8-variable shape, breaking the build.
…3-introspection # Conflicts: # internal/server/mcp/v20241105/method.go # internal/server/mcp/v20250326/method.go # internal/server/mcp/v20250618/method.go # internal/server/mcp/v20251125/method.go # internal/server/mcp/vdraft/method.go
|
🧨 Preview deployments removed. Cloudflare Pages environments for |
## Description Follow-up to #3583, adding the telemetry that was deferred out of the introspection PR to keep it focused. This mirrors the existing `prompts/get` instrumentation for `groups/get` across all five MCP version packages (`v20241105`, `v20250326`, `v20250618`, `v20251125`, `vdraft`) --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com>
Description
Adds two Toolbox methods for group introspection, implemented across all five MCP protocol versions (v20241105, v20250326, v20250618, v20251125, vdraft).
groups/list— returns named groups (name + description). The default nameless group is omitted and results are sorted by name.groups/get— returns a named group's tools and prompts. Unknown names return-32602(INVALID_PARAMS); the default group is reachable via an empty name.groups/listRequest:
{ "jsonrpc": "2.0", "id": 1, "method": "groups/list" }Response:
{ "jsonrpc": "2.0", "id": 1, "result": { "groups": [ { "name": "set_one" }, { "name": "set_two" } ] } }groups/getRequest:
{ "jsonrpc": "2.0", "id": 2, "method": "groups/get", "params": { "name": "set_two" } }Response:
{ "jsonrpc": "2.0", "id": 2, "result": { "name": "set_two", "tools": [ { "name": "tool_b", "description": "Tool B does B.", "inputSchema": { "type": "object", "properties": {}, "required": [] } }, { "name": "tool_a", "description": "Tool A does A.", "inputSchema": { "type": "object", "properties": {}, "required": [] } } ], "prompts": [] } }Unknown group:
{ "jsonrpc": "2.0", "id": 3, "method": "groups/get", "params": { "name": "nope" } }{ "jsonrpc": "2.0", "id": 3, "error": { "code": -32602, "message": "invalid group name: group with name \"nope\" does not exist" } }Stacked on #3576