{"record":{"id":"cf99bb90f2b383b8","repo":"BerriAI/litellm","slug":"user-does-not-have-permission-to-create-mcp-server","errorCode":null,"errorMessage":"User does not have permission to create mcp servers. You can only create mcp servers if you are a PROXY_ADMIN.","messagePattern":"User does not have permission to create mcp servers\\. You can only create mcp servers if you are a PROXY_ADMIN\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"litellm/proxy/management_endpoints/mcp_management_endpoints.py","lineNumber":1543,"sourceCode":"        payload: NewMCPServerRequest,\n        user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),\n        litellm_changed_by: str | None = Header(\n            None,\n            description=\"The litellm-changed-by header enables tracking of actions performed by authorized users on behalf of other users, providing an audit trail for accountability\",\n        ),\n    ):\n        \"\"\"\n        Allow users to add a new external mcp server.\n        \"\"\"\n        prisma_client: Final = get_prisma_client_or_throw(\"Database not connected. Connect a database to your proxy\")\n\n        # Validate and normalize payload fields\n        validate_and_normalize_mcp_server_payload(payload)\n        stamp_omitted_oauth2_flow(payload)\n\n        # AuthZ - restrict only proxy admins to create mcp servers\n        if LitellmUserRoles.PROXY_ADMIN != user_api_key_dict.user_role:\n            raise HTTPException(\n                status_code=status.HTTP_403_FORBIDDEN,\n                detail={\n                    \"error\": \"User does not have permission to create mcp servers. You can only create mcp servers if you are a PROXY_ADMIN.\"\n                },\n            )\n\n        # Block reserved special server IDs\n        if (\n            SpecialMCPServerName.all_team_servers == payload.server_id\n            or SpecialMCPServerName.all_proxy_servers == payload.server_id\n        ):\n            raise HTTPException(\n                status_code=status.HTTP_400_BAD_REQUEST,\n                detail={\"error\": f\"MCP Server with id {payload.server_id} is special and cannot be used.\"},\n            )\n\n        if payload.server_id is not None:\n            # fail if the mcp server with id already exists","sourceCodeStart":1525,"sourceCodeEnd":1561,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/mcp_management_endpoints.py#L1525-L1561","documentation":"Returned (403) by the create MCP server endpoint because it restricts creation to exactly LitellmUserRoles.PROXY_ADMIN — the check is strict role equality on user_api_key_dict.user_role, so internal users, team admins, and org admins are all rejected. The guard runs after payload validation but before any uniqueness or reserved-id checks.","triggerScenarios":"POST to the mcp server create endpoint with an internal-user or team virtual key; a team admin trying to self-serve an MCP server; any key whose user_role is not PROXY_ADMIN (note the master key authenticates as proxy admin and passes).","commonSituations":"Teams trying to register their own MCP servers without proxy-admin involvement; scripts run with a user-level key instead of the master key; assuming team-admin rank implies MCP create rights.","solutions":["Re-run the call with the proxy master key or a key belonging to a PROXY_ADMIN user.","Check the calling key's role first via /key/info (or user info) and only attempt creation when user_role is proxy_admin.","Have a proxy admin pre-create the server and grant it to the team."],"exampleFix":"# before: team admin key\nrequests.post(f\"{PROXY}/v1/mcp/server\", headers={\"Authorization\": f\"Bearer {TEAM_ADMIN_KEY}\"}, json=payload)\n\n# after: proxy master key (role == proxy_admin)\nrequests.post(f\"{PROXY}/v1/mcp/server\", headers={\"Authorization\": f\"Bearer {os.environ['LITELLM_MASTER_KEY']}\"}, json=payload)","handlingStrategy":"validation","validationCode":"info = requests.get(f\"{PROXY}/key/info\", headers=AUTH, params={\"key\": KEY}).json()\nrole = info.get(\"key_info\", info).get(\"user_role\")\nif role != \"proxy_admin\":\n    raise PermissionError(\"MCP server creation requires a PROXY_ADMIN key\")","typeGuard":"def is_proxy_admin(key_info: dict) -> bool:\n    return key_info.get(\"user_role\") == \"proxy_admin\"","tryCatchPattern":"try:\n    create_server(payload)\nexcept HTTPError as e:\n    if e.response.status_code == 403:\n        raise PermissionError(\"re-run with the proxy master key or a proxy-admin user's key\")\n    raise","preventionTips":["Keep a dedicated PROXY_ADMIN key for provisioning scripts.","Check user_role via /key/info before management calls.","Never assume team-admin rank grants MCP create rights."],"tags":["litellm","mcp","forbidden","authorization","proxy-admin"],"backgroundTag":"authorization-forbidden","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}