{"record":{"id":"6a99e7d2b90035ea","repo":"unclecode/crawl4ai","slug":"e-response-text","errorCode":null,"errorMessage":"e.response.text","messagePattern":"e\\.response\\.text","errorType":"http","errorClass":"HTTPException","httpStatus":null,"severity":"error","filePath":"deploy/docker/mcp_bridge.py","lineNumber":79,"sourceCode":"            placeholder = \"{\" + k + \"}\"\n            if placeholder in path:\n                path = path.replace(placeholder, str(v))\n                kwargs.pop(k)\n        url = base_url.rstrip(\"/\") + path\n\n        headers = _service_auth_headers()\n        async with httpx.AsyncClient(timeout=timeout) as client:\n            try:\n                r = (\n                    await client.get(url, params=kwargs, headers=headers)\n                    if method == \"GET\"\n                    else await client.request(method, url, json=kwargs, headers=headers)\n                )\n                r.raise_for_status()\n                return r.text if method == \"GET\" else r.json()\n            except httpx.HTTPStatusError as e:\n                # surface FastAPI error details instead of plain 500\n                raise HTTPException(e.response.status_code, e.response.text)\n            except httpx.TimeoutException:\n                raise HTTPException(504, \"upstream request timed out\")\n    return proxy\n\n# ── main entry point ────────────────────────────────────────────\ndef attach_mcp(\n    app: FastAPI,\n    *,                          # keyword‑only\n    base: str = \"/mcp\",\n    name: str | None = None,\n    base_url: str,              # eg. \"http://127.0.0.1:8020\"\n    timeout: float | None = None,  # httpx timeout in seconds; None = no limit\n) -> None:\n    \"\"\"Call once after all routes are declared to expose WS+SSE MCP endpoints.\"\"\"\n    server_name = name or app.title or \"FastAPI-MCP\"\n    mcp = Server(server_name)\n\n    # tools: Dict[str, Callable] = {}","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/mcp_bridge.py#L61-L97","documentation":"In deploy/docker/mcp_bridge.py each proxied MCP tool call forwards to the FastAPI service over httpx; when the upstream returns 4xx/5xx, raise_for_status() raises httpx.HTTPStatusError and the bridge re-raises HTTPException(e.response.status_code, e.response.text). So this 'error' is a faithful passthrough: the status code and body are the upstream FastAPI error (its detail JSON), not generated by the bridge.","triggerScenarios":"Calling an MCP tool whose underlying HTTP endpoint fails — e.g. crawl tool with an invalid URL (upstream 400), unauthorized service auth (401/403), monitor endpoints before initialization (upstream 500), any upstream validation failure.","commonSituations":"Debugging via MCP client and seeing raw upstream detail text; service-to-service auth headers (_service_auth_headers) missing or expired so every proxied call 401s; upstream schema changes making previously valid tool arguments invalid.","solutions":["Parse e.response.text (or the MCP error payload's detail) — it is the upstream FastAPI error JSON; fix the argument per that message.","Verify service auth configuration between the bridge and the base_url service if codes are 401/403.","Hit the underlying HTTP endpoint directly with curl to confirm behavior independent of MCP.","For persistent 5xx, check the upstream service logs — the bridge only mirrors them."],"exampleFix":"# before\ntools/call {\"name\": \"monitor_health\", \"arguments\": {}}  # -> error 500, detail 'Monitor not initialized'\n\n# after (initialize monitor / start upstream fully, then retry)\ntools/call {\"name\": \"monitor_health\", \"arguments\": {}}  # -> 200 payload","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"# MCP tools/call returns error payloads, not exceptions:\nif isinstance(result_text, str) and result_text.startswith('{\"error\"'):\n    err = json.loads(result_text)\n    if err[\"error\"] in (400, 422):\n        fix_arguments_per_detail(err[\"detail\"])\n    elif err[\"error\"] in (401, 403):\n        fix_service_auth()\n    elif err[\"error\"] >= 500:\n        check_upstream_logs()","preventionTips":["Treat the bridge as a passthrough: debug the upstream endpoint directly with curl.","Keep service auth credentials in sync between bridge and upstream.","Handle the {error, detail} JSON shape in MCP client code rather than string-matching."],"tags":["mcp","http-proxy","passthrough","api"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}