Let API tools declare aliases via route settings

What does this MR do and why?

API-backed MCP tools could not declare aliases, so renaming one had no backward-compatible path. ApiTool is a single class shared by every API route, so a class-level tool_aliases would leak across all of them. This adds a per-instance ApiTool#tool_aliases sourced from the route's mcp settings, a matching instance-level reader on BaseService, and switches Manager#build_alias_map to read the instance method so all tool types resolve through one path.

Part of #606029 (closed) (MR B). Behavior-only for API tools; the existing class-based aliases (gitlab_search, gitlab_merge_request_search) are unchanged and keep resolving through the new delegator.

Update dev docs + tool builder skill

Implementation details
  • ApiTool#tool_aliases reads settings[:tool_aliases] and maps to strings, matching how tool_name is .to_s'd in discover_api_tools. Without this, a symbol alias would never match the string tool name passed to get_tool.
  • BaseService#tool_aliases delegates to the existing self.tool_aliases, so custom, GraphQL, and aggregated tools are unaffected.
  • Manager#build_alias_map now calls tool.tool_aliases instead of tool.class.tool_aliases. list_tools stays canonical-only — aliases are not added to it.
  • tool_aliases: on a route that also sets aggregators: is dead config: that route's standalone ApiTool is never registered under its own name (discover_api_tools skips aggregated routes), so its aliases are never read. Aggregated tools alias through the aggregator class's self.tool_aliases. Documented in _index.md.

References

Screenshots or screen recordings

No UI changes.

How to set up and validate locally

  1. In the Rails console, confirm the refactor preserves the existing class-based aliases:
    mgr = Mcp::Tools::Manager.new
    mgr.alias_map                              # => includes "gitlab_search" => "search"
    mgr.get_tool(name: "gitlab_search").name   # => "search"
  2. Validate the new API-tool path. Add tool_aliases: [:old_name] to any route_setting :mcp block (for example on get_issue), reload, then:
    mgr = Mcp::Tools::Manager.new
    mgr.alias_map                          # => includes "old_name" => "get_issue"
    mgr.get_tool(name: "old_name").name    # => "get_issue"
    Revert the temporary route change afterward.

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