[go: up one dir, main page]

Define an MCP tool via API setting

What does this MR do and why?

Define an MCP tool via API setting

We can get MCP definition from the OpenAPI route description. It'll allow us to avoid duplication. Also, calling a route directly as a middleware would allow us to avoid generating an oauth token every time.

An MCP tool definition will come down to adding the following line to a route:

       params do
         requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
       end
+      route_setting :mcp, name: :get_issue
       get ":id/issues/:issue_iid", as: :api_v4_project_issue do

Examples

POST http://gdk.test:3000/api/v4/mcp_server
jsonrpc=2.0 method=tools/list id=1
{
    "id": "1",
    "jsonrpc": "2.0",
    "result": {
        "tools": [
            {
                "description": "Get a single project issue",
                "inputSchema": {
                    "additionalProperties": false,
                    "properties": {
                        "id": {
                            "description": "The ID or URL-encoded path of the project",
                            "type": "string"
                        },
                        "issue_iid": {
                            "description": "The internal ID of a project issue",
                            "type": "integer"
                        }
                    },
                    "required": [
                        "id",
                        "issue_iid"
                    ],
                    "type": "object"
                },
                "name": "get_issue"
            },
            {
                "description": "Get single merge request",
                "inputSchema": {
                    "additionalProperties": false,
                    "properties": {
                        "id": {
                            "description": "The ID or URL-encoded path of the project.",
                            "type": "string"
                        },
                        "merge_request_iid": {
                            "description": "The internal ID of the merge request.",
                            "type": "integer"
                        }
                    },
                    "required": [
                        "id",
                        "merge_request_iid"
                    ],
                    "type": "object"
                },
                "name": "get_merge_request"
            }
        ]
    }
}
http POST http://gdk.test:3000/api/v4/mcp_server

{
  "jsonrpc": 2.0,
  "method": "tools/call",
  "id": 1,
  "params": {
    "name":"get_issue",
    "arguments": {
      "id": 25,
      "issue_iid": 1
    }
  }
}
{
    "id": 1,
    "jsonrpc": "2.0",
    "result": [
        "{\"id\":655,\"iid\":1,\"project_id\":25,\"title\":\"Rename setupTest to setup in internal/services/runner/runner_test.go\",\"description\":\"## Summary\\nThe function `setupTest` in `internal/services/runner/runner_test.go` should be renamed to `setup` for consistency and brevity.\\n\\n## Current State\\n- Function is currently named `setupTest`\\n- Located in `internal/services/runner/runner_test.go`\\n\\n## Proposed Change\\n- Rename function from `setupTest` to `setup`\\n- Update all references to use the new name\\n\\n## Benefits\\n- Shorter, cleaner function name\\n- Improved code consistency\\n- Better readability\\n\\n## Files to Update\\n- `internal/services/runner/runner_test.go`\",\"state\":\"opened\",\"created_at\":\"2025-08-04T21:16:34.230Z\",\"updated_at\":\"2025-08-15T06:08:01.610Z\",\"closed_at\":null,\"closed_by\":null,\"labels\":[\"refactor\",\"test\"],\"milestone\":null,\"assignees\":[{\"id\":1,\"username\":\"root\",\"public_email\":null,\"name\":\"Administrator\",\"state\":\"active\",\"locked\":false,\"avatar_url\":\"https://www.gravatar.com/avatar/8bf0d08f75ff3ca6381d96b1d1035f8eed7a600904fa0e44ef0553192bafd567?s=80\\u0026d=identicon\",\"web_url\":\"http://host.docker.internal:3000/root\"}],\"author\":{\"id\":1,\"username\":\"root\",\"public_email\":null,\"name\":\"Administrator\",\"state\":\"active\",\"locked\":false,\"avatar_url\":\"https://www.gravatar.com/avatar/8bf0d08f75ff3ca6381d96b1d1035f8eed7a600904fa0e44ef0553192bafd567?s=80\\u0026d=identicon\",\"web_url\":\"http://host.docker.internal:3000/root\"},\"type\":\"ISSUE\",\"assignee\":{\"id\":1,\"username\":\"root\",\"public_email\":null,\"name\":\"Administrator\",\"state\":\"active\",\"locked\":false,\"avatar_url\":\"https://www.gravatar.com/avatar/8bf0d08f75ff3ca6381d96b1d1035f8eed7a600904fa0e44ef0553192bafd567?s=80\\u0026d=identicon\",\"web_url\":\"http://host.docker.internal:3000/root\"},\"user_notes_count\":2,\"merge_requests_count\":0,\"upvotes\":0,\"downvotes\":0,\"due_date\":null,\"confidential\":false,\"discussion_locked\":null,\"issue_type\":\"issue\",\"web_url\":\"http://host.docker.internal:3000/gitlab-org/duo-workflow-executor/-/issues/1\",\"time_stats\":{\"time_estimate\":0,\"total_time_spent\":0,\"human_time_estimate\":null,\"human_total_time_spent\":null},\"task_completion_status\":{\"count\":0,\"completed_count\":0},\"weight\":null,\"blocking_issues_count\":0,\"has_tasks\":true,\"task_status\":\"0 of 0 checklist items completed\",\"_links\":{\"self\":\"http://host.docker.internal:3000/api/v4/projects/25/issues/1\",\"notes\":\"http://host.docker.internal:3000/api/v4/projects/25/issues/1/notes\",\"award_emoji\":\"http://host.docker.internal:3000/api/v4/projects/25/issues/1/award_emoji\",\"project\":\"http://host.docker.internal:3000/api/v4/projects/25\",\"closed_as_duplicate_of\":null},\"references\":{\"short\":\"#1\",\"relative\":\"#1\",\"full\":\"gitlab-org/duo-workflow-executor#1\"},\"severity\":\"UNKNOWN\",\"subscribed\":false,\"moved_to_id\":null,\"imported\":false,\"imported_from\":\"none\",\"service_desk_reply_to\":null,\"epic_iid\":null,\"epic\":null,\"iteration\":null}"
    ]
}
Edited by Igor Drozdov

Merge request reports

Loading