Migrate toggle tool auto approve protobus (#3614)

* migrate toggleToolAutoApprove

* changset

---------

Co-authored-by: Elephant Lumps <celestial_vault@Elephants-MacBook-Pro.local>
This commit is contained in:
Evan 2025-05-20 15:25:46 -07:00 committed by GitHub
parent 6b243ee826
commit 78c3c5eff2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 236 additions and 23 deletions

View File

@ -0,0 +1,5 @@
---
"claude-dev": minor
---
Migrate toggleToolAutoApprove to protobus

View File

@ -13,6 +13,7 @@ service McpService {
rpc downloadMcp(StringRequest) returns (Empty);
rpc restartMcpServer(StringRequest) returns (McpServers);
rpc deleteMcpServer(StringRequest) returns (McpServers);
rpc toggleToolAutoApprove(ToggleToolAutoApproveRequest) returns (McpServers);
}
message ToggleMcpServerRequest {
@ -33,6 +34,13 @@ message AddRemoteMcpServerRequest {
string server_url = 3;
}
message ToggleToolAutoApproveRequest {
Metadata metadata = 1;
string server_name = 2;
repeated string tool_names = 3;
bool auto_approve = 4;
}
message McpTool {
string name = 1;
optional string description = 2;

View File

@ -394,21 +394,6 @@ export class Controller {
// break
// }
case "toggleToolAutoApprove": {
try {
await this.mcpHub?.toggleToolAutoApprove(message.serverName!, message.toolNames!, message.autoApprove!)
} catch (error) {
if (message.toolNames?.length === 1) {
console.error(
`Failed to toggle auto-approve for server ${message.serverName} with tool ${message.toolNames[0]}:`,
error,
)
} else {
console.error(`Failed to toggle auto-approve tools for server ${message.serverName}:`, error)
}
}
break
}
case "toggleWindsurfRule": {
const { rulePath, enabled } = message
if (rulePath && typeof enabled === "boolean") {

View File

@ -8,6 +8,7 @@ import { deleteMcpServer } from "./deleteMcpServer"
import { downloadMcp } from "./downloadMcp"
import { restartMcpServer } from "./restartMcpServer"
import { toggleMcpServer } from "./toggleMcpServer"
import { toggleToolAutoApprove } from "./toggleToolAutoApprove"
import { updateMcpTimeout } from "./updateMcpTimeout"
// Register all mcp service methods
@ -18,5 +19,6 @@ export function registerAllMethods(): void {
registerMethod("downloadMcp", downloadMcp)
registerMethod("restartMcpServer", restartMcpServer)
registerMethod("toggleMcpServer", toggleMcpServer)
registerMethod("toggleToolAutoApprove", toggleToolAutoApprove)
registerMethod("updateMcpTimeout", updateMcpTimeout)
}

View File

@ -0,0 +1,23 @@
import type { ToggleToolAutoApproveRequest, McpServers } from "@shared/proto/mcp"
import type { Controller } from "../index"
import { convertMcpServersToProtoMcpServers } from "@shared/proto-conversions/mcp/mcp-server-conversion"
/**
* Toggles auto-approve setting for MCP server tools
* @param controller The controller instance
* @param request The toggle tool auto-approve request
* @returns Updated list of MCP servers
*/
export async function toggleToolAutoApprove(controller: Controller, request: ToggleToolAutoApproveRequest): Promise<McpServers> {
try {
// Call the RPC variant that returns the servers directly
const mcpServers =
(await controller.mcpHub?.toggleToolAutoApproveRPC(request.serverName, request.toolNames, request.autoApprove)) || []
// Convert application types to proto types
return { mcpServers: convertMcpServersToProtoMcpServers(mcpServers) }
} catch (error) {
console.error(`Failed to toggle tool auto-approve for ${request.serverName}:`, error)
throw error
}
}

View File

@ -793,6 +793,58 @@ export class McpHub {
)
}
/**
* RPC variant of toggleToolAutoApprove that returns the updated servers instead of notifying the webview
* @param serverName The name of the MCP server
* @param toolNames Array of tool names to toggle auto-approve for
* @param shouldAllow Whether to enable or disable auto-approve
* @returns Array of updated MCP servers
*/
async toggleToolAutoApproveRPC(serverName: string, toolNames: string[], shouldAllow: boolean): Promise<McpServer[]> {
try {
const settingsPath = await this.getMcpSettingsFilePath()
const content = await fs.readFile(settingsPath, "utf-8")
const config = JSON.parse(content)
// Initialize autoApprove if it doesn't exist
if (!config.mcpServers[serverName].autoApprove) {
config.mcpServers[serverName].autoApprove = []
}
const autoApprove = config.mcpServers[serverName].autoApprove
for (const toolName of toolNames) {
const toolIndex = autoApprove.indexOf(toolName)
if (shouldAllow && toolIndex === -1) {
// Add tool to autoApprove list
autoApprove.push(toolName)
} else if (!shouldAllow && toolIndex !== -1) {
// Remove tool from autoApprove list
autoApprove.splice(toolIndex, 1)
}
}
await fs.writeFile(settingsPath, JSON.stringify(config, null, 2))
// Update the tools list to reflect the change
const connection = this.connections.find((conn) => conn.server.name === serverName)
if (connection && connection.server.tools) {
// Update the autoApprove property of each tool in the in-memory server object
connection.server.tools = connection.server.tools.map((tool) => ({
...tool,
autoApprove: autoApprove.includes(tool.name),
}))
}
// Return sorted servers without notifying webview
const serverOrder = Object.keys(config.mcpServers || {})
return this.getSortedMcpServers(serverOrder)
} catch (error) {
console.error("Failed to update autoApprove settings:", error)
throw error // Re-throw to ensure the error is properly handled
}
}
async toggleToolAutoApprove(serverName: string, toolNames: string[], shouldAllow: boolean): Promise<void> {
try {
const settingsPath = await this.getMcpSettingsFilePath()

View File

@ -24,7 +24,6 @@ export interface WebviewMessage {
| "browserRelaunchResult"
| "openExtensionSettings"
| "requestVsCodeLmModels"
| "toggleToolAutoApprove"
| "showAccountViewClicked"
| "authStateChanged"
| "authCallback"

View File

@ -71,6 +71,13 @@ export interface AddRemoteMcpServerRequest {
serverUrl: string
}
export interface ToggleToolAutoApproveRequest {
metadata?: Metadata | undefined
serverName: string
toolNames: string[]
autoApprove: boolean
}
export interface McpTool {
name: string
description?: string | undefined
@ -387,6 +394,115 @@ export const AddRemoteMcpServerRequest: MessageFns<AddRemoteMcpServerRequest> =
},
}
function createBaseToggleToolAutoApproveRequest(): ToggleToolAutoApproveRequest {
return { metadata: undefined, serverName: "", toolNames: [], autoApprove: false }
}
export const ToggleToolAutoApproveRequest: MessageFns<ToggleToolAutoApproveRequest> = {
encode(message: ToggleToolAutoApproveRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.metadata !== undefined) {
Metadata.encode(message.metadata, writer.uint32(10).fork()).join()
}
if (message.serverName !== "") {
writer.uint32(18).string(message.serverName)
}
for (const v of message.toolNames) {
writer.uint32(26).string(v!)
}
if (message.autoApprove !== false) {
writer.uint32(32).bool(message.autoApprove)
}
return writer
},
decode(input: BinaryReader | Uint8Array, length?: number): ToggleToolAutoApproveRequest {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = createBaseToggleToolAutoApproveRequest()
while (reader.pos < end) {
const tag = reader.uint32()
switch (tag >>> 3) {
case 1: {
if (tag !== 10) {
break
}
message.metadata = Metadata.decode(reader, reader.uint32())
continue
}
case 2: {
if (tag !== 18) {
break
}
message.serverName = reader.string()
continue
}
case 3: {
if (tag !== 26) {
break
}
message.toolNames.push(reader.string())
continue
}
case 4: {
if (tag !== 32) {
break
}
message.autoApprove = reader.bool()
continue
}
}
if ((tag & 7) === 4 || tag === 0) {
break
}
reader.skip(tag & 7)
}
return message
},
fromJSON(object: any): ToggleToolAutoApproveRequest {
return {
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
serverName: isSet(object.serverName) ? globalThis.String(object.serverName) : "",
toolNames: globalThis.Array.isArray(object?.toolNames) ? object.toolNames.map((e: any) => globalThis.String(e)) : [],
autoApprove: isSet(object.autoApprove) ? globalThis.Boolean(object.autoApprove) : false,
}
},
toJSON(message: ToggleToolAutoApproveRequest): unknown {
const obj: any = {}
if (message.metadata !== undefined) {
obj.metadata = Metadata.toJSON(message.metadata)
}
if (message.serverName !== "") {
obj.serverName = message.serverName
}
if (message.toolNames?.length) {
obj.toolNames = message.toolNames
}
if (message.autoApprove !== false) {
obj.autoApprove = message.autoApprove
}
return obj
},
create<I extends Exact<DeepPartial<ToggleToolAutoApproveRequest>, I>>(base?: I): ToggleToolAutoApproveRequest {
return ToggleToolAutoApproveRequest.fromPartial(base ?? ({} as any))
},
fromPartial<I extends Exact<DeepPartial<ToggleToolAutoApproveRequest>, I>>(object: I): ToggleToolAutoApproveRequest {
const message = createBaseToggleToolAutoApproveRequest()
message.metadata =
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
message.serverName = object.serverName ?? ""
message.toolNames = object.toolNames?.map((e) => e) || []
message.autoApprove = object.autoApprove ?? false
return message
},
}
function createBaseMcpTool(): McpTool {
return { name: "", description: undefined, inputSchema: undefined, autoApprove: undefined }
}
@ -1028,6 +1144,14 @@ export const McpServiceDefinition = {
responseStream: false,
options: {},
},
toggleToolAutoApprove: {
name: "toggleToolAutoApprove",
requestType: ToggleToolAutoApproveRequest,
requestStream: false,
responseType: McpServers,
responseStream: false,
options: {},
},
},
} as const

View File

@ -39,6 +39,7 @@ import { addRemoteMcpServer } from "../core/controller/mcp/addRemoteMcpServer"
import { downloadMcp } from "../core/controller/mcp/downloadMcp"
import { restartMcpServer } from "../core/controller/mcp/restartMcpServer"
import { deleteMcpServer } from "../core/controller/mcp/deleteMcpServer"
import { toggleToolAutoApprove } from "../core/controller/mcp/toggleToolAutoApprove"
// Models Service
import { getOllamaModels } from "../core/controller/models/getOllamaModels"
@ -131,6 +132,7 @@ export function addServices(
downloadMcp: wrapper(downloadMcp, controller),
restartMcpServer: wrapper(restartMcpServer, controller),
deleteMcpServer: wrapper(deleteMcpServer, controller),
toggleToolAutoApprove: wrapper(toggleToolAutoApprove, controller),
})
// Models Service

View File

@ -1,7 +1,8 @@
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
import { McpTool } from "@shared/mcp"
import { vscode } from "@/utils/vscode"
import { useExtensionState } from "@/context/ExtensionStateContext"
import { McpServiceClient } from "@/services/grpc-client"
import { convertProtoMcpServersToMcpServers } from "@shared/proto-conversions/mcp/mcp-server-conversion"
type McpToolRowProps = {
tool: McpTool
@ -11,20 +12,26 @@ type McpToolRowProps = {
const McpToolRow = ({ tool, serverName }: McpToolRowProps) => {
const { autoApprovalSettings } = useExtensionState()
const { setMcpServers } = useExtensionState()
// Accept the event object
const handleAutoApproveChange = (event: any) => {
// Only proceed if the event was triggered by a direct user interaction
if (!serverName) {
return
}
vscode.postMessage({
type: "toggleToolAutoApprove",
McpServiceClient.toggleToolAutoApprove({
serverName,
toolNames: [tool.name],
autoApprove: !tool.autoApprove,
})
.then((response) => {
const mcpServers = convertProtoMcpServersToMcpServers(response.mcpServers)
setMcpServers(mcpServers)
})
.catch((error) => {
console.error("Error toggling tool auto-approve", error)
})
}
return (
<div

View File

@ -134,12 +134,18 @@ const ServerRow = ({
const handleAutoApproveChange = () => {
if (!server.name) return
vscode.postMessage({
type: "toggleToolAutoApprove",
McpServiceClient.toggleToolAutoApprove({
serverName: server.name,
toolNames: server.tools?.map((tool) => tool.name) || [],
autoApprove: !server.tools?.every((tool) => tool.autoApprove),
})
.then((response) => {
const mcpServers = convertProtoMcpServersToMcpServers(response.mcpServers)
setMcpServers(mcpServers)
})
.catch((error) => {
console.error("Error toggling all tools auto-approve", error)
})
}
const handleToggleMcpServer = () => {