Skip to content

Commit c7166d0

Browse files
authored
Merge pull request #97 from RooVetGit/mcp_global_checkbox
More safety around always allowing MCP
2 parents ed626a6 + 23efdea commit c7166d0

File tree

9 files changed

+51
-8
lines changed

9 files changed

+51
-8
lines changed

src/core/prompts/system.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,8 @@ npm run build
633633
634634
5. Install the MCP Server by adding the MCP server configuration to the settings file located at '${await mcpHub.getMcpSettingsFilePath()}'. The settings file may have other MCP servers already configured, so you would read it first and then add your new server to the existing \`mcpServers\` object.
635635
636+
IMPORTANT: Regardless of what else you see in the settings file, you must not set any defaults for the \`alwaysAllow\` array in the newly added MCP server.
637+
636638
\`\`\`json
637639
{
638640
"mcpServers": {

src/core/webview/ClineProvider.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type GlobalStateKey =
6767
| "allowedCommands"
6868
| "soundEnabled"
6969
| "diffEnabled"
70+
| "alwaysAllowMcp"
7071

7172
export const GlobalFileNames = {
7273
apiConversationHistory: "api_conversation_history.json",
@@ -456,6 +457,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
456457
await this.updateGlobalState("alwaysAllowBrowser", message.bool ?? undefined)
457458
await this.postStateToWebview()
458459
break
460+
case "alwaysAllowMcp":
461+
await this.updateGlobalState("alwaysAllowMcp", message.bool)
462+
await this.postStateToWebview()
463+
break
459464
case "askResponse":
460465
this.cline?.handleWebviewAskResponse(message.askResponse!, message.text, message.images)
461466
break
@@ -904,6 +909,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
904909
alwaysAllowWrite,
905910
alwaysAllowExecute,
906911
alwaysAllowBrowser,
912+
alwaysAllowMcp,
907913
soundEnabled,
908914
diffEnabled,
909915
taskHistory,
@@ -921,6 +927,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
921927
alwaysAllowWrite: alwaysAllowWrite ?? false,
922928
alwaysAllowExecute: alwaysAllowExecute ?? false,
923929
alwaysAllowBrowser: alwaysAllowBrowser ?? false,
930+
alwaysAllowMcp: alwaysAllowMcp ?? false,
924931
uriScheme: vscode.env.uriScheme,
925932
clineMessages: this.cline?.clineMessages || [],
926933
taskHistory: (taskHistory || [])
@@ -1017,6 +1024,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
10171024
alwaysAllowWrite,
10181025
alwaysAllowExecute,
10191026
alwaysAllowBrowser,
1027+
alwaysAllowMcp,
10201028
taskHistory,
10211029
allowedCommands,
10221030
soundEnabled,
@@ -1053,6 +1061,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
10531061
this.getGlobalState("alwaysAllowWrite") as Promise<boolean | undefined>,
10541062
this.getGlobalState("alwaysAllowExecute") as Promise<boolean | undefined>,
10551063
this.getGlobalState("alwaysAllowBrowser") as Promise<boolean | undefined>,
1064+
this.getGlobalState("alwaysAllowMcp") as Promise<boolean | undefined>,
10561065
this.getGlobalState("taskHistory") as Promise<HistoryItem[] | undefined>,
10571066
this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
10581067
this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
@@ -1107,6 +1116,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
11071116
alwaysAllowWrite: alwaysAllowWrite ?? false,
11081117
alwaysAllowExecute: alwaysAllowExecute ?? false,
11091118
alwaysAllowBrowser: alwaysAllowBrowser ?? false,
1119+
alwaysAllowMcp: alwaysAllowMcp ?? false,
11101120
taskHistory,
11111121
allowedCommands,
11121122
soundEnabled,

src/shared/ExtensionMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export interface ExtensionState {
4747
alwaysAllowWrite?: boolean
4848
alwaysAllowExecute?: boolean
4949
alwaysAllowBrowser?: boolean
50+
alwaysAllowMcp?: boolean
5051
uriScheme?: string
5152
allowedCommands?: string[]
5253
soundEnabled?: boolean

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface WebviewMessage {
2929
| "cancelTask"
3030
| "refreshOpenRouterModels"
3131
| "alwaysAllowBrowser"
32+
| "alwaysAllowMcp"
3233
| "playSound"
3334
| "soundEnabled"
3435
| "diffEnabled"

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface ChatViewProps {
3737
export const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
3838

3939
const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryView }: ChatViewProps) => {
40-
const { version, clineMessages: messages, taskHistory, apiConfiguration, mcpServers, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, allowedCommands } = useExtensionState()
40+
const { version, clineMessages: messages, taskHistory, apiConfiguration, mcpServers, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, alwaysAllowMcp, allowedCommands } = useExtensionState()
4141

4242
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
4343
const task = useMemo(() => messages.at(0), [messages]) // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see Cline.abort)
@@ -803,11 +803,11 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
803803
(alwaysAllowReadOnly && clineAsk === "tool" && isReadOnlyToolAction()) ||
804804
(alwaysAllowWrite && clineAsk === "tool" && isWriteToolAction()) ||
805805
(alwaysAllowExecute && clineAsk === "command" && isAllowedCommand()) ||
806-
(clineAsk === "use_mcp_server" && isMcpToolAlwaysAllowed())
806+
(alwaysAllowMcp && clineAsk === "use_mcp_server" && isMcpToolAlwaysAllowed())
807807
) {
808808
handlePrimaryButtonClick()
809809
}
810-
}, [clineAsk, enableButtons, handlePrimaryButtonClick, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, messages, allowedCommands, mcpServers])
810+
}, [clineAsk, enableButtons, handlePrimaryButtonClick, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, alwaysAllowMcp, messages, allowedCommands, mcpServers])
811811

812812
return (
813813
<div

webview-ui/src/components/mcp/McpToolRow.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { vscode } from "../../utils/vscode"
55
type McpToolRowProps = {
66
tool: McpTool
77
serverName?: string
8+
alwaysAllowMcp?: boolean
89
}
910

10-
const McpToolRow = ({ tool, serverName }: McpToolRowProps) => {
11+
const McpToolRow = ({ tool, serverName, alwaysAllowMcp }: McpToolRowProps) => {
1112
const handleAlwaysAllowChange = () => {
1213
if (!serverName) return;
1314

@@ -33,7 +34,7 @@ const McpToolRow = ({ tool, serverName }: McpToolRowProps) => {
3334
<span className="codicon codicon-symbol-method" style={{ marginRight: "6px" }}></span>
3435
<span style={{ fontWeight: 500 }}>{tool.name}</span>
3536
</div>
36-
{serverName && (
37+
{serverName && alwaysAllowMcp && (
3738
<VSCodeCheckbox
3839
checked={tool.alwaysAllow}
3940
onChange={handleAlwaysAllowChange}

webview-ui/src/components/mcp/McpView.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type McpViewProps = {
1717
}
1818

1919
const McpView = ({ onDone }: McpViewProps) => {
20-
const { mcpServers: servers } = useExtensionState()
20+
const { mcpServers: servers, alwaysAllowMcp } = useExtensionState()
2121
// const [servers, setServers] = useState<McpServer[]>([
2222
// // Add some mock servers for testing
2323
// {
@@ -126,7 +126,7 @@ const McpView = ({ onDone }: McpViewProps) => {
126126
{servers.length > 0 && (
127127
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
128128
{servers.map((server) => (
129-
<ServerRow key={server.name} server={server} />
129+
<ServerRow key={server.name} server={server} alwaysAllowMcp={alwaysAllowMcp} />
130130
))}
131131
</div>
132132
)}
@@ -152,7 +152,7 @@ const McpView = ({ onDone }: McpViewProps) => {
152152
}
153153

154154
// Server Row Component
155-
const ServerRow = ({ server }: { server: McpServer }) => {
155+
const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer, alwaysAllowMcp?: boolean }) => {
156156
const [isExpanded, setIsExpanded] = useState(false)
157157

158158
const getStatusColor = () => {
@@ -260,6 +260,7 @@ const ServerRow = ({ server }: { server: McpServer }) => {
260260
key={tool.name}
261261
tool={tool}
262262
serverName={server.name}
263+
alwaysAllowMcp={alwaysAllowMcp}
263264
/>
264265
))}
265266
</div>

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
2525
setAlwaysAllowExecute,
2626
alwaysAllowBrowser,
2727
setAlwaysAllowBrowser,
28+
alwaysAllowMcp,
29+
setAlwaysAllowMcp,
2830
soundEnabled,
2931
setSoundEnabled,
3032
diffEnabled,
@@ -50,6 +52,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
5052
vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
5153
vscode.postMessage({ type: "alwaysAllowExecute", bool: alwaysAllowExecute })
5254
vscode.postMessage({ type: "alwaysAllowBrowser", bool: alwaysAllowBrowser })
55+
vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp })
5356
vscode.postMessage({ type: "allowedCommands", commands: allowedCommands ?? [] })
5457
vscode.postMessage({ type: "soundEnabled", bool: soundEnabled })
5558
vscode.postMessage({ type: "diffEnabled", bool: diffEnabled })
@@ -195,7 +198,29 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
195198
color: "var(--vscode-errorForeground)",
196199
}}>
197200
⚠️ WARNING: When enabled, Cline will automatically perform browser actions without requiring approval. This is potentially very dangerous and could lead to unwanted system modifications or security risks. Enable only if you fully trust the AI and understand the risks.<br/><br/>NOTE: The checkbox only applies when the model supports computer use.
201+
</p>
202+
</div>
198203

204+
<div style={{ marginBottom: 5 }}>
205+
<VSCodeCheckbox
206+
checked={alwaysAllowMcp}
207+
onChange={(e: any) => {
208+
setAlwaysAllowMcp(e.target.checked)
209+
vscode.postMessage({ type: "alwaysAllowMcp", bool: e.target.checked })
210+
}}>
211+
<span style={{ fontWeight: "500" }}>Always approve MCP tools</span>
212+
</VSCodeCheckbox>
213+
<p
214+
style={{
215+
fontSize: "12px",
216+
marginTop: "5px",
217+
padding: "8px",
218+
backgroundColor: "var(--vscode-errorBackground)",
219+
border: "1px solid var(--vscode-errorBorder)",
220+
borderRadius: "4px",
221+
color: "var(--vscode-errorForeground)",
222+
}}>
223+
⚠️ WARNING: When enabled, you can set individual MCP tools to auto-approve in the MCP Servers view. A tool will only be auto-approved if both this setting and the tool's individual "Always allow" checkbox are enabled. This is potentially very dangerous and could lead to unwanted system modifications or security risks. Enable only if you fully trust the AI and understand the risks.
199224
</p>
200225
</div>
201226

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export interface ExtensionStateContextType extends ExtensionState {
2525
setAlwaysAllowWrite: (value: boolean) => void
2626
setAlwaysAllowExecute: (value: boolean) => void
2727
setAlwaysAllowBrowser: (value: boolean) => void
28+
setAlwaysAllowMcp: (value: boolean) => void
2829
setShowAnnouncement: (value: boolean) => void
2930
setAllowedCommands: (value: string[]) => void
3031
setSoundEnabled: (value: boolean) => void
@@ -134,6 +135,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
134135
setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
135136
setAlwaysAllowExecute: (value) => setState((prevState) => ({ ...prevState, alwaysAllowExecute: value })),
136137
setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })),
138+
setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })),
137139
setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
138140
setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })),
139141
setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })),

0 commit comments

Comments
 (0)