mirror of
https://github.com/cline/cline.git
synced 2026-09-02 15:52:29 +08:00
feat: check pre-configured MCP server urls and do not parse unless on the allowed list (#8055)
* feat: add ability for enterprise to disable user from adding MCP servers via remote config * use a proper type check instead of an as any assertion * feat: check remote mcp server url against user configured mcp server and do not parse servers not on the allow list if no personal server allowed * feat: Enforce remote config's local MCP market place settings and filter by allowlist and source (#8068) * feat: add parse/load enforcement for local mcp market place servers --------- Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
This commit is contained in:
@@ -24,6 +24,9 @@ export function transformRemoteConfigToStateShape(remoteConfig: RemoteConfig): P
|
||||
if (remoteConfig.blockPersonalRemoteMCPServers !== undefined) {
|
||||
transformed.blockPersonalRemoteMCPServers = remoteConfig.blockPersonalRemoteMCPServers
|
||||
}
|
||||
if (remoteConfig.remoteMCPServers !== undefined) {
|
||||
transformed.remoteMCPServers = remoteConfig.remoteMCPServers
|
||||
}
|
||||
if (remoteConfig.yoloModeAllowed !== undefined) {
|
||||
// only set the yoloModeToggled field if yolo mode is not allowed. Otherwise, we let the user toggle it.
|
||||
if (remoteConfig.yoloModeAllowed === false) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { setTimeout as setTimeoutPromise } from "node:timers/promises"
|
||||
import { sendMcpServersUpdate } from "@core/controller/mcp/subscribeToMcpServers"
|
||||
import { GlobalFileNames } from "@core/storage/disk"
|
||||
import { StateManager } from "@core/storage/StateManager"
|
||||
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js"
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
|
||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
||||
@@ -223,6 +224,50 @@ export class McpHub {
|
||||
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||
|
||||
// Validate remote MCP server URL against remote config if blockPersonalRemoteMCPServers is enabled
|
||||
if (config.type !== "stdio" && "url" in config && config.url) {
|
||||
const stateManager = StateManager.get()
|
||||
const remoteConfig = stateManager.getRemoteConfigSettings()
|
||||
|
||||
if (remoteConfig.blockPersonalRemoteMCPServers === true) {
|
||||
const remoteMCPServers = remoteConfig.remoteMCPServers || []
|
||||
const allowedUrls = remoteMCPServers.map((server) => server.url)
|
||||
|
||||
if (!allowedUrls.includes(config.url)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate local MCP servers based on remote config
|
||||
if (config.type === "stdio") {
|
||||
const stateManager = StateManager.get()
|
||||
const remoteConfig = stateManager.getRemoteConfigSettings()
|
||||
|
||||
// If marketplace is disabled, block all local servers
|
||||
if (remoteConfig.mcpMarketplaceEnabled === false) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if server is from GitHub marketplace
|
||||
if (name.startsWith("github.com/")) {
|
||||
// If allowlist is configured, validate against it
|
||||
if (remoteConfig.allowedMCPServers && remoteConfig.allowedMCPServers.length > 0) {
|
||||
const allowedIds = remoteConfig.allowedMCPServers.map((server: { id: string }) => server.id)
|
||||
|
||||
if (!allowedIds.includes(name)) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If no allowlist, GitHub servers are not allowed
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Non-GitHub local servers are blocked
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (config.disabled) {
|
||||
//console.log(`[MCP Debug] Creating disabled connection object for server "${name}"`)
|
||||
// Create a connection object for disabled server so it appears in UI
|
||||
|
||||
@@ -27,6 +27,7 @@ export type GlobalStateAndSettings = GlobalState & Settings
|
||||
export interface RemoteConfigExtraFields {
|
||||
remoteConfiguredProviders: string[]
|
||||
allowedMCPServers: Array<{ id: string }>
|
||||
remoteMCPServers?: Array<{ name: string; url: string }>
|
||||
remoteGlobalRules?: GlobalInstructionsFile[]
|
||||
remoteGlobalWorkflows?: GlobalInstructionsFile[]
|
||||
blockPersonalRemoteMCPServers?: boolean
|
||||
|
||||
Reference in New Issue
Block a user