Fix connecting to Slack's MCP server

What does this MR do and why?

Fixes connecting AI Catalog agents to Slack's MCP server (https://mcp.slack.com/mcp). Both fixes are generic and help other MCP servers that behave the same way:

  • Find resource metadata published at the root. GitLab only looked for protected resource metadata at the path-specific URL (/.well-known/oauth-protected-resource/mcp). Slack only publishes it at the root, so GitLab requested no scopes and Slack rejected the request with "No scopes requested". GitLab now also tries the root URL, as the MCP authorization spec requires. It requests every scope the server lists, as it does for other servers.
  • Send client credentials in the request body when required. OAuth2::Client sends the client ID and secret as a basic auth header. Slack's token endpoint only accepts them in the request body (client_secret_post), so the token exchange and refresh failed. GitLab now uses the request body when the server lists client_secret_post and not client_secret_basic. Otherwise basic auth stays the default.

References

Screenshots

Before After
Screenshot from 2026-10-06 10-42-56.png Screenshot from 2026-10-06 10-43-24.png

How to set up and validate locally

  1. In Slack, go to Your Apps, select Create New App > From a manifest, choose your workspace, and paste this manifest. Replace http://gdk.test:8080 with your GDK URL:

    {
      "display_information": {
        "name": "GitLab MCP test"
      },
      "oauth_config": {
        "redirect_urls": [
          "http://gdk.test:8080"
        ],
        "scopes": {
          "user": [
            "canvases:read",
            "canvases:write",
            "channels:history",
            "channels:read",
            "channels:write",
            "chat:write",
            "emoji:read",
            "files:read",
            "files:write",
            "groups:history",
            "groups:read",
            "groups:write",
            "im:history",
            "im:read",
            "im:write",
            "lists:read",
            "lists:write",
            "mpim:history",
            "mpim:read",
            "mpim:write",
            "reactions:read",
            "reactions:write",
            "search:read.files",
            "search:read.im",
            "search:read.mpim",
            "search:read.private",
            "search:read.public",
            "search:read.users",
            "users:read",
            "users:read.email"
          ]
        }
      },
      "settings": {
        "is_mcp_enabled": true,
        "org_deploy_enabled": false,
        "socket_mode_enabled": false,
        "token_rotation_enabled": false
      }
    }
  2. Go to Basic Information and copy the Client ID and Client Secret.

  3. In a Rails console, enable the feature flags and turn on experiment and beta features:

    Feature.enable(:ai_catalog_mcp_servers)
    Feature.enable(:mcp_client)
    ApplicationSetting.current.update!(instance_level_ai_beta_features_enabled: true)
  4. In a top-level group, go to Settings > GitLab Duo and turn on Allow external MCP tools.

  5. Go to Explore > AI Catalog > MCP, select New MCP server, and enter:

    • Server URL: https://mcp.slack.com/mcp
    • Authentication method: OAuth
    • OAuth Client ID and OAuth Client Secret: from step 3
  6. Go to Explore > AI Catalog > Agents, select New agent, and create an agent. Under MCP servers, select the Slack server.

  7. Enable the agent in your group.

  8. In the group, go to Automate > MCP servers, select Connect for the Slack server, and select Allow in Slack. You should return to GitLab with "Successfully connected to MCP server". On master, Slack shows "No scopes requested" instead.

  9. Open GitLab Duo Chat in a project in the group, select your agent, and ask it to summarize the latest messages in a public channel. Approve the Slack tool call. The answer should include messages from that channel.

Edited by Keeyan Nejad

Merge request reports

Loading
Loading