BerriAI/litellm · error · HTTPException
Access denied to MCP server {server_id}
Error message
Access denied to MCP server {server_id} What it means
Returned (403) by the OAuth server-resolution helper when a non-admin-view caller references a server that was resolved from the temporary cache. Temporary servers come from the admin-only /server/oauth/session setup flow and are intentionally never exposed to non-admins, so any non-admin hitting them gets this blanket denial regardless of grants.
Source
Thrown at litellm/proxy/management_endpoints/mcp_management_endpoints.py:1806
client_ip: Final = IPAddressUtils.get_mcp_client_ip(request) if request else None
server = global_mcp_server_manager.get_mcp_server_by_id(
server_id
) or global_mcp_server_manager.get_mcp_server_by_name(server_id, client_ip=client_ip)
if server is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail={"error": f"MCP server {server_id} not found"},
)
# Per-server access policy mirrors `fetch_mcp_server`: admin-view
# callers are unrestricted; non-admins must have the server in their
# allowed-servers set. Temporary cached servers come from the
# admin-only `/server/oauth/session` setup flow and are not exposed
# to non-admins.
if not _user_has_admin_view(user_api_key_dict):
if resolved_from_temp_cache:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail={"error": f"Access denied to MCP server {server_id}"},
)
allowed_server_ids: Final[set[str]] = set()
for auth_context in await build_effective_auth_contexts(user_api_key_dict):
allowed_server_ids.update(await global_mcp_server_manager.get_allowed_mcp_servers(auth_context))
if server.server_id not in allowed_server_ids:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail={"error": f"Access denied to MCP server {server_id}"},
)
return server
@router.get(
"/server/oauth/{server_id}/authorize",
include_in_schema=False,
dependencies=[Depends(_mcp_oauth_user_api_key_auth)],
)View on GitHub (pinned to 77b7c6c40c)
Solutions
- Complete OAuth setup flows with the proxy admin/master key.
- For end users, register a permanent server first and run the user-side OAuth flow against its real server_id.
- Regenerate the temp session (it may also have expired) using an admin key.
Defensive patterns
Strategy: validation
Validate before calling
info = requests.get(f"{PROXY}/key/info", headers=AUTH, params={"key": KEY}).json()
role = info.get("key_info", info).get("user_role")
if role != "proxy_admin" and is_temp_session_id(server_id):
raise PermissionError("temp session servers are admin-only; use an admin key") Type guard
def is_temp_session_id(server_id: str) -> bool:
return server_id.startswith("mcp-oauth-session-") # match your deployment's temp id prefix Try / catch
try:
authorize(server_id)
except HTTPError as e:
if e.response.status_code == 403:
raise PermissionError("temp OAuth setup requires the admin key")
raise Prevention
- Never share OAuth setup URLs containing temp session ids with non-admins.
- Run setup flows with the admin key; run user flows against permanent server ids.
When it happens
Trigger: Calling /server/oauth/{temp_session_id}/authorize (or /token) with a non-admin virtual key; a bookmarked OAuth URL containing a temp session id being opened by a regular user; sharing setup links with team members.
Common situations: Admin copies the OAuth setup URL and a teammate opens it with their own (non-admin) key; automation for the OAuth flow accidentally configured with a user-level key.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- User does not have permission to create temporary mcp server
- User does not have permission to view mcp server with id {se
- User does not have permission to create mcp servers. You can
- Call not allowed to delete MCP server. User is not a proxy a
- Error caching temporary mcp server: {e}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/b659fea219dc9f9f.
Report an issue: GitHub.