{"record":{"id":"fe763f62d8114854","repo":"langflow-ai/langflow","slug":"failed-to-install-mcp","errorCode":null,"errorMessage":"Failed to install MCP","messagePattern":"Failed to install MCP","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/frontend/src/controllers/API/queries/mcp/use-add-mcp-server.ts","lineNumber":49,"sourceCode":"      }\n      if (body.args && body.args.length > 0) {\n        payload.args = body.args;\n      }\n      if (body.env && Object.keys(body.env).length > 0) {\n        payload.env = body.env;\n      }\n      if (body.headers && Object.keys(body.headers).length > 0) {\n        payload.headers = body.headers;\n      }\n\n      const res = await api.post(\n        `${getURL(\"MCP_SERVERS\", undefined, true)}/${body.name}`,\n        payload,\n      );\n\n      return { message: res.data?.message || \"MCP Server added successfully\" };\n    } catch (error: unknown) {\n      throw new Error(\n        extractApiErrorMessage(\n          error as Parameters<typeof extractApiErrorMessage>[0],\n          \"Failed to install MCP\",\n        ),\n      );\n    }\n  }\n\n  const mutation: UseMutationResult<AddMCPServerResponse, any, MCPServerType> =\n    mutate([\"useAddMCPServer\"], addMCPServer, {\n      ...options,\n      retry: 0,\n      onSuccess: (data, variables, context) => {\n        queryClient.invalidateQueries({\n          queryKey: [\"useGetMCPServers\"],\n        });\n        options?.onSuccess?.(data, variables, context);\n      },","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/frontend/src/controllers/API/queries/mcp/use-add-mcp-server.ts#L31-L67","documentation":"500 (arguably should be 403) returned by POST /{project_id}/install when the request's client IP is not a loopback address. The install flow writes MCP client config files on the user's machine, so Langflow restricts it to same-machine requests via get_client_ip + is_local_ip.","triggerScenarios":"Clicking 'install to Cursor/Claude/Windsurf' in a UI served over LAN/public, or through a reverse proxy that does not forward the real client IP (X-Forwarded-For missing), so the server sees the proxy IP instead of 127.0.0.1.","commonSituations":"Accessing Langflow via http://<lan-ip>:7860 or a domain behind nginx/tunnel; docker port-mapping where the source IP is NAT'd; SSH port-forward usually still works because it appears as loopback.","solutions":["Make the install request from the same machine Langflow runs on (http://localhost:7860 or an SSH tunnel).","If behind a proxy, configure it to pass X-Forwarded-For and ensure Langflow trusts/honors it, so loopback clients are detected.","Alternatively copy the generated MCP JSON manually from the UI instead of using /install."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import socket\nlocal = client_ip in {\"127.0.0.1\", \"::1\"} or ipaddress.ip_address(client_ip).is_loopback\nif not local:\n    # use an SSH tunnel or localhost UI instead of calling /install remotely","typeGuard":"import ipaddress\ndef is_loopback(ip_str: str) -> bool:\n    try:\n        return ipaddress.ip_address(ip_str).is_loopback\n    except ValueError:\n        return ip_str == \"localhost\"","tryCatchPattern":null,"preventionTips":["Open the Langflow UI via localhost or an SSH port-forward when using one-click MCP install.","Configure reverse proxies to forward X-Forwarded-For so loopback detection sees the real client.","Fall back to copying the MCP JSON manually when remote install is blocked."],"tags":["mcp","install","local-only","proxy"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}