langflow-ai/langflow · critical · ValueError

Agentic MCP server is not bound to an authenticated user

Error message

Agentic MCP server is not bound to an authenticated user ({AGENTIC_USER_ID_ENV_VAR} not set); refusing flow access.

What it means

Raised by the agentic MCP server's user-binding helper: every tool call resolves the acting user from the LANGFLOW_AGENTIC_USER_ID environment variable, which Langflow injects at spawn time from the authenticated session. If the variable is absent the server fails closed — it refuses to serve ANY flow access — so a mis-spawned or manually started server cannot read another user's (or any user's) flows. Replaces an older caller-supplied user_id parameter that allowed impersonation.

Solutions

  1. Launch the MCP server through Langflow's own spawn path (the authenticated endpoint that injects LANGFLOW_AGENTIC_USER_ID) rather than invoking the module yourself.
  2. For local debugging only, export LANGFLOW_AGENTIC_USER_ID=<your user uuid> before starting the server.
  3. If a custom spawn wrapper exists, make it forward/inject the variable from the authenticated user context.
  4. Never attempt to pass user_id as a tool argument — the parameter was removed by design.

Example fix

# before (manual run -> fails closed)
$ python -m langflow.agentic.mcp
# after (bound to your user for local debug)
$ LANGFLOW_AGENTIC_USER_ID=$(langflow whoami --id) python -m langflow.agentic.mcp
Defensive patterns

Strategy: validation

Validate before calling

import os
from lfx.base.mcp.security import AGENTIC_USER_ID_ENV_VAR

if not os.getenv(AGENTIC_USER_ID_ENV_VAR):
    raise SystemExit(
        f'Refuse to start: {AGENTIC_USER_ID_ENV_VAR} not set. '
        'Spawn the MCP server via Langflow authenticated spawn endpoint.'
    )

Try / catch

try: user_id = require_bound_user() except ValueError: log_and_exit('server mis-spawned; must be launched by Langflow with user binding')

Prevention

When it happens

Trigger: Running 'python -m langflow.agentic.mcp' directly in a shell without the env var; a tenant-authored MCP config that spawns the server through a route that skipped env injection; CI/container environments where the spawn wrapper was bypassed; debugging the server standalone.

Common situations: Developer starts the MCP server manually to test a tool; MCP client config (e.g. claude_desktop_config.json) invokes the module directly instead of going through Langflow's spawn endpoint; security hardening after upgrade from a version that accepted user_id as a parameter, breaking old custom launch scripts.

Understand the failure class

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/57165cfa5a2688b4. Report an issue: GitHub.

Appendix: source

Thrown at src/backend/base/langflow/agentic/mcp/server.py:95

def _bound_user_id() -> str:
    """Return the authenticated user id Langflow bound to this agentic MCP server process.

    SECURITY: Langflow injects ``AGENTIC_USER_ID_ENV_VAR`` at spawn time from the authenticated
    request identity (see ``lfx.base.mcp.util.update_tools``); a tenant cannot supply it via a
    stdio config because the key is in the MCP stdio env denylist. The flow/component tools are
    scoped to this id. We FAIL CLOSED when it is absent so a server spawned without a bound
    identity — a tenant-authored config that evaded injection, or a bare
    ``python -m langflow.agentic.mcp`` run — cannot read or write ANY user's flows. This replaces
    the previous caller-supplied ``user_id`` parameter, which let a caller pass another user's id
    (or omit it for an unscoped, any-flow read).
    """
    user_id = os.getenv(AGENTIC_USER_ID_ENV_VAR)
    if not user_id:
        msg = (
            f"Agentic MCP server is not bound to an authenticated user ({AGENTIC_USER_ID_ENV_VAR} "
            "not set); refusing flow access."
        )
        raise ValueError(msg)
    return user_id


@mcp.tool()
def search_templates(query: str | None = None, fields: list[str] = DEFAULT_TEMPLATE_FIELDS) -> list[dict[str, Any]]:
    """Search and load template data with configurable field selection.

    Args:
        query: Optional search term to filter templates by name or description.
               Case-insensitive substring matching.
        fields: List of fields to include in the results. If None, returns default fields:
               DEFAULT_TEMPLATE_FIELDS
               Common fields: id, name, description, tags, is_component, last_tested_version,
               endpoint_name, data, icon, icon_bg_color, gradient, updated_at
        tags: Optional list of tags to filter templates. Returns templates that have ANY of these tags.

    Returns:
        List of dictionaries containing the selected fields for each matching template.

View on GitHub (pinned to 976ec789d2)