Skip to content

Bug: MCP Server x-api-key header Not Propagated to Nested MCP Calls #12529

Description

@stevehaertel

Bug Description

Description

The documentation claims that you can add x-api-key into the mcp server settings and have it pass through into nested MCP servers inside your flow, but this doesn't work.

When using Langflow as an MCP server that contains flows with nested MCP components (MCP client functionality), authentication headers like x-api-key are not being propagated from the incoming request to the nested MCP server calls. This causes authentication failures (401 errors) when the nested MCP server requires authentication.

Actual Behavior

Authentication headers are received by the Langflow MCP server but are not propagated to nested MCP server calls.

Actual flow:

MCP Client
  ↓ [x-api-key: <API_KEY>]
Langflow MCP Server
  ↓ [x-api-key received but not extracted ✗]
Flow Execution
  ↓ [No authentication context ✗]
MCP Component
  ↓ [headers: {} - EMPTY! ✗]
Nested MCP Server
  ↓ [401 Authentication Error ✗]

Root Cause

The issue occurs in two places:

1. Header Extraction (src/backend/base/langflow/api/v1/mcp_projects.py)

The extract_global_variables_from_headers function only extracts headers with the prefix X-LANGFLOW-GLOBAL-VAR-*. Standard authentication headers like x-api-key don't have this prefix and are not extracted.

# Current code only extracts X-LANGFLOW-GLOBAL-VAR-* headers
variables = extract_global_variables_from_headers(request.headers)
request_vars_token = current_request_variables_ctx.set(variables or None)

2. Header Resolution (src/lfx/src/lfx/base/mcp/util.py)

The _resolve_global_variables_in_headers function only resolves variable placeholders in existing headers. It doesn't add new headers from request_variables, so even if authentication headers were extracted, they wouldn't be added to nested MCP calls unless explicitly configured in the server config.

def _resolve_global_variables_in_headers(headers: dict, request_variables: dict[str, str] | None) -> dict:
    """Resolve global variable names in header values to their actual values."""
    if not request_variables:
        return headers

    resolved = {}
    for key, value in headers.items():
        # Only resolves placeholders, doesn't add new headers
        if isinstance(value, str) and value in request_variables:
            resolved[key] = request_variables[value]
        else:
            resolved[key] = value
    return resolved

Proposed Solution

A two-part fix is needed:

Part 1: Extract Authentication Headers as Request Variables

File: src/backend/base/langflow/api/v1/mcp_projects.py

project_token = current_project_ctx.set(project_id)
variables = extract_global_variables_from_headers(request.headers)

# Also extract x-api-key header for MCP server authentication
# This allows the header to be propagated to nested MCP servers
if "x-api-key" in request.headers:
    if variables is None:
        variables = {}
    variables["x-api-key"] = request.headers["x-api-key"]

request_vars_token = current_request_variables_ctx.set(variables or None)

Part 2: Auto-Add Authentication Headers from Request Variables

File: src/lfx/src/lfx/base/mcp/util.py

def _resolve_global_variables_in_headers(headers: dict, request_variables: dict[str, str] | None) -> dict:
    """Resolve global variable names in header values to their actual values."""
    if not request_variables:
        return headers

    resolved = {}
    for key, value in headers.items():
        # If the value matches a global variable name, replace it with the actual value
        if isinstance(value, str) and value in request_variables:
            resolved[key] = request_variables[value]
        else:
            resolved[key] = value
    
    # Also add authentication headers directly from request_variables if not already present
    # This allows headers like x-api-key to be propagated to nested MCP servers
    auth_headers = ["x-api-key", "authorization"]
    for auth_header in auth_headers:
        if auth_header in request_variables and auth_header not in resolved:
            resolved[auth_header] = request_variables[auth_header]
    
    return resolved

Impact

This bug affects any Langflow deployment where:

  • Langflow is used as an MCP server
  • Flows contain MCP components that call other MCP servers (nested scenario)
  • The nested MCP servers require authentication

This is a critical issue for production deployments using nested MCP architectures, as it prevents proper authentication propagation and causes service failures.

Workaround

There are two possible workarounds:

Option 1: Use X-LANGFLOW-GLOBAL-VAR-* Headers (Recommended)

Configure the MCP client to send authentication using the X-LANGFLOW-GLOBAL-VAR-* prefix, which will be extracted as request variables:

{
  "mcpServers": {
    "my-langflow-server": {
      "command": "uvx",
      "args": [
        "mcp-proxy",
        "--transport",
        "streamablehttp",
        "--headers",
        "X-LANGFLOW-GLOBAL-VAR-API_KEY",
        "your-api-key-value",
        "http://localhost:7860/api/v1/mcp/project/PROJECT_ID/streamable"
      ]
    }
  }
}

Then configure the nested MCP component to use this global variable:

  • In the MCP component's headers configuration, set x-api-key to the value API_KEY (the variable name without the prefix)
  • Langflow will resolve API_KEY to the actual value from the request variables

Limitations:

  • Requires explicit configuration in each nested MCP component
  • Not intuitive - users must understand the variable resolution mechanism
  • Doesn't work for standard x-api-key headers sent by clients

Option 2: Hardcode Credentials (Not Recommended)

Manually configure the x-api-key header in each nested MCP component's server configuration with a hardcoded value.

Limitations:

  • Requires hardcoding credentials in flow configurations
  • Doesn't support dynamic authentication from the incoming request
  • Creates security and maintenance issues
  • Credentials are stored in the flow definition

Additional Context

The Langflow documentation (docs/docs/Agents/mcp-server.mdx) describes how to configure API key authentication for MCP servers but doesn't mention the limitation with nested MCP calls or the need for explicit header configuration in nested scenarios.

Testing

After applying the fix:

  1. Restart the Langflow server
  2. Call an MCP tool that uses nested MCP components
  3. Verify in logs that:
    • [MCP Tool Execution] Request variables: includes authentication headers
    • [MCP HTTP Client] Connection params headers: includes authentication headers
    • No 401 errors occur
    • Nested MCP server calls succeed

Related Documentation

Reproduction

  1. Configure the nested MCP server to require authentication (e.g., x-api-key header)
  2. Create a flow with an agent using an mcp server as a tool
  3. Connect an MCP client (e.g., Cursor, Claude) to the Langflow MCP server with x-api-key in the mcp json
  4. Call a tool that triggers the flow with the nested MCP component
  5. Observe 401 authentication error from the nested MCP server

Expected behavior

Authentication headers from the incoming MCP request should be propagated to nested MCP server calls, allowing the entire request chain to maintain proper authentication.

Expected flow:

MCP Client
  ↓ [x-api-key: <API_KEY>]
Langflow MCP Server
  ↓ [Extract and propagate x-api-key ✓]
Flow Execution
  ↓ [Pass authentication context ✓]
MCP Component
  ↓ [Include x-api-key in nested call ✓]
Nested MCP Server
  ↓ [Authenticate successfully ✓]

Who can help?

No response

Operating System

Ubuntu 24

Langflow Version

main

Python Version

3.12

Screenshot

Image

Flow File

No response

Metadata

Metadata

Labels

bugSomething isn't workingjiraThis issue has been logged in Jira for fix by the engineering team.mcp

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions