mirror of
https://github.com/cline/cline.git
synced 2025-06-03 03:59:07 +00:00
PROTOBUS: toggleMcpServer (#3063)
* wip * migrate toggleMcpServer * changeset * support optional types and enum type
This commit is contained in:
parent
4af5150823
commit
dfcb3d5d9b
5
.changeset/wise-roses-wink.md
Normal file
5
.changeset/wise-roses-wink.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate the toggleMcpServer message to protobus
|
@ -114,6 +114,7 @@ async function generateMethodRegistrations() {
|
||||
console.log(chalk.cyan("Generating method registration files..."))
|
||||
|
||||
const serviceDirs = [
|
||||
path.join(ROOT_DIR, "src", "core", "controller", "mcp"),
|
||||
path.join(ROOT_DIR, "src", "core", "controller", "browser"),
|
||||
path.join(ROOT_DIR, "src", "core", "controller", "checkpoints"),
|
||||
// Add more service directories here as needed
|
||||
|
60
proto/mcp.proto
Normal file
60
proto/mcp.proto
Normal file
@ -0,0 +1,60 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cline;
|
||||
|
||||
import "common.proto";
|
||||
|
||||
service McpService {
|
||||
rpc toggleMcpServer(ToggleMcpServerRequest) returns (McpServers);
|
||||
}
|
||||
|
||||
message McpTool {
|
||||
string name = 1;
|
||||
optional string description = 2;
|
||||
optional string input_schema = 3;
|
||||
optional bool auto_approve = 4;
|
||||
}
|
||||
|
||||
message McpResource {
|
||||
string uri = 1;
|
||||
string name = 2;
|
||||
optional string mime_type = 3;
|
||||
optional string description = 4;
|
||||
}
|
||||
|
||||
message McpResourceTemplate {
|
||||
string uri_template = 1;
|
||||
string name = 2;
|
||||
optional string mime_type = 3;
|
||||
optional string description = 4;
|
||||
}
|
||||
|
||||
enum McpServerStatus {
|
||||
// Protobuf enums (in proto3) must have a zero value defined, which serves as the default if the field isn't explicitly set.
|
||||
// To align with the required nature of the TypeScript type and avoid an unnecessary UNSPECIFIED state, we map one of the existing statuses to this zero value.
|
||||
MCP_SERVER_STATUS_DISCONNECTED = 0; // default
|
||||
MCP_SERVER_STATUS_CONNECTED = 1;
|
||||
MCP_SERVER_STATUS_CONNECTING = 2;
|
||||
}
|
||||
|
||||
message McpServer {
|
||||
string name = 1;
|
||||
string config = 2;
|
||||
McpServerStatus status = 3;
|
||||
optional string error = 4;
|
||||
repeated McpTool tools = 5;
|
||||
repeated McpResource resources = 6;
|
||||
repeated McpResourceTemplate resource_templates = 7;
|
||||
optional bool disabled = 8;
|
||||
optional int32 timeout = 9;
|
||||
}
|
||||
|
||||
message ToggleMcpServerRequest {
|
||||
Metadata metadata = 1;
|
||||
string server_name = 2;
|
||||
bool disabled = 3;
|
||||
}
|
||||
|
||||
message McpServers {
|
||||
repeated McpServer mcp_servers = 1;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { Controller } from "./index"
|
||||
import { handleBrowserServiceRequest } from "./browser/index"
|
||||
import { handleCheckpointsDiffServiceRequest } from "./checkpoints"
|
||||
import { handleMcpServiceRequest } from "./mcp"
|
||||
|
||||
/**
|
||||
* Handles gRPC requests from the webview
|
||||
@ -38,6 +39,11 @@ export class GrpcHandler {
|
||||
message: await handleCheckpointsDiffServiceRequest(this.controller, method, message),
|
||||
request_id: requestId,
|
||||
}
|
||||
case "cline.McpService":
|
||||
return {
|
||||
message: await handleMcpServiceRequest(this.controller, method, message),
|
||||
request_id: requestId,
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown service: ${service}`)
|
||||
}
|
||||
|
@ -588,14 +588,6 @@ export class Controller {
|
||||
|
||||
// break
|
||||
// }
|
||||
case "toggleMcpServer": {
|
||||
try {
|
||||
await this.mcpHub?.toggleServerDisabled(message.serverName!, message.disabled!)
|
||||
} catch (error) {
|
||||
console.error(`Failed to toggle MCP server ${message.serverName}:`, error)
|
||||
}
|
||||
break
|
||||
}
|
||||
case "toggleToolAutoApprove": {
|
||||
try {
|
||||
await this.mcpHub?.toggleToolAutoApprove(message.serverName!, message.toolNames!, message.autoApprove!)
|
||||
|
15
src/core/controller/mcp/index.ts
Normal file
15
src/core/controller/mcp/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { createServiceRegistry, ServiceMethodHandler } from "../grpc-service"
|
||||
import { registerAllMethods } from "./methods"
|
||||
|
||||
// Create MCP service registry
|
||||
const mcpService = createServiceRegistry("mcp")
|
||||
|
||||
// Export the method handler type and registration function
|
||||
export type McpMethodHandler = ServiceMethodHandler
|
||||
export const registerMethod = mcpService.registerMethod
|
||||
|
||||
// Export the request handler
|
||||
export const handleMcpServiceRequest = mcpService.handleRequest
|
||||
|
||||
// Register all mcp methods
|
||||
registerAllMethods()
|
12
src/core/controller/mcp/methods.ts
Normal file
12
src/core/controller/mcp/methods.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// AUTO-GENERATED FILE - DO NOT MODIFY DIRECTLY
|
||||
// Generated by proto/build-proto.js
|
||||
|
||||
// Import all method implementations
|
||||
import { registerMethod } from "./index"
|
||||
import { toggleMcpServer } from "./toggleMcpServer"
|
||||
|
||||
// Register all mcp service methods
|
||||
export function registerAllMethods(): void {
|
||||
// Register each method with the registry
|
||||
registerMethod("toggleMcpServer", toggleMcpServer)
|
||||
}
|
23
src/core/controller/mcp/toggleMcpServer.ts
Normal file
23
src/core/controller/mcp/toggleMcpServer.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { ToggleMcpServerRequest, McpServers } from "../../../shared/proto/mcp"
|
||||
import type { Controller } from "../index"
|
||||
import { convertMcpServersToProtoMcpServers } from "../../../shared/proto-conversions/mcp/mcp-server-conversion"
|
||||
|
||||
/**
|
||||
* Toggles an MCP server's enabled/disabled status
|
||||
* @param controller The controller instance
|
||||
* @param request The request containing server ID and disabled status
|
||||
* @returns A response indicating success or failure
|
||||
*/
|
||||
export async function toggleMcpServer(controller: Controller, request: ToggleMcpServerRequest): Promise<McpServers> {
|
||||
try {
|
||||
const mcpServers = await controller.mcpHub?.toggleServerDisabledRPC(request.serverName, request.disabled)
|
||||
|
||||
// Convert from McpServer[] to ProtoMcpServer[] ensuring all required fields are set
|
||||
const protoServers = convertMcpServersToProtoMcpServers(mcpServers)
|
||||
|
||||
return { mcpServers: protoServers }
|
||||
} catch (error) {
|
||||
console.error(`Failed to toggle MCP server ${request.serverName}:`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
@ -501,7 +501,7 @@ export class McpHub {
|
||||
|
||||
// Public methods for server management
|
||||
|
||||
public async toggleServerDisabled(serverName: string, disabled: boolean): Promise<void> {
|
||||
public async toggleServerDisabledRPC(serverName: string, disabled: boolean): Promise<McpServer[]> {
|
||||
try {
|
||||
const config = await this.readAndValidateMcpSettingsFile()
|
||||
if (!config) {
|
||||
@ -519,8 +519,20 @@ export class McpHub {
|
||||
connection.server.disabled = disabled
|
||||
}
|
||||
|
||||
await this.notifyWebviewOfServerChanges()
|
||||
const serverOrder = Object.keys(config.mcpServers || {})
|
||||
|
||||
const mcpServers = [...this.connections]
|
||||
.sort((a, b) => {
|
||||
const indexA = serverOrder.indexOf(a.server.name)
|
||||
const indexB = serverOrder.indexOf(b.server.name)
|
||||
return indexA - indexB
|
||||
})
|
||||
.map((connection) => connection.server)
|
||||
|
||||
return mcpServers
|
||||
}
|
||||
console.error(`Server "${serverName}" not found in MCP configuration`)
|
||||
throw new Error(`Server "${serverName}" not found in MCP configuration`)
|
||||
} catch (error) {
|
||||
console.error("Failed to update server disabled state:", error)
|
||||
if (error instanceof Error) {
|
||||
|
153
src/shared/proto-conversions/mcp/mcp-server-conversion.ts
Normal file
153
src/shared/proto-conversions/mcp/mcp-server-conversion.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import { McpServer, McpTool, McpResource, McpResourceTemplate } from "../../mcp"
|
||||
import {
|
||||
McpServer as ProtoMcpServer,
|
||||
McpTool as ProtoMcpTool,
|
||||
McpResource as ProtoMcpResource,
|
||||
McpResourceTemplate as ProtoMcpResourceTemplate,
|
||||
McpServerStatus,
|
||||
} from "../../proto/mcp"
|
||||
|
||||
// Helper to convert TS status to Proto enum
|
||||
function convertMcpStatusToProto(status: McpServer["status"]): McpServerStatus {
|
||||
switch (status) {
|
||||
case "connected":
|
||||
return McpServerStatus.MCP_SERVER_STATUS_CONNECTED
|
||||
case "connecting":
|
||||
return McpServerStatus.MCP_SERVER_STATUS_CONNECTING
|
||||
case "disconnected":
|
||||
return McpServerStatus.MCP_SERVER_STATUS_DISCONNECTED
|
||||
}
|
||||
}
|
||||
|
||||
export function convertMcpServersToProtoMcpServers(mcpServers: McpServer[]): ProtoMcpServer[] {
|
||||
const protoServers: ProtoMcpServer[] = mcpServers.map((server) => ({
|
||||
name: server.name,
|
||||
config: server.config,
|
||||
status: convertMcpStatusToProto(server.status),
|
||||
error: server.error,
|
||||
|
||||
// Convert nested types
|
||||
tools: (server.tools || []).map(convertTool),
|
||||
resources: (server.resources || []).map(convertResource),
|
||||
resourceTemplates: (server.resourceTemplates || []).map(convertResourceTemplate),
|
||||
|
||||
disabled: server.disabled,
|
||||
timeout: server.timeout,
|
||||
}))
|
||||
return protoServers
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts McpTool to ProtoMcpTool format, ensuring all required fields have values
|
||||
*/
|
||||
function convertTool(tool: McpTool): ProtoMcpTool {
|
||||
const inputSchemaString = tool.inputSchema
|
||||
? typeof tool.inputSchema === "object"
|
||||
? JSON.stringify(tool.inputSchema)
|
||||
: tool.inputSchema
|
||||
: undefined
|
||||
|
||||
return {
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
inputSchema: inputSchemaString,
|
||||
autoApprove: tool.autoApprove,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts McpResource to ProtoMcpResource format, ensuring all required fields have values
|
||||
*/
|
||||
function convertResource(resource: McpResource): ProtoMcpResource {
|
||||
return {
|
||||
uri: resource.uri,
|
||||
name: resource.name,
|
||||
mimeType: resource.mimeType,
|
||||
description: resource.description,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts McpResourceTemplate to ProtoMcpResourceTemplate format, ensuring all required fields have values
|
||||
*/
|
||||
function convertResourceTemplate(template: McpResourceTemplate): ProtoMcpResourceTemplate {
|
||||
return {
|
||||
uriTemplate: template.uriTemplate,
|
||||
name: template.name,
|
||||
mimeType: template.mimeType,
|
||||
description: template.description,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to convert Proto enum to TS status
|
||||
function convertProtoStatusToMcp(status: McpServerStatus): McpServer["status"] {
|
||||
switch (status) {
|
||||
case McpServerStatus.MCP_SERVER_STATUS_CONNECTED:
|
||||
return "connected"
|
||||
case McpServerStatus.MCP_SERVER_STATUS_CONNECTING:
|
||||
return "connecting"
|
||||
case McpServerStatus.MCP_SERVER_STATUS_DISCONNECTED:
|
||||
default: // Includes UNSPECIFIED if it were present, maps to disconnected
|
||||
return "disconnected"
|
||||
}
|
||||
}
|
||||
|
||||
export function convertProtoMcpServersToMcpServers(protoServers: ProtoMcpServer[]): McpServer[] {
|
||||
const mcpServers: McpServer[] = protoServers.map((protoServer) => {
|
||||
return {
|
||||
name: protoServer.name,
|
||||
config: protoServer.config,
|
||||
status: convertProtoStatusToMcp(protoServer.status),
|
||||
error: protoServer.error === "" ? undefined : protoServer.error,
|
||||
|
||||
// Convert nested types
|
||||
tools: protoServer.tools.map(convertProtoTool),
|
||||
resources: protoServer.resources.map(convertProtoResource),
|
||||
resourceTemplates: protoServer.resourceTemplates.map(convertProtoResourceTemplate),
|
||||
|
||||
disabled: protoServer.disabled,
|
||||
timeout: protoServer.timeout,
|
||||
}
|
||||
})
|
||||
return mcpServers
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ProtoMcpTool to McpTool format, parsing inputSchema if needed
|
||||
*/
|
||||
function convertProtoTool(protoTool: ProtoMcpTool): McpTool {
|
||||
return {
|
||||
name: protoTool.name,
|
||||
description: protoTool.description === "" ? undefined : protoTool.description,
|
||||
inputSchema: protoTool.inputSchema
|
||||
? protoTool.inputSchema.startsWith("{")
|
||||
? JSON.parse(protoTool.inputSchema)
|
||||
: protoTool.inputSchema
|
||||
: undefined,
|
||||
autoApprove: protoTool.autoApprove,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ProtoMcpResource to McpResource format
|
||||
*/
|
||||
function convertProtoResource(protoResource: ProtoMcpResource): McpResource {
|
||||
return {
|
||||
uri: protoResource.uri,
|
||||
name: protoResource.name,
|
||||
mimeType: protoResource.mimeType === "" ? undefined : protoResource.mimeType,
|
||||
description: protoResource.description === "" ? undefined : protoResource.description,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ProtoMcpResourceTemplate to McpResourceTemplate format
|
||||
*/
|
||||
function convertProtoResourceTemplate(protoTemplate: ProtoMcpResourceTemplate): McpResourceTemplate {
|
||||
return {
|
||||
uriTemplate: protoTemplate.uriTemplate,
|
||||
name: protoTemplate.name,
|
||||
mimeType: protoTemplate.mimeType === "" ? undefined : protoTemplate.mimeType,
|
||||
description: protoTemplate.description === "" ? undefined : protoTemplate.description,
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-ts_proto v2.7.0
|
||||
// protoc v6.30.1
|
||||
// protoc v6.30.2
|
||||
// source: browser.proto
|
||||
|
||||
/* eslint-disable */
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-ts_proto v2.7.0
|
||||
// protoc v6.30.1
|
||||
// protoc v6.30.2
|
||||
// source: checkpoints.proto
|
||||
|
||||
/* eslint-disable */
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-ts_proto v2.7.0
|
||||
// protoc v6.30.1
|
||||
// protoc v6.30.2
|
||||
// source: common.proto
|
||||
|
||||
/* eslint-disable */
|
||||
|
824
src/shared/proto/mcp.ts
Normal file
824
src/shared/proto/mcp.ts
Normal file
@ -0,0 +1,824 @@
|
||||
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-ts_proto v2.7.0
|
||||
// protoc v6.30.2
|
||||
// source: mcp.proto
|
||||
|
||||
/* eslint-disable */
|
||||
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"
|
||||
import { Metadata } from "./common"
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
export enum McpServerStatus {
|
||||
/**
|
||||
* MCP_SERVER_STATUS_DISCONNECTED - Protobuf enums (in proto3) must have a zero value defined, which serves as the default if the field isn't explicitly set.
|
||||
* To align with the required nature of the TypeScript type and avoid an unnecessary UNSPECIFIED state, we map one of the existing statuses to this zero value.
|
||||
*/
|
||||
MCP_SERVER_STATUS_DISCONNECTED = 0,
|
||||
MCP_SERVER_STATUS_CONNECTED = 1,
|
||||
MCP_SERVER_STATUS_CONNECTING = 2,
|
||||
UNRECOGNIZED = -1,
|
||||
}
|
||||
|
||||
export function mcpServerStatusFromJSON(object: any): McpServerStatus {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "MCP_SERVER_STATUS_DISCONNECTED":
|
||||
return McpServerStatus.MCP_SERVER_STATUS_DISCONNECTED
|
||||
case 1:
|
||||
case "MCP_SERVER_STATUS_CONNECTED":
|
||||
return McpServerStatus.MCP_SERVER_STATUS_CONNECTED
|
||||
case 2:
|
||||
case "MCP_SERVER_STATUS_CONNECTING":
|
||||
return McpServerStatus.MCP_SERVER_STATUS_CONNECTING
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return McpServerStatus.UNRECOGNIZED
|
||||
}
|
||||
}
|
||||
|
||||
export function mcpServerStatusToJSON(object: McpServerStatus): string {
|
||||
switch (object) {
|
||||
case McpServerStatus.MCP_SERVER_STATUS_DISCONNECTED:
|
||||
return "MCP_SERVER_STATUS_DISCONNECTED"
|
||||
case McpServerStatus.MCP_SERVER_STATUS_CONNECTED:
|
||||
return "MCP_SERVER_STATUS_CONNECTED"
|
||||
case McpServerStatus.MCP_SERVER_STATUS_CONNECTING:
|
||||
return "MCP_SERVER_STATUS_CONNECTING"
|
||||
case McpServerStatus.UNRECOGNIZED:
|
||||
default:
|
||||
return "UNRECOGNIZED"
|
||||
}
|
||||
}
|
||||
|
||||
export interface McpTool {
|
||||
name: string
|
||||
description?: string | undefined
|
||||
inputSchema?: string | undefined
|
||||
autoApprove?: boolean | undefined
|
||||
}
|
||||
|
||||
export interface McpResource {
|
||||
uri: string
|
||||
name: string
|
||||
mimeType?: string | undefined
|
||||
description?: string | undefined
|
||||
}
|
||||
|
||||
export interface McpResourceTemplate {
|
||||
uriTemplate: string
|
||||
name: string
|
||||
mimeType?: string | undefined
|
||||
description?: string | undefined
|
||||
}
|
||||
|
||||
export interface McpServer {
|
||||
name: string
|
||||
config: string
|
||||
status: McpServerStatus
|
||||
error?: string | undefined
|
||||
tools: McpTool[]
|
||||
resources: McpResource[]
|
||||
resourceTemplates: McpResourceTemplate[]
|
||||
disabled?: boolean | undefined
|
||||
timeout?: number | undefined
|
||||
}
|
||||
|
||||
export interface ToggleMcpServerRequest {
|
||||
metadata?: Metadata | undefined
|
||||
serverName: string
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export interface McpServers {
|
||||
mcpServers: McpServer[]
|
||||
}
|
||||
|
||||
function createBaseMcpTool(): McpTool {
|
||||
return { name: "", description: undefined, inputSchema: undefined, autoApprove: undefined }
|
||||
}
|
||||
|
||||
export const McpTool: MessageFns<McpTool> = {
|
||||
encode(message: McpTool, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.name !== "") {
|
||||
writer.uint32(10).string(message.name)
|
||||
}
|
||||
if (message.description !== undefined) {
|
||||
writer.uint32(18).string(message.description)
|
||||
}
|
||||
if (message.inputSchema !== undefined) {
|
||||
writer.uint32(26).string(message.inputSchema)
|
||||
}
|
||||
if (message.autoApprove !== undefined) {
|
||||
writer.uint32(32).bool(message.autoApprove)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpTool {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpTool()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.name = reader.string()
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.description = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.inputSchema = 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): McpTool {
|
||||
return {
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
||||
description: isSet(object.description) ? globalThis.String(object.description) : undefined,
|
||||
inputSchema: isSet(object.inputSchema) ? globalThis.String(object.inputSchema) : undefined,
|
||||
autoApprove: isSet(object.autoApprove) ? globalThis.Boolean(object.autoApprove) : undefined,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpTool): unknown {
|
||||
const obj: any = {}
|
||||
if (message.name !== "") {
|
||||
obj.name = message.name
|
||||
}
|
||||
if (message.description !== undefined) {
|
||||
obj.description = message.description
|
||||
}
|
||||
if (message.inputSchema !== undefined) {
|
||||
obj.inputSchema = message.inputSchema
|
||||
}
|
||||
if (message.autoApprove !== undefined) {
|
||||
obj.autoApprove = message.autoApprove
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpTool>, I>>(base?: I): McpTool {
|
||||
return McpTool.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpTool>, I>>(object: I): McpTool {
|
||||
const message = createBaseMcpTool()
|
||||
message.name = object.name ?? ""
|
||||
message.description = object.description ?? undefined
|
||||
message.inputSchema = object.inputSchema ?? undefined
|
||||
message.autoApprove = object.autoApprove ?? undefined
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpResource(): McpResource {
|
||||
return { uri: "", name: "", mimeType: undefined, description: undefined }
|
||||
}
|
||||
|
||||
export const McpResource: MessageFns<McpResource> = {
|
||||
encode(message: McpResource, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.uri !== "") {
|
||||
writer.uint32(10).string(message.uri)
|
||||
}
|
||||
if (message.name !== "") {
|
||||
writer.uint32(18).string(message.name)
|
||||
}
|
||||
if (message.mimeType !== undefined) {
|
||||
writer.uint32(26).string(message.mimeType)
|
||||
}
|
||||
if (message.description !== undefined) {
|
||||
writer.uint32(34).string(message.description)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpResource {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpResource()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.uri = reader.string()
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.name = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.mimeType = reader.string()
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break
|
||||
}
|
||||
|
||||
message.description = reader.string()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): McpResource {
|
||||
return {
|
||||
uri: isSet(object.uri) ? globalThis.String(object.uri) : "",
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
||||
mimeType: isSet(object.mimeType) ? globalThis.String(object.mimeType) : undefined,
|
||||
description: isSet(object.description) ? globalThis.String(object.description) : undefined,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpResource): unknown {
|
||||
const obj: any = {}
|
||||
if (message.uri !== "") {
|
||||
obj.uri = message.uri
|
||||
}
|
||||
if (message.name !== "") {
|
||||
obj.name = message.name
|
||||
}
|
||||
if (message.mimeType !== undefined) {
|
||||
obj.mimeType = message.mimeType
|
||||
}
|
||||
if (message.description !== undefined) {
|
||||
obj.description = message.description
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpResource>, I>>(base?: I): McpResource {
|
||||
return McpResource.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpResource>, I>>(object: I): McpResource {
|
||||
const message = createBaseMcpResource()
|
||||
message.uri = object.uri ?? ""
|
||||
message.name = object.name ?? ""
|
||||
message.mimeType = object.mimeType ?? undefined
|
||||
message.description = object.description ?? undefined
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpResourceTemplate(): McpResourceTemplate {
|
||||
return { uriTemplate: "", name: "", mimeType: undefined, description: undefined }
|
||||
}
|
||||
|
||||
export const McpResourceTemplate: MessageFns<McpResourceTemplate> = {
|
||||
encode(message: McpResourceTemplate, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.uriTemplate !== "") {
|
||||
writer.uint32(10).string(message.uriTemplate)
|
||||
}
|
||||
if (message.name !== "") {
|
||||
writer.uint32(18).string(message.name)
|
||||
}
|
||||
if (message.mimeType !== undefined) {
|
||||
writer.uint32(26).string(message.mimeType)
|
||||
}
|
||||
if (message.description !== undefined) {
|
||||
writer.uint32(34).string(message.description)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpResourceTemplate {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpResourceTemplate()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.uriTemplate = reader.string()
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.name = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.mimeType = reader.string()
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break
|
||||
}
|
||||
|
||||
message.description = reader.string()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): McpResourceTemplate {
|
||||
return {
|
||||
uriTemplate: isSet(object.uriTemplate) ? globalThis.String(object.uriTemplate) : "",
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
||||
mimeType: isSet(object.mimeType) ? globalThis.String(object.mimeType) : undefined,
|
||||
description: isSet(object.description) ? globalThis.String(object.description) : undefined,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpResourceTemplate): unknown {
|
||||
const obj: any = {}
|
||||
if (message.uriTemplate !== "") {
|
||||
obj.uriTemplate = message.uriTemplate
|
||||
}
|
||||
if (message.name !== "") {
|
||||
obj.name = message.name
|
||||
}
|
||||
if (message.mimeType !== undefined) {
|
||||
obj.mimeType = message.mimeType
|
||||
}
|
||||
if (message.description !== undefined) {
|
||||
obj.description = message.description
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpResourceTemplate>, I>>(base?: I): McpResourceTemplate {
|
||||
return McpResourceTemplate.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpResourceTemplate>, I>>(object: I): McpResourceTemplate {
|
||||
const message = createBaseMcpResourceTemplate()
|
||||
message.uriTemplate = object.uriTemplate ?? ""
|
||||
message.name = object.name ?? ""
|
||||
message.mimeType = object.mimeType ?? undefined
|
||||
message.description = object.description ?? undefined
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpServer(): McpServer {
|
||||
return {
|
||||
name: "",
|
||||
config: "",
|
||||
status: 0,
|
||||
error: undefined,
|
||||
tools: [],
|
||||
resources: [],
|
||||
resourceTemplates: [],
|
||||
disabled: undefined,
|
||||
timeout: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
export const McpServer: MessageFns<McpServer> = {
|
||||
encode(message: McpServer, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.name !== "") {
|
||||
writer.uint32(10).string(message.name)
|
||||
}
|
||||
if (message.config !== "") {
|
||||
writer.uint32(18).string(message.config)
|
||||
}
|
||||
if (message.status !== 0) {
|
||||
writer.uint32(24).int32(message.status)
|
||||
}
|
||||
if (message.error !== undefined) {
|
||||
writer.uint32(34).string(message.error)
|
||||
}
|
||||
for (const v of message.tools) {
|
||||
McpTool.encode(v!, writer.uint32(42).fork()).join()
|
||||
}
|
||||
for (const v of message.resources) {
|
||||
McpResource.encode(v!, writer.uint32(50).fork()).join()
|
||||
}
|
||||
for (const v of message.resourceTemplates) {
|
||||
McpResourceTemplate.encode(v!, writer.uint32(58).fork()).join()
|
||||
}
|
||||
if (message.disabled !== undefined) {
|
||||
writer.uint32(64).bool(message.disabled)
|
||||
}
|
||||
if (message.timeout !== undefined) {
|
||||
writer.uint32(72).int32(message.timeout)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpServer {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpServer()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.name = reader.string()
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.config = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 24) {
|
||||
break
|
||||
}
|
||||
|
||||
message.status = reader.int32() as any
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break
|
||||
}
|
||||
|
||||
message.error = reader.string()
|
||||
continue
|
||||
}
|
||||
case 5: {
|
||||
if (tag !== 42) {
|
||||
break
|
||||
}
|
||||
|
||||
message.tools.push(McpTool.decode(reader, reader.uint32()))
|
||||
continue
|
||||
}
|
||||
case 6: {
|
||||
if (tag !== 50) {
|
||||
break
|
||||
}
|
||||
|
||||
message.resources.push(McpResource.decode(reader, reader.uint32()))
|
||||
continue
|
||||
}
|
||||
case 7: {
|
||||
if (tag !== 58) {
|
||||
break
|
||||
}
|
||||
|
||||
message.resourceTemplates.push(McpResourceTemplate.decode(reader, reader.uint32()))
|
||||
continue
|
||||
}
|
||||
case 8: {
|
||||
if (tag !== 64) {
|
||||
break
|
||||
}
|
||||
|
||||
message.disabled = reader.bool()
|
||||
continue
|
||||
}
|
||||
case 9: {
|
||||
if (tag !== 72) {
|
||||
break
|
||||
}
|
||||
|
||||
message.timeout = reader.int32()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): McpServer {
|
||||
return {
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
||||
config: isSet(object.config) ? globalThis.String(object.config) : "",
|
||||
status: isSet(object.status) ? mcpServerStatusFromJSON(object.status) : 0,
|
||||
error: isSet(object.error) ? globalThis.String(object.error) : undefined,
|
||||
tools: globalThis.Array.isArray(object?.tools) ? object.tools.map((e: any) => McpTool.fromJSON(e)) : [],
|
||||
resources: globalThis.Array.isArray(object?.resources)
|
||||
? object.resources.map((e: any) => McpResource.fromJSON(e))
|
||||
: [],
|
||||
resourceTemplates: globalThis.Array.isArray(object?.resourceTemplates)
|
||||
? object.resourceTemplates.map((e: any) => McpResourceTemplate.fromJSON(e))
|
||||
: [],
|
||||
disabled: isSet(object.disabled) ? globalThis.Boolean(object.disabled) : undefined,
|
||||
timeout: isSet(object.timeout) ? globalThis.Number(object.timeout) : undefined,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpServer): unknown {
|
||||
const obj: any = {}
|
||||
if (message.name !== "") {
|
||||
obj.name = message.name
|
||||
}
|
||||
if (message.config !== "") {
|
||||
obj.config = message.config
|
||||
}
|
||||
if (message.status !== 0) {
|
||||
obj.status = mcpServerStatusToJSON(message.status)
|
||||
}
|
||||
if (message.error !== undefined) {
|
||||
obj.error = message.error
|
||||
}
|
||||
if (message.tools?.length) {
|
||||
obj.tools = message.tools.map((e) => McpTool.toJSON(e))
|
||||
}
|
||||
if (message.resources?.length) {
|
||||
obj.resources = message.resources.map((e) => McpResource.toJSON(e))
|
||||
}
|
||||
if (message.resourceTemplates?.length) {
|
||||
obj.resourceTemplates = message.resourceTemplates.map((e) => McpResourceTemplate.toJSON(e))
|
||||
}
|
||||
if (message.disabled !== undefined) {
|
||||
obj.disabled = message.disabled
|
||||
}
|
||||
if (message.timeout !== undefined) {
|
||||
obj.timeout = Math.round(message.timeout)
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpServer>, I>>(base?: I): McpServer {
|
||||
return McpServer.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpServer>, I>>(object: I): McpServer {
|
||||
const message = createBaseMcpServer()
|
||||
message.name = object.name ?? ""
|
||||
message.config = object.config ?? ""
|
||||
message.status = object.status ?? 0
|
||||
message.error = object.error ?? undefined
|
||||
message.tools = object.tools?.map((e) => McpTool.fromPartial(e)) || []
|
||||
message.resources = object.resources?.map((e) => McpResource.fromPartial(e)) || []
|
||||
message.resourceTemplates = object.resourceTemplates?.map((e) => McpResourceTemplate.fromPartial(e)) || []
|
||||
message.disabled = object.disabled ?? undefined
|
||||
message.timeout = object.timeout ?? undefined
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseToggleMcpServerRequest(): ToggleMcpServerRequest {
|
||||
return { metadata: undefined, serverName: "", disabled: false }
|
||||
}
|
||||
|
||||
export const ToggleMcpServerRequest: MessageFns<ToggleMcpServerRequest> = {
|
||||
encode(message: ToggleMcpServerRequest, 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)
|
||||
}
|
||||
if (message.disabled !== false) {
|
||||
writer.uint32(24).bool(message.disabled)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ToggleMcpServerRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseToggleMcpServerRequest()
|
||||
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 !== 24) {
|
||||
break
|
||||
}
|
||||
|
||||
message.disabled = reader.bool()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ToggleMcpServerRequest {
|
||||
return {
|
||||
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
|
||||
serverName: isSet(object.serverName) ? globalThis.String(object.serverName) : "",
|
||||
disabled: isSet(object.disabled) ? globalThis.Boolean(object.disabled) : false,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ToggleMcpServerRequest): unknown {
|
||||
const obj: any = {}
|
||||
if (message.metadata !== undefined) {
|
||||
obj.metadata = Metadata.toJSON(message.metadata)
|
||||
}
|
||||
if (message.serverName !== "") {
|
||||
obj.serverName = message.serverName
|
||||
}
|
||||
if (message.disabled !== false) {
|
||||
obj.disabled = message.disabled
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ToggleMcpServerRequest>, I>>(base?: I): ToggleMcpServerRequest {
|
||||
return ToggleMcpServerRequest.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ToggleMcpServerRequest>, I>>(object: I): ToggleMcpServerRequest {
|
||||
const message = createBaseToggleMcpServerRequest()
|
||||
message.metadata =
|
||||
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
|
||||
message.serverName = object.serverName ?? ""
|
||||
message.disabled = object.disabled ?? false
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpServers(): McpServers {
|
||||
return { mcpServers: [] }
|
||||
}
|
||||
|
||||
export const McpServers: MessageFns<McpServers> = {
|
||||
encode(message: McpServers, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
for (const v of message.mcpServers) {
|
||||
McpServer.encode(v!, writer.uint32(10).fork()).join()
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpServers {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpServers()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.mcpServers.push(McpServer.decode(reader, reader.uint32()))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): McpServers {
|
||||
return {
|
||||
mcpServers: globalThis.Array.isArray(object?.mcpServers)
|
||||
? object.mcpServers.map((e: any) => McpServer.fromJSON(e))
|
||||
: [],
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpServers): unknown {
|
||||
const obj: any = {}
|
||||
if (message.mcpServers?.length) {
|
||||
obj.mcpServers = message.mcpServers.map((e) => McpServer.toJSON(e))
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpServers>, I>>(base?: I): McpServers {
|
||||
return McpServers.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpServers>, I>>(object: I): McpServers {
|
||||
const message = createBaseMcpServers()
|
||||
message.mcpServers = object.mcpServers?.map((e) => McpServer.fromPartial(e)) || []
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
export type McpServiceDefinition = typeof McpServiceDefinition
|
||||
export const McpServiceDefinition = {
|
||||
name: "McpService",
|
||||
fullName: "cline.McpService",
|
||||
methods: {
|
||||
toggleMcpServer: {
|
||||
name: "toggleMcpServer",
|
||||
requestType: ToggleMcpServerRequest,
|
||||
requestStream: false,
|
||||
responseType: McpServers,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined
|
||||
|
||||
export type DeepPartial<T> = T extends Builtin
|
||||
? T
|
||||
: T extends globalThis.Array<infer U>
|
||||
? globalThis.Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U>
|
||||
? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {}
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: Partial<T>
|
||||
|
||||
type KeysOfUnion<T> = T extends T ? keyof T : never
|
||||
export type Exact<P, I extends P> = P extends Builtin
|
||||
? P
|
||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never }
|
||||
|
||||
function isSet(value: any): boolean {
|
||||
return value !== null && value !== undefined
|
||||
}
|
||||
|
||||
export interface MessageFns<T> {
|
||||
encode(message: T, writer?: BinaryWriter): BinaryWriter
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): T
|
||||
fromJSON(object: any): T
|
||||
toJSON(message: T): unknown
|
||||
create<I extends Exact<DeepPartial<T>, I>>(base?: I): T
|
||||
fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T
|
||||
}
|
@ -41,7 +41,7 @@ const McpToolRow = ({ tool, serverName }: McpToolRowProps) => {
|
||||
<span style={{ fontWeight: 500 }}>{tool.name}</span>
|
||||
</div>
|
||||
{serverName && autoApprovalSettings.enabled && autoApprovalSettings.actions.useMcp && (
|
||||
<VSCodeCheckbox checked={tool.autoApprove} onChange={handleAutoApproveChange} data-tool={tool.name}>
|
||||
<VSCodeCheckbox checked={tool.autoApprove ?? false} onChange={handleAutoApproveChange} data-tool={tool.name}>
|
||||
Auto-approve
|
||||
</VSCodeCheckbox>
|
||||
)}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { McpServer } from "@shared/mcp"
|
||||
import { DEFAULT_MCP_TIMEOUT_SECONDS } from "@shared/mcp"
|
||||
import { useState, useCallback } from "react"
|
||||
import { useState, useCallback, useEffect } from "react"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
import {
|
||||
VSCodeButton,
|
||||
@ -16,7 +16,8 @@ import DangerButton from "@/components/common/DangerButton"
|
||||
import McpToolRow from "./McpToolRow"
|
||||
import McpResourceRow from "./McpResourceRow"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
|
||||
import { McpServiceClient } from "@/services/grpc-client"
|
||||
import { convertProtoMcpServersToMcpServers } from "@shared/proto-conversions/mcp/mcp-server-conversion"
|
||||
// constant JSX.Elements
|
||||
const TimeoutOptions = [
|
||||
{ value: "30", label: "30 seconds" },
|
||||
@ -40,7 +41,7 @@ const ServerRow = ({
|
||||
isExpandable?: boolean
|
||||
hasTrashIcon?: boolean
|
||||
}) => {
|
||||
const { mcpMarketplaceCatalog, autoApprovalSettings } = useExtensionState()
|
||||
const { mcpMarketplaceCatalog, autoApprovalSettings, setMcpServers } = useExtensionState()
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
@ -109,6 +110,20 @@ const ServerRow = ({
|
||||
})
|
||||
}
|
||||
|
||||
const handleToggleMcpServer = () => {
|
||||
McpServiceClient.toggleMcpServer({
|
||||
serverName: server.name,
|
||||
disabled: !server.disabled,
|
||||
})
|
||||
.then((response) => {
|
||||
const mcpServers = convertProtoMcpServersToMcpServers(response.mcpServers)
|
||||
setMcpServers(mcpServers)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error toggling MCP server", error)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<div
|
||||
@ -184,20 +199,12 @@ const ServerRow = ({
|
||||
opacity: server.disabled ? 0.5 : 0.9,
|
||||
}}
|
||||
onClick={() => {
|
||||
vscode.postMessage({
|
||||
type: "toggleMcpServer",
|
||||
serverName: server.name,
|
||||
disabled: !server.disabled,
|
||||
})
|
||||
handleToggleMcpServer()
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
vscode.postMessage({
|
||||
type: "toggleMcpServer",
|
||||
serverName: server.name,
|
||||
disabled: !server.disabled,
|
||||
})
|
||||
handleToggleMcpServer()
|
||||
}
|
||||
}}>
|
||||
<div
|
||||
|
@ -17,7 +17,7 @@ import { vscode } from "../utils/vscode"
|
||||
import { DEFAULT_BROWSER_SETTINGS } from "@shared/BrowserSettings"
|
||||
import { DEFAULT_CHAT_SETTINGS } from "@shared/ChatSettings"
|
||||
import { TelemetrySetting } from "@shared/TelemetrySetting"
|
||||
import { ClineRulesToggles } from "@shared/cline-rules"
|
||||
|
||||
interface ExtensionStateContextType extends ExtensionState {
|
||||
didHydrateState: boolean
|
||||
showWelcome: boolean
|
||||
@ -34,6 +34,7 @@ interface ExtensionStateContextType extends ExtensionState {
|
||||
setTelemetrySetting: (value: TelemetrySetting) => void
|
||||
setShowAnnouncement: (value: boolean) => void
|
||||
setPlanActSeparateModelsSetting: (value: boolean) => void
|
||||
setMcpServers: (value: McpServer[]) => void
|
||||
}
|
||||
|
||||
const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
|
||||
@ -226,6 +227,7 @@ export const ExtensionStateContextProvider: React.FC<{
|
||||
...prevState,
|
||||
shouldShowAnnouncement: value,
|
||||
})),
|
||||
setMcpServers: (mcpServers: McpServer[]) => setMcpServers(mcpServers),
|
||||
}
|
||||
|
||||
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>
|
||||
|
@ -3,7 +3,7 @@ import { v4 as uuidv4 } from "uuid"
|
||||
import { BrowserServiceDefinition } from "@shared/proto/browser"
|
||||
import { CheckpointsServiceDefinition } from "@shared/proto/checkpoints"
|
||||
import { EmptyRequest } from "@shared/proto/common"
|
||||
|
||||
import { McpServiceDefinition } from "@shared/proto/mcp"
|
||||
// Generic type for any protobuf service definition
|
||||
type ProtoService = {
|
||||
name: string
|
||||
@ -95,5 +95,6 @@ function createGrpcClient<T extends ProtoService>(service: T): GrpcClientType<T>
|
||||
|
||||
const BrowserServiceClient = createGrpcClient(BrowserServiceDefinition)
|
||||
const CheckpointsServiceClient = createGrpcClient(CheckpointsServiceDefinition)
|
||||
const McpServiceClient = createGrpcClient(McpServiceDefinition)
|
||||
|
||||
export { BrowserServiceClient, CheckpointsServiceClient }
|
||||
export { BrowserServiceClient, CheckpointsServiceClient, McpServiceClient }
|
||||
|
Loading…
Reference in New Issue
Block a user