feat: Global variable passthrough in MCP Projects SSE#9890
Conversation
…SE handling - Introduced `current_request_variables_ctx` to manage per-request variables injected via HTTP headers. - Updated `handle_project_sse` and `handle_project_messages` to extract variables prefixed with `X-LANGFLOW-GLOBAL-VAR-*` from request headers. - Enhanced error handling for variable extraction failures with logging for better debugging.
WalkthroughAdds per-request header-driven variables via a new ContextVar and propagates them into flow execution. Endpoints extract X-Langflow-Global-Var-* headers, set/reset the context var during request/SSE handling, and mcp_utils reads it to pass a context dict to simple_run_flow in handle_call_tool. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant API as mcp_projects.handle_project_messages
participant Ctx as current_request_variables_ctx
participant Util as mcp_utils.handle_call_tool
participant Flow as simple_run_flow
C->>API: POST /... (headers X-Langflow-Global-Var-*)
API->>API: Extract headers, build {VAR: value}
API->>Ctx: set(variables)
note right of API: Variables available to downstream calls
API->>Util: handle_call_tool(...)
Util->>Ctx: get() -> variables
Util->>Util: exec_context = {"request_variables": vars} or None
Util->>Flow: simple_run_flow(..., context=exec_context)
Flow-->>Util: result
Util-->>API: result
API-->>C: response
API->>Ctx: reset() in finally
sequenceDiagram
autonumber
participant C as Client
participant API as mcp_projects.handle_project_sse
participant Ctx as current_request_variables_ctx
participant Stream as SSE stream
participant Util as mcp_utils.handle_call_tool
C->>API: GET /.../sse (headers X-Langflow-Global-Var-*)
API->>API: Extract headers, build {VAR: value}
API->>Ctx: set(variables)
API-->>C: Open SSE stream
loop Events
API->>Util: handle_call_tool(...) as events occur
Util->>Ctx: get() -> variables
Util-->>API: event payload
API-->>Stream: send event
end
API->>Ctx: reset() in finally
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
Example MCP Server JSON: |
|
Tip For best results, initiate chat on the files or code changes. @edwinjosechittilappilly Thank you for sharing this example MCP Server JSON configuration! This is an excellent demonstration of how the global variable passthrough feature implemented in this PR would be used in practice. The configuration perfectly showcases the key aspects of the new functionality:
This example validates that the implementation correctly addresses the real-world need for dynamic variable injection from external MCP clients, making the system more flexible and secure by allowing per-request customization without hardcoding sensitive values. The design choice to use HTTP headers with a specific prefix pattern makes it easy for MCP proxy tools like ฅ(^◡^)ฅ |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/backend/base/langflow/api/v1/mcp_utils.py (1)
179-182: Prefer a consistent context shape (avoidNone).Always pass a dict to downstream callers to simplify handling and avoid
Nonechecks later.Apply this diff:
- request_variables = current_request_variables_ctx.get() - exec_context = {"request_variables": request_variables} if request_variables else None + request_variables = current_request_variables_ctx.get() + exec_context = {"request_variables": request_variables or {}}src/backend/base/langflow/api/v1/mcp_projects.py (2)
270-282: Normalize header suffix and ignore empty values; also consider bounds.
- Map hyphens to underscores so both
X-...-OPENAI-API-KEYandX-...-OPENAI_API_KEYnormalize to the same key.- Trim values and skip empties to avoid accidental blanks.
- Minor hardening: consider bounding the number/size of accepted headers to prevent abuse.
Apply this diff:
- variables: dict[str, str] = {} - header_prefix = "x-langflow-global-var-" + variables: dict[str, str] = {} + header_prefix = "x-langflow-global-var-" try: for header_name, header_value in request.headers.items(): header_lower = header_name.lower() if header_lower.startswith(header_prefix): - var_name = header_lower[len(header_prefix) :].upper() - variables[var_name] = header_value + raw = header_lower[len(header_prefix) :] + var_name = raw.replace("-", "_").upper() + value = header_value.strip() + if value: + variables[var_name] = value except Exception: # noqa: BLE001 await logger.aexception("Failed to parse request variables from headers for project %s", project_id)Optional follow-up: extract this parsing into a tiny helper to remove duplication with the POST path. I can draft it if you want.
323-335: Mirror normalization for POST path.Keep header parsing consistent with the SSE path: normalize name and trim/skip empty values.
Apply this diff:
- variables: dict[str, str] = {} - header_prefix = "x-langflow-global-var-" + variables: dict[str, str] = {} + header_prefix = "x-langflow-global-var-" try: for header_name, header_value in request.headers.items(): header_lower = header_name.lower() if header_lower.startswith(header_prefix): - var_name = header_lower[len(header_prefix) :].upper() - variables[var_name] = header_value + raw = header_lower[len(header_prefix) :] + var_name = raw.replace("-", "_").upper() + value = header_value.strip() + if value: + variables[var_name] = value except Exception: # noqa: BLE001 await logger.aexception("Failed to parse request variables from headers for project %s", project_id)
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/backend/base/langflow/api/v1/mcp_projects.py(5 hunks)src/backend/base/langflow/api/v1/mcp_utils.py(3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{src/backend/**/*.py,tests/**/*.py,Makefile}
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code
Files:
src/backend/base/langflow/api/v1/mcp_projects.pysrc/backend/base/langflow/api/v1/mcp_utils.py
🔇 Additional comments (5)
src/backend/base/langflow/api/v1/mcp_utils.py (2)
35-38: Per-request ContextVar introduction — LGTMThe new
current_request_variables_ctxis well-scoped with a safe default ofNone. Good foundation for request‑scoped propagation.
233-239: simple_run_flow acceptscontext(no change required).Signature is
async def simple_run_flow(..., context: dict | None = None)(src/backend/base/langflow/api/v1/endpoints.py). mcp_utils.py buildsexec_context = {"request_variables": ...}orNoneand Graph/components consumerequest_variables, so the call is compatible.src/backend/base/langflow/api/v1/mcp_projects.py (3)
29-37: Import of request‑variables context — LGTMImporting
current_request_variables_ctxhere is appropriate for per-request propagation.
308-309: Context reset — LGTMResetting
current_request_variables_ctxinfinallyprevents leakage across requests.
345-346: Context reset — LGTMGood symmetry with the SSE path; prevents cross-request contamination.
feat: add request-level variable extraction from headers in project SSE handling - Introduced `current_request_variables_ctx` to manage per-request variables injected via HTTP headers. - Updated `handle_project_sse` and `handle_project_messages` to extract variables prefixed with `X-LANGFLOW-GLOBAL-VAR-*` from request headers. - Enhanced error handling for variable extraction failures with logging for better debugging.


This pull request introduces support for passing per-request variables from HTTP headers into the backend execution context. These variables, extracted from headers prefixed with
X-LANGFLOW-GLOBAL-VAR-*, are now injected into the context for project-related SSE and message handling endpoints, enabling more dynamic and customizable request processing.Request variable extraction and context management
X-LANGFLOW-GLOBAL-VAR-*in bothhandle_project_sseandhandle_project_messages, storing them in a new context variable for each request. [1] [2]current_request_variables_ctxas a newContextVarto hold these per-request variables, with a default ofNone.Integration with tool execution
handle_call_tooland related functions to include the extracted request variables in the execution context, allowing downstream processing to access them. [1] [2]Summary by CodeRabbit