Lock the full input schema of every MCP tool in specs

What does this MR do and why?

Spec-only change. Every tool the GitLab MCP server serves (CE and EE, including unlisted and REST-backed tools) now has a spec that compares its entire input_schema with eq. Any change to the agent-facing contract (new property, maxItems, required, description, enum) fails CI until someone updates the expected hash on purpose.

Motivation: ee/spec/services/mcp/tools/security/attach_scan_profile_service_spec.rb only checked types, so maxItems: 100 was added in !258207 (merged) without any spec failing. No changelog entry because the change is spec-only.

Sweep and coverage details
  1. Sweep method: built the list of served tools from Mcp::Tools::Manager.new.tools in both FOSS_ONLY=1 and EE, and dumped each tool's input_schema per registered version. Cross-checked with register_version / def input_schema in app/services/mcp/tools and ee/app/services/mcp/tools, the EE prepend modules in ee/app/services/ee/mcp/tools, and every route_setting :mcp in lib/api and ee/lib/api.

  2. Counts from the first sweep (master) and the second sweep (this branch):

    Sweep Tools served CE Tools served EE Without full eq
    master 46 56 19
    this branch 46 56 0

    The 19 distinct tools on master without a full eq:

    • 7 class-based tools with no full eq: get_repository_file, list_tags, search, attach_scan_profile, start_duo_session, send_duo_session_input, and save_vulnerability (version 0.2.0).
    • 3 more tools whose EE-served schema was only partly checked: link_work_items, list_work_items, save_work_item.
    • 9 REST-backed tools with no per-tool schema spec: fork_repository, get_issue, create_issue, get_merge_request_commits, get_merge_request_diffs, get_merge_request_pipelines, list_pipelines, get_pipeline_jobs, list_branches.
  3. Differences from the initial gap list, which was built by grepping specs for partial schema checks:

    • Added save_vulnerability 0.2.0. Only 0.1.0 was locked. Both versions share one schema, so one literal is checked against both.
    • Added the EE-served schemas of link_work_items, list_work_items, save_work_item and search. EE adds properties, and the EE specs checked them piecemeal.
    • list_wiki_pages was already fully covered.
    • The other REST routes with route_setting :mcp (create_merge_request, update_merge_request, gitlab_search_in_instance/group/project, update_pipeline, delete_pipeline, create_duo_workflow, resume_duo_workflow) are not served directly. They sit behind the aggregated tools search, save_merge_request, manage_pipeline, start_duo_session and send_duo_session_input, whose schemas are locked in those tools' specs.
  4. What changed:

    • Replaced partial schema examples with a full eq in the class-based tool specs listed above. Removed the partial checks the full eq replaces, and kept the behavior examples.
    • search in EE: its schema depends on the advanced search and exact code search settings. All four combinations are locked from a base literal plus the added properties. The CE search example runs only in FOSS (unless: Gitlab.ee?).
    • REST-backed tools: one example per tool in the request spec of its route, next to the Grape params that define the schema. fork_repository in spec/requests/api/projects_spec.rb; get_merge_request_commits, get_merge_request_diffs and get_merge_request_pipelines in spec/requests/api/merge_requests_spec.rb; list_pipelines and get_pipeline_jobs in spec/requests/api/ci/pipelines_spec.rb; list_branches in spec/requests/api/branches_spec.rb; get_issue in spec/requests/api/issues/get_project_issues_spec.rb.
    • create_issue is the only REST tool whose schema differs in EE: ee/lib/ee/api/helpers/issues_helpers.rb adds epic_id when the route is defined, whatever the license. Following the EE spec guidelines, the CE example in spec/requests/api/issues/post_projects_issues_spec.rb runs only in FOSS (unless: Gitlab.ee?), and ee/spec/requests/api/issues_spec.rb locks the EE schema. EE is CE plus epic_id, so the EE example also catches CE param changes in regular pipelines.
    • Checked that the specs catch a change: adding maxItems: 100 to attach_scan_profile's source makes its spec fail.
  5. Known exception: the existing accept_merge_request spec builds the strategy enum from AutoMergeService.all_strategies_ordered_by_preference instead of a literal, because EE adds merge train strategies. Left as is.

References

Expected conflict: that MR adds maxItems: 100 (and a combined-limit description) to attach_scan_profile. This MR asserts master's schema, so whichever merges second updates the expected hash in ee/spec/services/mcp/tools/security/attach_scan_profile_service_spec.rb.

Screenshots or screen recordings

No UI changes.

How to set up and validate locally

The change is spec-only, so running the specs is the validation.

  1. Run the changed specs in EE:

    bundle exec rspec \
      spec/requests/api/projects_spec.rb \
      spec/requests/api/merge_requests_spec.rb \
      spec/requests/api/ci/pipelines_spec.rb \
      spec/requests/api/branches_spec.rb \
      spec/requests/api/issues/get_project_issues_spec.rb \
      spec/requests/api/issues/post_projects_issues_spec.rb \
      ee/spec/requests/api/issues_spec.rb \
      spec/services/mcp/tools/search/search_service_spec.rb \
      ee/spec/services/ee/mcp/tools/search/search_service_spec.rb \
      spec/services/mcp/tools/repositories/get_repository_file_service_spec.rb \
      spec/services/mcp/tools/repositories/tags/list_tags_service_spec.rb \
      ee/spec/services/mcp/tools/security/attach_scan_profile_service_spec.rb \
      ee/spec/services/mcp/tools/security/save_vulnerability_service_spec.rb \
      ee/spec/services/mcp/tools/duo_workflows/start_duo_session_service_spec.rb \
      ee/spec/services/mcp/tools/duo_workflows/send_duo_session_input_service_spec.rb \
      ee/spec/services/ee/mcp/tools/work_items/link_work_items_service_spec.rb \
      ee/spec/services/ee/mcp/tools/work_items/list_work_items_service_spec.rb \
      ee/spec/services/ee/mcp/tools/work_items/save_work_item_service_spec.rb
  2. Run the CE ones (paths starting with spec/) with FOSS_ONLY=1.

  3. Optional: add maxItems: 100 to a property in ee/app/services/mcp/tools/security/attach_scan_profile_service.rb and confirm its spec fails.

Local results: every changed spec passes in EE and in FOSS. For the large request specs, only the new MCP tool input schemas blocks were run locally.

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.

Edited by Terri Chu

Merge request reports

Loading
Loading