{"record":{"id":"57165cfa5a2688b4","repo":"langflow-ai/langflow","slug":"agentic-mcp-server-is-not-bound-to-an-authenticate","errorCode":null,"errorMessage":"Agentic MCP server is not bound to an authenticated user ({AGENTIC_USER_ID_ENV_VAR} not set); refusing flow access.","messagePattern":"Agentic MCP server is not bound to an authenticated user \\((.+?) not set\\); refusing flow access\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"src/backend/base/langflow/agentic/mcp/server.py","lineNumber":95,"sourceCode":"def _bound_user_id() -> str:\n    \"\"\"Return the authenticated user id Langflow bound to this agentic MCP server process.\n\n    SECURITY: Langflow injects ``AGENTIC_USER_ID_ENV_VAR`` at spawn time from the authenticated\n    request identity (see ``lfx.base.mcp.util.update_tools``); a tenant cannot supply it via a\n    stdio config because the key is in the MCP stdio env denylist. The flow/component tools are\n    scoped to this id. We FAIL CLOSED when it is absent so a server spawned without a bound\n    identity — a tenant-authored config that evaded injection, or a bare\n    ``python -m langflow.agentic.mcp`` run — cannot read or write ANY user's flows. This replaces\n    the previous caller-supplied ``user_id`` parameter, which let a caller pass another user's id\n    (or omit it for an unscoped, any-flow read).\n    \"\"\"\n    user_id = os.getenv(AGENTIC_USER_ID_ENV_VAR)\n    if not user_id:\n        msg = (\n            f\"Agentic MCP server is not bound to an authenticated user ({AGENTIC_USER_ID_ENV_VAR} \"\n            \"not set); refusing flow access.\"\n        )\n        raise ValueError(msg)\n    return user_id\n\n\n@mcp.tool()\ndef search_templates(query: str | None = None, fields: list[str] = DEFAULT_TEMPLATE_FIELDS) -> list[dict[str, Any]]:\n    \"\"\"Search and load template data with configurable field selection.\n\n    Args:\n        query: Optional search term to filter templates by name or description.\n               Case-insensitive substring matching.\n        fields: List of fields to include in the results. If None, returns default fields:\n               DEFAULT_TEMPLATE_FIELDS\n               Common fields: id, name, description, tags, is_component, last_tested_version,\n               endpoint_name, data, icon, icon_bg_color, gradient, updated_at\n        tags: Optional list of tags to filter templates. Returns templates that have ANY of these tags.\n\n    Returns:\n        List of dictionaries containing the selected fields for each matching template.","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/agentic/mcp/server.py#L77-L113","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","For local debugging only, export LANGFLOW_AGENTIC_USER_ID=<your user uuid> before starting the server.","If a custom spawn wrapper exists, make it forward/inject the variable from the authenticated user context.","Never attempt to pass user_id as a tool argument — the parameter was removed by design."],"exampleFix":"# before (manual run -> fails closed)\n$ python -m langflow.agentic.mcp\n# after (bound to your user for local debug)\n$ LANGFLOW_AGENTIC_USER_ID=$(langflow whoami --id) python -m langflow.agentic.mcp","handlingStrategy":"validation","validationCode":"import os\nfrom lfx.base.mcp.security import AGENTIC_USER_ID_ENV_VAR\n\nif not os.getenv(AGENTIC_USER_ID_ENV_VAR):\n    raise SystemExit(\n        f'Refuse to start: {AGENTIC_USER_ID_ENV_VAR} not set. '\n        'Spawn the MCP server via Langflow authenticated spawn endpoint.'\n    )","typeGuard":null,"tryCatchPattern":"try: user_id = require_bound_user() except ValueError: log_and_exit('server mis-spawned; must be launched by Langflow with user binding')","preventionTips":["Never launch 'python -m langflow.agentic.mcp' by hand outside debugging.","Keep MCP client configs pointing at Langflow's spawn endpoint so identity injection happens.","Treat this error as a security control, not a bug — do not paper over it by hardcoding ids in tool calls."],"tags":["agentic","mcp","security","fail-closed","environment"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}