{"record":{"id":"8c49da107dc3995b","repo":"BerriAI/litellm","slug":"ip-filtering","errorCode":"ip_filtering","errorMessage":"MCP server '{server_id}' is not accessible from your IP address ({_rest_client_ip}). This server is restricted to internal networks only. To make it externally accessible, set 'available_on_public_internet: true' in the server configuration.","messagePattern":"MCP server '(.+?)' is not accessible from your IP address \\((.+?)\\)\\. This server is restricted to internal networks only\\. To make it externally accessible, set 'available_on_public_internet: true' in the server configuration\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"litellm/proxy/_experimental/mcp_server/rest_endpoints.py","lineNumber":467,"sourceCode":"            )\n            allowed_server_ids_set.update(servers)\n\n        allowed_server_ids_set = set(\n            global_mcp_server_manager.filter_server_ids_by_ip(list(allowed_server_ids_set), _rest_client_ip)\n        )\n\n        canonical_server_id: Final = _resolve_mcp_server_id_for_rest(server_id, allowed_server_ids_set, _rest_client_ip)\n\n        if canonical_server_id not in allowed_server_ids_set:\n            _server: Final = global_mcp_server_manager.get_mcp_server_by_id(\n                server_id\n            ) or global_mcp_server_manager.get_mcp_server_by_name(server_id)\n            if (\n                _server is not None\n                and _rest_client_ip is not None\n                and not global_mcp_server_manager._is_server_accessible_from_ip(_server, _rest_client_ip)\n            ):\n                raise HTTPException(\n                    status_code=403,\n                    detail={\n                        \"error\": \"ip_filtering\",\n                        \"message\": (\n                            f\"MCP server '{server_id}' is not accessible from your IP address \"\n                            f\"({_rest_client_ip}). This server is restricted to internal \"\n                            \"networks only. To make it externally accessible, set \"\n                            \"'available_on_public_internet: true' in the server configuration.\"\n                        ),\n                    },\n                )\n            if _server is None:\n                raise HTTPException(\n                    status_code=404,\n                    detail={\n                        \"error\": \"server_not_found\",\n                        \"message\": f\"MCP server '{server_id}' was not found\",\n                    },","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/_experimental/mcp_server/rest_endpoints.py#L449-L485","documentation":"On the REST tool-call route, the requested server exists in the registry but available_on_public_internet is false (the default) and _is_server_accessible_from_ip judges the caller's client IP non-internal, so the proxy refuses with 403 error=ip_filtering. The message embeds the offending client IP and the exact config knob to change.","triggerScenarios":"Calling a restricted internal MCP server over the REST facade from a public/egress IP; or the client IP is derived incorrectly because a reverse proxy does not forward X-Forwarded-For (or the proxy's trusted-proxy handling is misconfigured), making even internal callers appear external.","commonSituations":"Exposing the litellm proxy publicly while leaving default servers internal-only; k8s ingress stripping XFF; on-prem callers behind NAT; security policy requires an explicit opt-in per server before internet exposure.","solutions":["If the server should be internet-reachable, set available_on_public_internet: true on that mcp_servers entry (config.yaml or DB) and reload the proxy.","Otherwise call from an allowed internal network/VPN.","If you believe you are internal: check the reported IP in the message and fix X-Forwarded-For / trusted-proxy forwarding so the real client IP is derived."],"exampleFix":"# before\nmcp_servers:\n  internal-wiki:\n    url: https://wiki.internal\n# -> 403 ip_filtering for external callers\n\n# after\nmcp_servers:\n  internal-wiki:\n    url: https://wiki.internal\n    available_on_public_internet: true","handlingStrategy":"validation","validationCode":"import ipaddress\n\ndef client_ip_can_reach_server(client_ip: str | None, server_public: bool) -> bool:\n    if server_public:\n        return True\n    if not client_ip:\n        return False\n    try:\n        return ipaddress.ip_address(client_ip).is_private or ipaddress.ip_address(client_ip).is_loopback\n    except ValueError:\n        return False\n\nassert client_ip_can_reach_server(my_ip, server_config.get(\"available_on_public_internet\", False))","typeGuard":null,"tryCatchPattern":"resp = await client.post(f\"{proxy}/mcp/tool-call\", json=payload, headers=headers)\nif resp.status_code == 403 and resp.json().get(\"detail\", {}).get(\"error\") == \"ip_filtering\":\n    raise NetworkLocationError(\"call must originate from an internal IP or the server must set available_on_public_internet: true\") from None\nresp.raise_for_status()","preventionTips":["Decide the exposure of every MCP server at registration time and set available_on_public_internet explicitly.","Verify egress IP before integrating from CI/external services.","Keep X-Forwarded-For forwarding correct so internal callers are never misclassified as external."],"tags":["ip-filtering","http-403","network","mcp","configuration","security"],"backgroundTag":"ip-allowlist-blocked","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}