Move MCP toolset from annotations to _meta
What does this MR do and why?
The MCP tools/list response used to merge a custom toolset key into each tool's annotations. The MCP spec defines a fixed set of annotation keys and sets aside _meta for extra metadata, which uses reverse-DNS keys. This MR moves the key:
API::Mcp::Handlers::ListTools#build_tool_datanow sends_meta: { "com.gitlab/toolset" => "<name>" }.annotationsholds only the keys the tool declares, and is left out when it's empty, the same wayBase::BaseService#to_hdoes it.- The EE
governed_tool_dataoverride now usesdeep_mergeto addanthropic/requiresUserInteraction, so Ask-tier tools keep the toolset key. - The developer docs ("Declaring a toolset") say where the toolset now appears.
Release note for external clients: the toolset moved from annotations.toolset to _meta["com.gitlab/toolset"] in tools/list.
The consumer audit in the issue found nothing that reads annotations.toolset outside in-repo specs, so the key moves without a period where both locations are sent. A repo search also turned up ee/spec/requests/api/mcp/handlers/orbit_tools_spec.rb, which used annotations.toolset to find Orbit tools. That spec is updated here.
get_mcp_server_version keeps annotations: { readOnlyHint: true }, because the service declares it on master. Only tools with empty annotations lose the key. This differs from the issue description, as the workplan points out.
References
- Resolves #633038 (closed)
- Ask-tier
_metaoverride: !258209 (merged)
Screenshots or screen recordings
Not applicable. This changes the API payload only, with no UI change.
How to set up and validate locally
- In GDK or Caproni, call
tools/liston/api/v4/mcpwith the headerX-Gitlab-Enabled-Mcp-Server-Toolsets: all. - Confirm every tool has
_meta["com.gitlab/toolset"]and thatannotationsholds only spec keys (readOnlyHint,destructiveHint, and so on). - Turn on
duo_mcp_server_governance_rule_enforcementandduo_workflow_local_tool_governance, then set one tool to Always ask on the group's Tool management tab. - Call
tools/listagain and confirm that tool's_metahas bothcom.gitlab/toolsetandanthropic/requiresUserInteraction. - Connect Claude Code or MCP Inspector and confirm the tool list loads.
Local verification
Verified against a local Caproni dev environment (gitlab-org/gitlab), following the steps above.
-
Called
tools/liston/api/v4/mcpwithX-Gitlab-Enabled-Mcp-Server-Toolsets: all. Every tool'sannotationsno longer carriestoolset; it shows up correctly in_meta["com.gitlab/toolset"]. Confirmed directly onget_mcp_server_version:"annotations": { "title": "Get MCP server version", "readOnlyHint": true, "idempotentHint": true, "openWorldHint": false }, "_meta": { "com.gitlab/toolset": "meta" } -
Ran the four spec files this MR touches (
spec/requests/api/mcp/handlers/list_tools_spec.rb,ee/spec/requests/api/mcp/handlers/list_tools_spec.rb,ee/spec/requests/api/mcp/handlers/orbit_tools_spec.rb,ee/spec/lib/ee/api/mcp/handlers/list_tools_spec.rb): 101 examples, 0 failures.
Not yet re-tested: the Ask-tier governance path (steps 3-4 above) via the Tool management UI, and connecting a live MCP client (Claude Code/MCP Inspector) per step 5 — the deep_merge fix for the governance path is covered by the passing ee/spec/lib/ee/api/mcp/handlers/list_tools_spec.rb suite above, but not separately exercised live.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.