Send the workflow ID header on internal MCP calls
What does this MR do and why?
When a Duo Agent Platform flow runs through Workhorse, Workhorse acts as the MCP client for the flow and calls MCP servers. It already sends X-Duo-Workflow-Session-Id on those calls.
This MR makes Workhorse also send X-Gitlab-Duo-Workflow-Id on MCP tool calls. It sends it only to GitLab's own MCP servers:
gitlab(/api/v4/mcp)orbit(/api/v4/orbit/mcp)
Third-party MCP servers do not get this header.
Why
Rails reads the calling workflow from X-Gitlab-Duo-Workflow-Id. Gitlab::Middleware::DuoWorkflowId stores it in Gitlab::ApplicationContext[:duo_workflow_id]. RunHTTPRequest actions in Workhorse already send this header (workhorse/internal/ai_assist/duoworkflow/actions.go). MCP tool calls did not. So Rails could not tell which workflow made an MCP tool call.
A follow-up Rails change will use this header. Sessions started with the start_duo_session MCP tool (which calls POST /api/v4/ai/duo_workflows/workflows) will record the workflow that started them as their parent. POST /api/v4/ai/duo_workflows/agent_workflows already does this since !259111 (merged).
How
- In
workhorse/internal/ai_assist/duoworkflow/mcp.go,roundTrippergets a newinternalfield. buildSessionsets this field from the sameinternalPathslookup that picks the Rails endpoint. So the header goes only to requests that are routed to Rails.TestBuildSession_sendsWorkflowIDOnlyToInternalServerschecks thegitlabserver, theorbitserver, and an external server.
Behavior changes
MCP tool calls from a flow to GitLab now get the same workflow attribution that RunHTTPRequest calls already get. This means:
- Issues, merge requests, and notes created through MCP tools are linked to the workflow that created them.
- Flows set up to reuse an open merge request can reuse it when they create a merge request through MCP.
- API log lines for
/api/v4/mcpand/api/v4/orbit/mcpincludeduo_workflow_id. - With the
ai_flow_trigger_chainingfeature flag enabled (off by default), assignments made by a flow through MCP tools can start the assigned flow with the calling workflow as its parent. See !259133 (merged).
No changelog. This is an internal attribution change with no user-facing change on its own.
References
- https://gitlab.com/gitlab-org/gitlab/-/work_items/632365
- Plan: https://gitlab.com/gitlab-org/gitlab/-/work_items/630476
- !259111 (merged)
Screenshots or screen recordings
Not applicable. Backend only.
How to set up and validate locally
- In GDK, run a flow that has the GitLab MCP server enabled, for example the Developer flow.
- Let the flow call a GitLab MCP tool.
- In
log/api_json.log, find the request to/api/v4/mcp. Check thatduo_workflow_idis set to the workflow ID of the session. - Optional: check that requests to a third-party MCP server configured for the flow do not carry the
X-Gitlab-Duo-Workflow-Idheader.
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.