mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
Merge pull request #18639 from BerriAI/litellm_feat_mcp_global_mode
[feat] mcp global mode
This commit is contained in:
commit
d5e4a43be3
18 changed files with 311 additions and 9 deletions
|
|
@ -198,6 +198,7 @@ mcp_servers:
|
|||
- `http` - Streamable HTTP transport
|
||||
- `stdio` - Standard Input/Output transport
|
||||
- **Command**: The command to execute for stdio transport (required for stdio)
|
||||
- **allow_all_keys**: Set to `true` to make the server available to every LiteLLM API key, even if the key/team doesn't list the server in its MCP permissions.
|
||||
- **Args**: Array of arguments to pass to the command (optional for stdio)
|
||||
- **Env**: Environment variables to set for the stdio process (optional for stdio)
|
||||
- **Description**: Optional description for the server
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ LiteLLM provides fine-grained permission management for MCP servers, allowing yo
|
|||
- **Restrict MCP access by entity**: Control which keys, teams, or organizations can access specific MCP servers
|
||||
- **Tool-level filtering**: Automatically filter available tools based on entity permissions
|
||||
- **Centralized control**: Manage all MCP permissions from the LiteLLM Admin UI or API
|
||||
- **One-click public MCPs**: Mark specific servers as available to every LiteLLM API key when you don't need per-key restrictions
|
||||
|
||||
This ensures that only authorized entities can discover and use MCP tools, providing an additional security layer for your MCP infrastructure.
|
||||
|
||||
|
|
@ -95,6 +96,48 @@ mcp_servers:
|
|||
- If you specify both `allowed_tools` and `disallowed_tools`, the allowed list takes priority
|
||||
- Tool names are case-sensitive
|
||||
|
||||
## Public MCP Servers (allow_all_keys)
|
||||
|
||||
Some MCP servers are meant to be shared broadly—think internal knowledge bases, calendar integrations, or other low-risk utilities where every team should be able to connect without requesting access. Instead of adding those servers to every key, team, or organization, enable the new `allow_all_keys` toggle.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="ui" label="UI">
|
||||
|
||||
1. Open **MCP Servers → Add / Edit** in the Admin UI.
|
||||
2. Expand **Permission Management / Access Control**.
|
||||
3. Toggle **Allow All LiteLLM Keys** on.
|
||||
|
||||
<Image
|
||||
img={require('../img/mcp_allow_all_ui.png')}
|
||||
style={{width: '80%', display: 'block', margin: '1rem auto'}}
|
||||
alt="Allow all LiteLLM keys toggle in MCP UI"
|
||||
/>
|
||||
|
||||
The toggle makes the server “public” without touching existing access groups.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="config" label="config.yaml">
|
||||
|
||||
Set `allow_all_keys: true` to mark the server as public:
|
||||
|
||||
```yaml title="Make an MCP server public" showLineNumbers
|
||||
mcp_servers:
|
||||
deepwiki:
|
||||
url: https://mcp.deepwiki.com/mcp
|
||||
allow_all_keys: true
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### When to use it
|
||||
|
||||
- You have shared MCP utilities where fine-grained ACLs would only add busywork.
|
||||
- You want a “default enabled” experience for internal users, while still being able to layer tool-level restrictions.
|
||||
- You’re onboarding new teams and want the safest MCPs available out of the box.
|
||||
|
||||
Once enabled, LiteLLM automatically includes the server for every key during tool discovery/calls—no extra virtual-key or team configuration is required.
|
||||
|
||||
---
|
||||
|
||||
## Allow/Disallow MCP Tool Parameters
|
||||
|
|
|
|||
BIN
docs/my-website/img/mcp_oauth.png
Normal file
BIN
docs/my-website/img/mcp_oauth.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
|
|
@ -0,0 +1,3 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "LiteLLM_MCPServerTable" ADD COLUMN "allow_all_keys" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
|
|
@ -211,6 +211,7 @@ model LiteLLM_MCPServerTable {
|
|||
authorization_url String?
|
||||
token_url String?
|
||||
registration_url String?
|
||||
allow_all_keys Boolean @default(false)
|
||||
}
|
||||
|
||||
// Generate Tokens for Proxy
|
||||
|
|
@ -748,4 +749,4 @@ model LiteLLM_SkillsTable {
|
|||
created_by String?
|
||||
updated_at DateTime @default(now()) @updatedAt
|
||||
updated_by String?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ class MCPServerManager:
|
|||
allowed_params=server_config.get("allowed_params", None),
|
||||
access_groups=server_config.get("access_groups", None),
|
||||
static_headers=server_config.get("static_headers", None),
|
||||
allow_all_keys=bool(server_config.get("allow_all_keys", False)),
|
||||
)
|
||||
self.config_mcp_servers[server_id] = new_server
|
||||
|
||||
|
|
@ -549,6 +550,7 @@ class MCPServerManager:
|
|||
access_groups=getattr(mcp_server, "mcp_access_groups", None),
|
||||
allowed_tools=getattr(mcp_server, "allowed_tools", None),
|
||||
disallowed_tools=getattr(mcp_server, "disallowed_tools", None),
|
||||
allow_all_keys=mcp_server.allow_all_keys,
|
||||
)
|
||||
return new_server
|
||||
|
||||
|
|
@ -581,6 +583,14 @@ class MCPServerManager:
|
|||
all_servers = list(self.get_registry().values())
|
||||
return {server.server_id for server in all_servers}
|
||||
|
||||
def get_allow_all_keys_server_ids(self) -> List[str]:
|
||||
"""Return server IDs that bypass per-key restrictions."""
|
||||
return [
|
||||
server.server_id
|
||||
for server in self.get_registry().values()
|
||||
if server.allow_all_keys
|
||||
]
|
||||
|
||||
async def get_allowed_mcp_servers(
|
||||
self, user_api_key_auth: Optional[UserAPIKeyAuth] = None
|
||||
) -> List[str]:
|
||||
|
|
@ -593,6 +603,8 @@ class MCPServerManager:
|
|||
if user_api_key_auth and _user_has_admin_view(user_api_key_auth):
|
||||
return list(self.get_registry().keys())
|
||||
|
||||
allow_all_server_ids = self.get_allow_all_keys_server_ids()
|
||||
|
||||
try:
|
||||
allowed_mcp_servers = await MCPRequestHandler.get_allowed_mcp_servers(
|
||||
user_api_key_auth
|
||||
|
|
@ -600,14 +612,17 @@ class MCPServerManager:
|
|||
verbose_logger.debug(
|
||||
f"Allowed MCP Servers for user api key auth: {allowed_mcp_servers}"
|
||||
)
|
||||
if len(allowed_mcp_servers) == 0:
|
||||
combined_servers = set(allowed_mcp_servers)
|
||||
combined_servers.update(allow_all_server_ids)
|
||||
|
||||
if len(combined_servers) == 0:
|
||||
verbose_logger.debug(
|
||||
"No allowed MCP Servers found for user api key auth."
|
||||
)
|
||||
return allowed_mcp_servers
|
||||
return list(combined_servers)
|
||||
except Exception as e:
|
||||
verbose_logger.warning(f"Failed to get allowed MCP servers: {str(e)}.")
|
||||
return []
|
||||
return allow_all_server_ids
|
||||
|
||||
async def get_tools_for_server(self, server_id: str) -> List[MCPTool]:
|
||||
"""
|
||||
|
|
@ -2238,6 +2253,7 @@ class MCPServerManager:
|
|||
authorization_url=server.authorization_url,
|
||||
token_url=server.token_url,
|
||||
registration_url=server.registration_url,
|
||||
allow_all_keys=server.allow_all_keys,
|
||||
)
|
||||
|
||||
async def get_all_mcp_servers_with_health_and_teams(
|
||||
|
|
@ -2331,6 +2347,7 @@ class MCPServerManager:
|
|||
authorization_url=server.authorization_url,
|
||||
token_url=server.token_url,
|
||||
registration_url=server.registration_url,
|
||||
allow_all_keys=server.allow_all_keys,
|
||||
)
|
||||
list_mcp_servers.append(mcp_server_table)
|
||||
|
||||
|
|
|
|||
|
|
@ -1037,6 +1037,7 @@ class NewMCPServerRequest(LiteLLMPydanticObjectBase):
|
|||
authorization_url: Optional[str] = None
|
||||
token_url: Optional[str] = None
|
||||
registration_url: Optional[str] = None
|
||||
allow_all_keys: bool = False
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
|
|
@ -1097,6 +1098,7 @@ class UpdateMCPServerRequest(LiteLLMPydanticObjectBase):
|
|||
authorization_url: Optional[str] = None
|
||||
token_url: Optional[str] = None
|
||||
registration_url: Optional[str] = None
|
||||
allow_all_keys: bool = False
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
|
|
@ -1149,6 +1151,7 @@ class LiteLLM_MCPServerTable(LiteLLMPydanticObjectBase):
|
|||
authorization_url: Optional[str] = None
|
||||
token_url: Optional[str] = None
|
||||
registration_url: Optional[str] = None
|
||||
allow_all_keys: bool = False
|
||||
|
||||
|
||||
class MakeMCPServersPublicRequest(LiteLLMPydanticObjectBase):
|
||||
|
|
@ -3821,4 +3824,4 @@ class LiteLLM_ManagedVectorStoresTable(LiteLLMPydanticObjectBase):
|
|||
|
||||
|
||||
class ResponseLiteLLM_ManagedVectorStore(TypedDict, total=False):
|
||||
vector_store: LiteLLM_ManagedVectorStoresTable
|
||||
vector_store: LiteLLM_ManagedVectorStoresTable
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ if MCP_AVAILABLE:
|
|||
authorization_url=payload.authorization_url,
|
||||
token_url=payload.token_url,
|
||||
registration_url=payload.registration_url,
|
||||
allow_all_keys=payload.allow_all_keys,
|
||||
)
|
||||
|
||||
def get_prisma_client_or_throw(message: str):
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ model LiteLLM_MCPServerTable {
|
|||
authorization_url String?
|
||||
token_url String?
|
||||
registration_url String?
|
||||
allow_all_keys Boolean @default(false)
|
||||
}
|
||||
|
||||
// Generate Tokens for Proxy
|
||||
|
|
@ -748,4 +749,4 @@ model LiteLLM_SkillsTable {
|
|||
created_by String?
|
||||
updated_at DateTime @default(now()) @updatedAt
|
||||
updated_by String?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ from litellm.proxy._types import MCPAuthType, MCPTransportType
|
|||
# MCPInfo now allows arbitrary additional fields for custom metadata
|
||||
MCPInfo = Dict[str, Any]
|
||||
|
||||
|
||||
class MCPOAuthMetadata(BaseModel):
|
||||
scopes: Optional[List[str]] = None
|
||||
authorization_url: Optional[str] = None
|
||||
token_url: Optional[str] = None
|
||||
registration_url: Optional[str] = None
|
||||
|
||||
|
||||
class MCPServer(BaseModel):
|
||||
server_id: str
|
||||
name: str
|
||||
|
|
@ -47,4 +49,5 @@ class MCPServer(BaseModel):
|
|||
args: Optional[List[str]] = None
|
||||
env: Optional[Dict[str, str]] = None
|
||||
access_groups: Optional[List[str]] = None
|
||||
allow_all_keys: bool = False
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ model LiteLLM_MCPServerTable {
|
|||
authorization_url String?
|
||||
token_url String?
|
||||
registration_url String?
|
||||
allow_all_keys Boolean @default(false)
|
||||
}
|
||||
|
||||
// Generate Tokens for Proxy
|
||||
|
|
@ -748,4 +749,4 @@ model LiteLLM_SkillsTable {
|
|||
created_by String?
|
||||
updated_at DateTime @default(now()) @updatedAt
|
||||
updated_by String?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1057,6 +1057,110 @@ async def test_list_tools_multiple_servers_prefixed_names():
|
|||
assert names == ["jira-toolA", "zapier-toolA"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mcp_manager_allows_public_servers_without_permissions():
|
||||
try:
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
MCPServerManager,
|
||||
)
|
||||
from litellm.types.mcp_server.mcp_server_manager import MCPServer
|
||||
from litellm.proxy._types import MCPTransport
|
||||
except ImportError:
|
||||
pytest.skip("MCP server not available")
|
||||
|
||||
manager = MCPServerManager()
|
||||
public_server = MCPServer(
|
||||
server_id="public",
|
||||
name="public",
|
||||
transport=MCPTransport.http,
|
||||
allow_all_keys=True,
|
||||
)
|
||||
manager.registry = {public_server.server_id: public_server}
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.management_endpoints.common_utils._user_has_admin_view",
|
||||
return_value=False,
|
||||
), patch(
|
||||
"litellm.proxy._experimental.mcp_server.mcp_server_manager.MCPRequestHandler.get_allowed_mcp_servers",
|
||||
AsyncMock(return_value=[]),
|
||||
):
|
||||
allowed = await manager.get_allowed_mcp_servers(UserAPIKeyAuth())
|
||||
|
||||
assert allowed == ["public"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mcp_manager_returns_public_when_permission_lookup_fails():
|
||||
try:
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
MCPServerManager,
|
||||
)
|
||||
from litellm.types.mcp_server.mcp_server_manager import MCPServer
|
||||
from litellm.proxy._types import MCPTransport
|
||||
except ImportError:
|
||||
pytest.skip("MCP server not available")
|
||||
|
||||
manager = MCPServerManager()
|
||||
public_server = MCPServer(
|
||||
server_id="public",
|
||||
name="public",
|
||||
transport=MCPTransport.http,
|
||||
allow_all_keys=True,
|
||||
)
|
||||
manager.registry = {public_server.server_id: public_server}
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.management_endpoints.common_utils._user_has_admin_view",
|
||||
return_value=False,
|
||||
), patch(
|
||||
"litellm.proxy._experimental.mcp_server.mcp_server_manager.MCPRequestHandler.get_allowed_mcp_servers",
|
||||
AsyncMock(side_effect=Exception("boom")),
|
||||
):
|
||||
allowed = await manager.get_allowed_mcp_servers(UserAPIKeyAuth())
|
||||
|
||||
assert allowed == ["public"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mcp_manager_merges_public_and_restricted_servers():
|
||||
try:
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
MCPServerManager,
|
||||
)
|
||||
from litellm.types.mcp_server.mcp_server_manager import MCPServer
|
||||
from litellm.proxy._types import MCPTransport
|
||||
except ImportError:
|
||||
pytest.skip("MCP server not available")
|
||||
|
||||
manager = MCPServerManager()
|
||||
public_server = MCPServer(
|
||||
server_id="public",
|
||||
name="public",
|
||||
transport=MCPTransport.http,
|
||||
allow_all_keys=True,
|
||||
)
|
||||
scoped_server = MCPServer(
|
||||
server_id="restricted",
|
||||
name="restricted",
|
||||
transport=MCPTransport.http,
|
||||
)
|
||||
manager.registry = {
|
||||
public_server.server_id: public_server,
|
||||
scoped_server.server_id: scoped_server,
|
||||
}
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.management_endpoints.common_utils._user_has_admin_view",
|
||||
return_value=False,
|
||||
), patch(
|
||||
"litellm.proxy._experimental.mcp_server.mcp_server_manager.MCPRequestHandler.get_allowed_mcp_servers",
|
||||
AsyncMock(return_value=["restricted"]),
|
||||
):
|
||||
allowed = await manager.get_allowed_mcp_servers(UserAPIKeyAuth())
|
||||
|
||||
assert set(allowed) == {"public", "restricted"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_mcp_tool_user_unauthorized_access():
|
||||
"""Test that a user cannot call a tool from a server they don't have access to"""
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { Form } from "antd";
|
||||
|
||||
import MCPPermissionManagement from "./MCPPermissionManagement";
|
||||
|
||||
const defaultProps = {
|
||||
availableAccessGroups: [],
|
||||
mcpServer: null,
|
||||
searchValue: "",
|
||||
setSearchValue: () => {},
|
||||
getAccessGroupOptions: () => [],
|
||||
};
|
||||
|
||||
describe("MCPPermissionManagement", () => {
|
||||
const expandPanel = async () => {
|
||||
const user = userEvent.setup();
|
||||
const headerButton = screen.getByRole("button", {
|
||||
name: /permission management/i,
|
||||
});
|
||||
await user.click(headerButton);
|
||||
return user;
|
||||
};
|
||||
|
||||
const renderWithForm = (props = {}) => {
|
||||
const Wrapper: React.FC = ({ children }) => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<Form form={form} initialValues={{ allow_all_keys: false }}>
|
||||
{children}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
return render(
|
||||
<Wrapper>
|
||||
<MCPPermissionManagement {...defaultProps} {...props} />
|
||||
</Wrapper>,
|
||||
);
|
||||
};
|
||||
|
||||
it("should default allow_all_keys switch to unchecked for new servers", async () => {
|
||||
renderWithForm();
|
||||
await expandPanel();
|
||||
const toggle = screen.getByRole("switch");
|
||||
expect(toggle).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
it("should reflect allow_all_keys when editing an existing server", async () => {
|
||||
renderWithForm({
|
||||
mcpServer: {
|
||||
server_id: "server-1",
|
||||
url: "https://example.com",
|
||||
created_at: "2024-01-01T00:00:00Z",
|
||||
created_by: "user",
|
||||
updated_at: "2024-01-01T00:00:00Z",
|
||||
updated_by: "user",
|
||||
allow_all_keys: true,
|
||||
},
|
||||
});
|
||||
|
||||
const user = await expandPanel();
|
||||
const toggle = screen.getByRole("switch");
|
||||
expect(toggle).toHaveAttribute("aria-checked", "true");
|
||||
|
||||
await user.click(toggle);
|
||||
expect(toggle).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Form, Select, Tooltip, Collapse, Input, Space, Button } from "antd";
|
||||
import { Form, Select, Tooltip, Collapse, Input, Space, Button, Switch } from "antd";
|
||||
import { InfoCircleOutlined, MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
|
||||
import { MCPServer } from "./types";
|
||||
const { Panel } = Collapse;
|
||||
|
|
@ -38,6 +38,11 @@ const MCPPermissionManagement: React.FC<MCPPermissionManagementProps> = ({
|
|||
}));
|
||||
form.setFieldValue("static_headers", staticHeaders);
|
||||
}
|
||||
if (typeof mcpServer.allow_all_keys === "boolean") {
|
||||
form.setFieldValue("allow_all_keys", mcpServer.allow_all_keys);
|
||||
}
|
||||
} else {
|
||||
form.setFieldValue("allow_all_keys", false);
|
||||
}
|
||||
}, [mcpServer, form]);
|
||||
|
||||
|
|
@ -57,6 +62,26 @@ const MCPPermissionManagement: React.FC<MCPPermissionManagementProps> = ({
|
|||
className="border-0"
|
||||
>
|
||||
<div className="space-y-6 pt-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Allow All LiteLLM Keys
|
||||
<Tooltip title="When enabled, every API key can access this MCP server.">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<p className="text-sm text-gray-600 mt-1">Enable if this server should be "public" to all keys.</p>
|
||||
</div>
|
||||
<Form.Item
|
||||
name="allow_all_keys"
|
||||
valuePropName="checked"
|
||||
initialValue={mcpServer?.allow_all_keys ?? false}
|
||||
className="mb-0"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
static_headers: staticHeadersList,
|
||||
stdio_config: rawStdioConfig,
|
||||
credentials: credentialValues,
|
||||
allow_all_keys: allowAllKeysRaw,
|
||||
...restValues
|
||||
} = values;
|
||||
|
||||
|
|
@ -278,6 +279,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
|||
mcp_access_groups: accessGroups,
|
||||
alias: restValues.alias,
|
||||
allowed_tools: allowedTools.length > 0 ? allowedTools : null,
|
||||
allow_all_keys: Boolean(allowAllKeysRaw),
|
||||
static_headers: staticHeaders,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -286,7 +286,12 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
if (!accessToken) return;
|
||||
try {
|
||||
// Ensure access groups is always a string array
|
||||
const { static_headers: staticHeadersList, credentials: credentialValues, ...restValues } = values;
|
||||
const {
|
||||
static_headers: staticHeadersList,
|
||||
credentials: credentialValues,
|
||||
allow_all_keys: allowAllKeysRaw,
|
||||
...restValues
|
||||
} = values;
|
||||
|
||||
const accessGroups = (restValues.mcp_access_groups || []).map((g: any) =>
|
||||
typeof g === "string" ? g : g.name || String(g),
|
||||
|
|
@ -339,6 +344,7 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({
|
|||
allowed_tools: allowedTools.length > 0 ? allowedTools : null,
|
||||
disallowed_tools: restValues.disallowed_tools || [],
|
||||
static_headers: staticHeaders,
|
||||
allow_all_keys: Boolean(allowAllKeysRaw ?? mcpServer.allow_all_keys),
|
||||
};
|
||||
|
||||
const includeCredentials = restValues.auth_type && AUTH_TYPES_REQUIRING_CREDENTIALS.includes(restValues.auth_type);
|
||||
|
|
|
|||
|
|
@ -229,6 +229,25 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
|
|||
<Text className="font-medium">Auth Type</Text>
|
||||
<div>{handleAuth(mcpServer.auth_type)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<Text className="font-medium">Allow All LiteLLM Keys</Text>
|
||||
<div className="flex items-center gap-2">
|
||||
{mcpServer.allow_all_keys ? (
|
||||
<span className="px-2 py-1 bg-green-50 text-green-700 rounded-md text-sm">
|
||||
Enabled
|
||||
</span>
|
||||
) : (
|
||||
<span className="px-2 py-1 bg-gray-100 text-gray-600 rounded-md text-sm">
|
||||
Disabled
|
||||
</span>
|
||||
)}
|
||||
{mcpServer.allow_all_keys && (
|
||||
<Text className="text-xs text-gray-500">
|
||||
All keys can access this MCP server
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Text className="font-medium">Access Groups</Text>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ export interface MCPServer {
|
|||
teams?: Team[];
|
||||
mcp_access_groups?: string[];
|
||||
allowed_tools?: string[];
|
||||
allow_all_keys?: boolean;
|
||||
}
|
||||
|
||||
export interface MCPServerProps {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue