diff --git a/app/services/mcp/tools/api_tool.rb b/app/services/mcp/tools/api_tool.rb index e0128f5a62a07127c92e0e9c75f863f58996a774..7c0975a920cea099d340ba07c5eb5d0b339c162c 100644 --- a/app/services/mcp/tools/api_tool.rb +++ b/app/services/mcp/tools/api_tool.rb @@ -23,6 +23,10 @@ def initialize(route) @settings = route.app.route_setting(:mcp) end + def name + settings[:tool_name] + end + def description route.description end diff --git a/app/services/mcp/tools/fetch_gitlab_resource.rb b/app/services/mcp/tools/fetch_gitlab_resource.rb new file mode 100644 index 0000000000000000000000000000000000000000..b09c0fe9026a80b5813f868c02097eba303ebf44 --- /dev/null +++ b/app/services/mcp/tools/fetch_gitlab_resource.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Mcp + module Tools + class FetchGitlabResource + attr_reader :tools + + def self.tool_name + 'fetch_gitlab_resource' + end + + def initialize(tools) + @tools = tools + end + + def description + "Get gitlab resource like issue or merge request" + end + + def input_schema + { + type: 'object', + properties: { + id: { + type: 'string', + description: 'The global ID or URL-encoded path of the project.', + minLength: 1 + }, + iid: { + type: 'integer', + description: 'The internal ID of the project merge request.' + }, + type: { + type: 'string', + description: 'Type of Gitlab resource to fetch. Accepted values: issue, merge_request.' + } + }, + required: %w[id iid type], + additionalProperties: false + } + end + + def execute(request, params) + args = params[:arguments] + + tool = tools.find { |tool| tool.name.to_s == "get_#{args[:type]}" } + raise ArgumentError, 'type is invalid' unless tool + + case args[:type] + when 'issue' + arguments = { id: args[:id], issue_iid: args[:iid] } + when 'merge_request' + arguments = { id: args[:id], merge_request_iid: args[:iid] } + end + + params[:arguments] = arguments + + tool.execute(request, params) + end + end + end +end diff --git a/app/services/mcp/tools/manager.rb b/app/services/mcp/tools/manager.rb index 9fdd7325643b82bfdd608da7afe492b3369b3789..67e67a646abd9d5657b048260dc23b3fd2d3d104 100644 --- a/app/services/mcp/tools/manager.rb +++ b/app/services/mcp/tools/manager.rb @@ -17,14 +17,29 @@ def initialize def build_tools api_tools = {} + aggregated_api_tools = {} + ::API::API.routes.each do |route| settings = route.app.route_setting(:mcp) next if settings.blank? - api_tools[settings[:tool_name].to_s] = Mcp::Tools::ApiTool.new(route) + tool = Mcp::Tools::ApiTool.new(route) + api_tools[settings[:tool_name].to_s] = tool + + aggregators = settings[:aggregators] + next if aggregators.blank? + + aggregators.each do |aggregator| + aggregated_api_tools[aggregator] ||= [] + aggregated_api_tools[aggregator] << tool + end + end + + aggregated_tools = aggregated_api_tools.to_h do |klass, tools| + [klass.tool_name, klass.new(tools)] end - { **api_tools, **CUSTOM_TOOLS } + { **api_tools, **CUSTOM_TOOLS, **aggregated_tools } end end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index f7b907dd1bf23358e4e7ed07d0c3a4d27517c25c..54593a98783cd8e304cb5f48f587a5fc0af0145d 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -260,7 +260,7 @@ class Issues < ::API::Base params do requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue' end - route_setting :mcp, tool_name: :get_issue, params: [:id, :issue_iid] + route_setting :mcp, tool_name: :get_issue, params: [:id, :issue_iid], aggregators: [::Mcp::Tools::FetchGitlabResource] route_setting :authentication, job_token_allowed: true route_setting :authorization, job_token_policies: :read_work_items, diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 1b1321055e16cce903f71ef5a08b4ff0ad34523e..8c802095e5da7f27fd48a6b802474af32e8124a5 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -401,7 +401,7 @@ def batch_process_mergeability_checks(merge_requests) ] tags %w[merge_requests] end - route_setting :mcp, tool_name: :get_merge_request, params: [:id, :merge_request_iid] + route_setting :mcp, tool_name: :get_merge_request, params: [:id, :merge_request_iid], aggregators: [::Mcp::Tools::FetchGitlabResource] route_setting :authentication, job_token_allowed: true route_setting :authorization, job_token_policies: :read_merge_requests, allow_public_access_for_enabled_project_features: [:repository, :merge_requests]