Expose the client-injected MCP tool carve-out on the session

What does this MR do and why?

The Duo Workflow Service needs to know whether MCP tools the client supplied may skip the tool call approval gate. This is the Rails half: the feature flag, and a field on the session that answers it.

The flag used to travel in the x-gitlab-enabled-feature-flags header. That works where Workhorse builds the request, but POST /ai/duo_workflows/direct_access returns its headers to the caller, so on that path the header is whatever the caller chooses to send and a client could enable the carve-out for itself. As a field on the session, the answer comes from Rails on every path. It is also resolved per workflow rather than per token, so turning the flag off takes effect on the next workflow.

The flag is beta rather than wip because it exists to be enabled for one namespace, and wip is for hiding code that is not usable yet.

Split out of !255049, which carries a Workhorse change that stops setup-test-env compiling, so no RSpec job there could run these examples.

Nothing consumes the field until the service side merges, so behaviour is unchanged on its own.

GitLab Dedicated is out of scope. Feature flags are not supported there, so there is no way to turn dap_allow_client_injected_mcp_tools on for a Dedicated tenant. The longer-term fix that removes the need for the flag is tracked in https://gitlab.com/gitlab-org/gitlab/-/work_items/628575.

How to set up and validate locally

  1. Run the specs. They need no local overrides, since nothing here references the unreleased protobuf field:

    bundle exec rspec ee/spec/graphql/types/ai/duo_workflows/workflow_type_spec.rb \
      ee/spec/requests/api/graphql/ai/duo_workflows/workflows_spec.rb
  2. Query the field for a session, for example through /-/graphql-explorer:

    query {
      duoWorkflowWorkflows(workflowId: "gid://gitlab/Ai::DuoWorkflows::Workflow/1") {
        nodes { id allowClientInjectedMcpTools }
      }
    }
  3. Toggle the flag for the session's root namespace and query again. It returns false while the flag is off.

    Feature.enable(:dap_allow_client_injected_mcp_tools, Group.find_by_full_path('your-group'))

References

Edited by Raounak Sharma

Merge request reports

Loading
Loading