fix(security): restrict MCP semantic filter settings to proxy admins

Add an explicit PROXY_ADMIN check on PATCH /update/mcp_semantic_filter_settings
and hide Semantic Filter and Network Settings tabs from non-admin users in
the MCP Servers UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Sameer Kankute 2026-07-01 10:55:54 +05:30
parent b962ce9b09
commit 7292864c05
No known key found for this signature in database
3 changed files with 44 additions and 8 deletions

View file

@ -1160,6 +1160,12 @@ async def update_mcp_semantic_filter_settings(
Update MCP semantic filter settings in database.
Settings will be picked up by all pods within approximately 10 seconds via background polling.
"""
if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN:
raise HTTPException(
status_code=403,
detail="Only proxy admins can update MCP semantic filter settings.",
)
result = await _update_litellm_setting(
settings=settings,
settings_key="mcp_semantic_tool_filter",

View file

@ -2367,3 +2367,29 @@ def test_update_ui_settings_writes_audit_log(monkeypatch):
assert after["disable_custom_api_keys"] is True
finally:
app.dependency_overrides.pop(user_api_key_auth, None)
def test_update_mcp_semantic_filter_settings_requires_proxy_admin(monkeypatch):
"""Non-admin callers must not mutate global MCP semantic filter settings."""
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
async def _internal_user_auth():
return UserAPIKeyAuth(
user_id="internal-user-1",
api_key="hashed-internal-key",
user_role=LitellmUserRoles.INTERNAL_USER,
)
app.dependency_overrides[user_api_key_auth] = _internal_user_auth
try:
resp = client.patch(
"/update/mcp_semantic_filter_settings",
json={"enabled": True, "top_k": 99, "similarity_threshold": 0.01},
)
assert resp.status_code == 403
assert "proxy admin" in resp.json()["detail"].lower()
finally:
app.dependency_overrides.pop(user_api_key_auth, None)

View file

@ -497,8 +497,8 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
<Tab>All Servers</Tab>
<Tab>Toolsets</Tab>
<Tab>Connect</Tab>
<Tab>Semantic Filter</Tab>
<Tab>Network Settings</Tab>
{isAdminRole(userRole) && <Tab>Semantic Filter</Tab>}
{isAdminRole(userRole) && <Tab>Network Settings</Tab>}
{isAdminRole(userRole) && (
<Tab>
<span className="flex items-center gap-2">
@ -652,12 +652,16 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
<TabPanel>
<MCPConnect />
</TabPanel>
<TabPanel>
<MCPSemanticFilterSettings accessToken={accessToken} />
</TabPanel>
<TabPanel>
<MCPNetworkSettings accessToken={accessToken} />
</TabPanel>
{isAdminRole(userRole) && (
<TabPanel>
<MCPSemanticFilterSettings accessToken={accessToken} />
</TabPanel>
)}
{isAdminRole(userRole) && (
<TabPanel>
<MCPNetworkSettings accessToken={accessToken} />
</TabPanel>
)}
{isAdminRole(userRole) && (
<TabPanel>
<MCPSubmissionsTab accessToken={accessToken} />