From 4db6cfc225ac50f44d24f395406286bfd019bdb9 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 07:46:55 +0000 Subject: [PATCH 1/6] feat(vscode): disable MCP removal in agent behaviour settings Remove the MCP server removal functionality from the agent behaviour settings screen. The remove buttons are hidden and the backend handler is replaced with a no-op. This intentionally disables MCP removal while keeping the code structure intact for future re-implementation. Files changed: - AgentBehaviourTab.tsx: Remove confirmation dialog and close buttons - McpEditView.tsx: Hide remove button in edit view header - session.tsx: Make removeMcp a no-op (no message posted) - KiloProvider.ts: Make handleRemoveMcp a no-op All removal points are marked with TODO: Re-implement MCP removal. --- packages/kilo-vscode/src/KiloProvider.ts | 21 +--------- .../components/settings/AgentBehaviourTab.tsx | 40 ++----------------- .../src/components/settings/McpEditView.tsx | 2 +- .../webview-ui/src/context/session.tsx | 4 +- 4 files changed, 9 insertions(+), 58 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 633fb7e3c34..8f7fe2bcf0b 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1732,25 +1732,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper await this.fetchAndSendAgents() } - private async handleRemoveMcp(name: string): Promise { - const workspace = this.getProjectDirectory(this.currentSession?.id) - const mp = this.getMarketplace() - const stub = { id: name, type: "mcp" as const, name, description: "", url: "", content: "" } - - // Remove from both scopes — an MCP could exist in project, global, or both - const project = await mp.remove(stub, "project", workspace) - const global = await mp.remove(stub, "global", workspace) - - if (project.success || global.success) { - // Use global scope when removed from global (or both) so the global - // config cache is also invalidated; project scope is a subset. - const scope = global.success ? "global" : "project" - await this.disposeCliInstance(scope) - this.cachedConfigMessage = null - await this.fetchAndSendConfig() - } else { - console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) - } + private async handleRemoveMcp(_name: string): Promise { + // TODO: Re-implement MCP removal } private async fetchAndSendMcpStatus(): Promise { diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index 3210a800f44..79af68bb878 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -466,30 +466,7 @@ const AgentBehaviourTab: Component = () => { ) } - const confirmRemoveMcp = (name: string) => { - dialog.show(() => ( - -
- {language.t("settings.agentBehaviour.removeMcp.confirm", { name })} -
- - -
-
-
- )) - } + // TODO: Re-implement MCP removal (confirmRemoveMcp dialog removed) const renderMcpSubtab = () => { const mcpEntries = createMemo(() => Object.entries(config().mcp ?? {})) @@ -529,9 +506,8 @@ const AgentBehaviourTab: Component = () => { setEditingMcp("")} - onRemove={(name) => { - confirmRemoveMcp(name) - setEditingMcp("") + onRemove={(_name) => { + // TODO: Re-implement MCP removal }} /> ) @@ -641,15 +617,7 @@ const AgentBehaviourTab: Component = () => { {name} - { - e.stopPropagation() - confirmRemoveMcp(name) - }} - /> + {/* TODO: Re-implement MCP removal — remove button hidden */} = (props) => { {language.t("settings.agentBehaviour.editMcp")} — {props.name} - props.onRemove(props.name)} /> + {/* TODO: Re-implement MCP removal — remove button hidden */} {/* Transport info */} diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx index 6e5959e0169..efac0d89792 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx @@ -278,8 +278,8 @@ export const SessionProvider: ParentComponent = (props) => { vscode.postMessage({ type: "removeMode", name }) } - const removeMcp = (name: string) => { - vscode.postMessage({ type: "removeMcp", name }) + const removeMcp = (_name: string) => { + // TODO: Re-implement MCP removal } // MCP runtime status From 4d5f04303008918e33db8cf46b8cb5bef9dcf0e5 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Thu, 2 Apr 2026 10:42:14 +0200 Subject: [PATCH 2/6] feat(vscode): reimplement MCP removal in agent behaviour settings Reimplement MCP server removal from the agent behaviour settings screen. Uses the marketplace service to remove the MCP entry from both project and global kilo.json configs, then invalidates the CLI cache so the change takes effect immediately. Changes: - KiloProvider: handleRemoveMcp calls marketplace.remove() for both scopes, then invalidateAfterMarketplaceChange() to refresh state - session.tsx: removeMcp posts the removeMcp message to extension host - AgentBehaviourTab.tsx: restore confirmation dialog and remove buttons - McpEditView.tsx: restore remove button in edit view header --- packages/kilo-vscode/src/KiloProvider.ts | 16 +++++++- .../components/settings/AgentBehaviourTab.tsx | 40 +++++++++++++++++-- .../src/components/settings/McpEditView.tsx | 2 +- .../webview-ui/src/context/session.tsx | 4 +- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 8f7fe2bcf0b..bbc3f01b2b9 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1732,8 +1732,20 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper await this.fetchAndSendAgents() } - private async handleRemoveMcp(_name: string): Promise { - // TODO: Re-implement MCP removal + private async handleRemoveMcp(name: string): Promise { + const workspace = this.getProjectDirectory(this.currentSession?.id) + const mp = this.getMarketplace() + const stub = { id: name, type: "mcp" as const, name, description: "", url: "", content: "" } + + const project = await mp.remove(stub, "project", workspace) + const global = await mp.remove(stub, "global", workspace) + + if (project.success || global.success) { + const scope = global.success ? "global" : "project" + await this.invalidateAfterMarketplaceChange(scope) + } else { + console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) + } } private async fetchAndSendMcpStatus(): Promise { diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index 79af68bb878..3210a800f44 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -466,7 +466,30 @@ const AgentBehaviourTab: Component = () => { ) } - // TODO: Re-implement MCP removal (confirmRemoveMcp dialog removed) + const confirmRemoveMcp = (name: string) => { + dialog.show(() => ( + +
+ {language.t("settings.agentBehaviour.removeMcp.confirm", { name })} +
+ + +
+
+
+ )) + } const renderMcpSubtab = () => { const mcpEntries = createMemo(() => Object.entries(config().mcp ?? {})) @@ -506,8 +529,9 @@ const AgentBehaviourTab: Component = () => { setEditingMcp("")} - onRemove={(_name) => { - // TODO: Re-implement MCP removal + onRemove={(name) => { + confirmRemoveMcp(name) + setEditingMcp("") }} /> ) @@ -617,7 +641,15 @@ const AgentBehaviourTab: Component = () => { {name} - {/* TODO: Re-implement MCP removal — remove button hidden */} + { + e.stopPropagation() + confirmRemoveMcp(name) + }} + /> = (props) => { {language.t("settings.agentBehaviour.editMcp")} — {props.name} - {/* TODO: Re-implement MCP removal — remove button hidden */} + props.onRemove(props.name)} /> {/* Transport info */} diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx index efac0d89792..6e5959e0169 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx @@ -278,8 +278,8 @@ export const SessionProvider: ParentComponent = (props) => { vscode.postMessage({ type: "removeMode", name }) } - const removeMcp = (_name: string) => { - // TODO: Re-implement MCP removal + const removeMcp = (name: string) => { + vscode.postMessage({ type: "removeMcp", name }) } // MCP runtime status From 6ca0682335c0006acc0f795f6a4c9cc090769647 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Thu, 2 Apr 2026 11:28:40 +0200 Subject: [PATCH 3/6] fix(vscode): use invalidateAfterMarketplaceChange in handleRemoveMode Replace disposeCliInstance with invalidateAfterMarketplaceChange in the marketplace removal path of handleRemoveMode for consistency with handleRemoveMcp. This ensures the more robust invalidation path is used (global.config.update instead of global.dispose) and properly clears both cachedConfigMessage and cachedAgentsMessage. Also removes the now-unused disposeCliInstance method and refactors handleRemoveMcp to use a loop pattern matching the bot's suggestion. --- packages/kilo-vscode/src/KiloProvider.ts | 67 ++++++++---------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index bbc3f01b2b9..c9aa7e86ec3 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1700,36 +1700,33 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper */ private async handleRemoveMode(name: string): Promise { if (!this.client) return - let removed = false // 1. Try CLI removal (handles .md files and legacy .kilocodemodes) try { const dir = this.getWorkspaceDirectory() const result = await this.client.kilocode.removeAgent({ name, directory: dir }) - if (!result.error) removed = true + if (!result.error) { + this.cachedAgentsMessage = null + await this.fetchAndSendAgents() + return + } } catch { // CLI removal failed — agent may be in kilo.json instead } // 2. Try removing from kilo.json (handles marketplace-installed modes) - if (!removed) { - const workspace = this.getProjectDirectory(this.currentSession?.id) - const mp = this.getMarketplace() - const stub = { id: name, type: "mode" as const, name, description: "", content: "" } - const project = await mp.remove(stub, "project", workspace) - const global = await mp.remove(stub, "global", workspace) - if (project.success || global.success) { - await this.disposeCliInstance("global") - removed = true + const workspace = this.getProjectDirectory(this.currentSession?.id) + const mp = this.getMarketplace() + const stub = { id: name, type: "mode" as const, name, description: "", content: "" } + for (const scope of ["project", "global"] as const) { + const result = await mp.remove(stub, scope, workspace) + if (result.success) { + await this.invalidateAfterMarketplaceChange(scope) + return } } - if (!removed) { - console.error("[Kilo New] KiloProvider: Failed to remove mode:", name) - } - - this.cachedAgentsMessage = null - await this.fetchAndSendAgents() + console.error("[Kilo New] KiloProvider: Failed to remove mode:", name) } private async handleRemoveMcp(name: string): Promise { @@ -1737,15 +1734,15 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const mp = this.getMarketplace() const stub = { id: name, type: "mcp" as const, name, description: "", url: "", content: "" } - const project = await mp.remove(stub, "project", workspace) - const global = await mp.remove(stub, "global", workspace) - - if (project.success || global.success) { - const scope = global.success ? "global" : "project" - await this.invalidateAfterMarketplaceChange(scope) - } else { - console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) + for (const scope of ["project", "global"] as const) { + const result = await mp.remove(stub, scope, workspace) + if (result.success) { + await this.invalidateAfterMarketplaceChange(scope) + return + } } + + console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) } private async fetchAndSendMcpStatus(): Promise { @@ -1793,26 +1790,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } } - /** - * Dispose the CLI backend instance so it re-reads config from disk. - * Call after any marketplace install/remove that writes config files directly. - * Global-scope changes need global.dispose() to also reset the global config cache. - */ - private async disposeCliInstance(scope: "project" | "global"): Promise { - if (!this.client) return - if (scope === "global") { - await this.client.global.dispose().catch((e: unknown) => { - console.warn("[Kilo New] global.dispose() after marketplace change failed:", e) - }) - } - // Always dispose the per-project instance so it rebuilds state from - // the (possibly updated) global + project config on the next request. - const dir = this.getWorkspaceDirectory() - await this.client.instance.dispose({ directory: dir }).catch((e: unknown) => { - console.warn("[Kilo New] instance.dispose() after marketplace change failed:", e) - }) - } - /** * Invalidate CLI caches and refresh the webview after a marketplace install/remove. * From 935e29c3768bf19687764d3ca805586304188a47 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Thu, 2 Apr 2026 11:33:57 +0200 Subject: [PATCH 4/6] fix(vscode): always remove from both scopes in handleRemoveMode/Mcp mp.remove returns success even when the entry doesn't exist (no-op), so the loop-with-early-return pattern would skip the global scope after the project-scope no-op succeeded. Revert to attempting both scopes and invalidating once afterward to correctly handle global-only and dual-scope installations. --- packages/kilo-vscode/src/KiloProvider.ts | 38 +++++++++++++----------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index c9aa7e86ec3..26250327472 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1714,35 +1714,39 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper // CLI removal failed — agent may be in kilo.json instead } - // 2. Try removing from kilo.json (handles marketplace-installed modes) + // 2. Try removing from kilo.json (handles marketplace-installed modes). + // mp.remove returns success even when the entry doesn't exist (no-op), + // so we must attempt both scopes to cover dual-scope installations. const workspace = this.getProjectDirectory(this.currentSession?.id) const mp = this.getMarketplace() const stub = { id: name, type: "mode" as const, name, description: "", content: "" } - for (const scope of ["project", "global"] as const) { - const result = await mp.remove(stub, scope, workspace) - if (result.success) { - await this.invalidateAfterMarketplaceChange(scope) - return - } - } + const project = await mp.remove(stub, "project", workspace) + const global = await mp.remove(stub, "global", workspace) - console.error("[Kilo New] KiloProvider: Failed to remove mode:", name) + if (project.success || global.success) { + const scope = global.success ? "global" : "project" + await this.invalidateAfterMarketplaceChange(scope) + } else { + console.error("[Kilo New] KiloProvider: Failed to remove mode:", name) + } } private async handleRemoveMcp(name: string): Promise { + // mp.remove returns success even when the entry doesn't exist (no-op), + // so we must attempt both scopes to cover dual-scope installations. const workspace = this.getProjectDirectory(this.currentSession?.id) const mp = this.getMarketplace() const stub = { id: name, type: "mcp" as const, name, description: "", url: "", content: "" } - for (const scope of ["project", "global"] as const) { - const result = await mp.remove(stub, scope, workspace) - if (result.success) { - await this.invalidateAfterMarketplaceChange(scope) - return - } - } + const project = await mp.remove(stub, "project", workspace) + const global = await mp.remove(stub, "global", workspace) - console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) + if (project.success || global.success) { + const scope = global.success ? "global" : "project" + await this.invalidateAfterMarketplaceChange(scope) + } else { + console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) + } } private async fetchAndSendMcpStatus(): Promise { From 5a93d1db255c3a13bc0b7386e284ed5913917208 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Thu, 2 Apr 2026 11:52:57 +0200 Subject: [PATCH 5/6] refactor(vscode): extract shared marketplace removal helpers Extract removeMarketplaceItem (single scope) and removeMarketplaceItemFromAllScopes (both scopes) to eliminate duplicated remove+invalidate logic between the marketplace UI handler, handleRemoveMode, and handleRemoveMcp. --- packages/kilo-vscode/src/KiloProvider.ts | 69 +++++++++++++----------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 26250327472..a82206ac443 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -35,7 +35,7 @@ import { import { GitOps } from "./agent-manager/GitOps" import { GitStatsPoller, type LocalStats } from "./agent-manager/GitStatsPoller" import { getWorkspaceRoot } from "./review-utils" -import { MarketplaceService } from "./services/marketplace" +import { MarketplaceService, type MarketplaceItem, type RemoveResult } from "./services/marketplace" import { resolveProjectDirectory } from "./project-directory" import { getBusySessionCount, seedSessionStatuses } from "./session-status" import { slimPart, slimParts } from "./kilo-provider/slim-metadata" @@ -949,12 +949,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper break } case "removeInstalledMarketplaceItem": { - const workspace = this.getProjectDirectory(this.currentSession?.id) const scope = message.mpInstallOptions?.target ?? "project" - const result = await this.getMarketplace().remove(message.mpItem, scope, workspace) - if (result.success) { - await this.invalidateAfterMarketplaceChange(scope) - } + const result = await this.removeMarketplaceItem(message.mpItem, scope) this.postMessage({ type: "marketplaceRemoveResult", success: result.success, @@ -1714,37 +1710,18 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper // CLI removal failed — agent may be in kilo.json instead } - // 2. Try removing from kilo.json (handles marketplace-installed modes). - // mp.remove returns success even when the entry doesn't exist (no-op), - // so we must attempt both scopes to cover dual-scope installations. - const workspace = this.getProjectDirectory(this.currentSession?.id) - const mp = this.getMarketplace() + // 2. Try removing from kilo.json (handles marketplace-installed modes) const stub = { id: name, type: "mode" as const, name, description: "", content: "" } - const project = await mp.remove(stub, "project", workspace) - const global = await mp.remove(stub, "global", workspace) - - if (project.success || global.success) { - const scope = global.success ? "global" : "project" - await this.invalidateAfterMarketplaceChange(scope) - } else { + const removed = await this.removeMarketplaceItemFromAllScopes(stub) + if (!removed) { console.error("[Kilo New] KiloProvider: Failed to remove mode:", name) } } private async handleRemoveMcp(name: string): Promise { - // mp.remove returns success even when the entry doesn't exist (no-op), - // so we must attempt both scopes to cover dual-scope installations. - const workspace = this.getProjectDirectory(this.currentSession?.id) - const mp = this.getMarketplace() const stub = { id: name, type: "mcp" as const, name, description: "", url: "", content: "" } - - const project = await mp.remove(stub, "project", workspace) - const global = await mp.remove(stub, "global", workspace) - - if (project.success || global.success) { - const scope = global.success ? "global" : "project" - await this.invalidateAfterMarketplaceChange(scope) - } else { + const removed = await this.removeMarketplaceItemFromAllScopes(stub) + if (!removed) { console.error("[Kilo New] KiloProvider: Failed to remove MCP server:", name) } } @@ -1794,6 +1771,38 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } } + /** + * Remove a marketplace item from a single scope and invalidate CLI caches. + */ + private async removeMarketplaceItem(item: MarketplaceItem, scope: "project" | "global"): Promise { + const workspace = this.getProjectDirectory(this.currentSession?.id) + const result = await this.getMarketplace().remove(item, scope, workspace) + if (result.success) { + await this.invalidateAfterMarketplaceChange(scope) + } + return result + } + + /** + * Remove a marketplace item from both project and global scopes. + * mp.remove returns success even when the entry doesn't exist (no-op), + * so we must attempt both scopes to cover dual-scope installations. + * Returns true if at least one scope removal succeeded. + */ + private async removeMarketplaceItemFromAllScopes(item: MarketplaceItem): Promise { + const workspace = this.getProjectDirectory(this.currentSession?.id) + const mp = this.getMarketplace() + const project = await mp.remove(item, "project", workspace) + const global = await mp.remove(item, "global", workspace) + + if (project.success || global.success) { + const scope = global.success ? "global" : "project" + await this.invalidateAfterMarketplaceChange(scope) + return true + } + return false + } + /** * Invalidate CLI caches and refresh the webview after a marketplace install/remove. * From afa1ab028f4837176eede1da494ddfd9f54be818 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Thu, 2 Apr 2026 13:20:59 +0200 Subject: [PATCH 6/6] fix(vscode): remove MCPs from legacy config files on deletion MCPs loaded via the CLI-side McpMigrator (from .kilo/mcp.json, .kilocode/mcp.json, or the VS Code global storage mcp_settings.json) were not being removed because handleRemoveMcp only operated on kilo.json. The MCP would silently 'reappear' after invalidation because the migrator re-read it from the legacy file. Now removes the entry from all legacy files before the kilo.json removal so that the subsequent CLI cache invalidation sees the cleaned-up state. --- packages/kilo-vscode/src/KiloProvider.ts | 51 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index a82206ac443..351c05937be 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1719,6 +1719,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } private async handleRemoveMcp(name: string): Promise { + // Remove from legacy files first so that the subsequent invalidation + // causes the CLI to re-read config without the legacy entry. + await this.removeLegacyMcp(name) + const stub = { id: name, type: "mcp" as const, name, description: "", url: "", content: "" } const removed = await this.removeMarketplaceItemFromAllScopes(stub) if (!removed) { @@ -1726,6 +1730,53 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } } + /** + * Remove an MCP server from legacy config files (.kilo/mcp.json, .kilocode/mcp.json, + * and the VS Code global storage mcp_settings.json). These files are read by the + * CLI-side McpMigrator and merged into config at the lowest precedence level. + * Returns true if the entry was found and removed from at least one file. + */ + private async removeLegacyMcp(name: string): Promise { + const workspace = this.getProjectDirectory(this.currentSession?.id) + const files: vscode.Uri[] = [] + + // Project-level legacy files + if (workspace) { + files.push(vscode.Uri.file(path.join(workspace, ".kilo", "mcp.json"))) + files.push(vscode.Uri.file(path.join(workspace, ".kilocode", "mcp.json"))) + } + + // Global legacy file (VS Code extension global storage) + const storage = this.extensionContext?.globalStorageUri + if (storage) { + files.push(vscode.Uri.joinPath(storage, "settings", "mcp_settings.json")) + } + + let removed = false + for (const uri of files) { + const bytes = await vscode.workspace.fs.readFile(uri).then( + (b) => b, + () => null, + ) + if (!bytes) continue + + try { + const parsed = JSON.parse(Buffer.from(bytes).toString("utf8")) as Record + const servers = parsed.mcpServers as Record | undefined + if (!servers?.[name]) continue + + delete servers[name] + const content = Buffer.from(JSON.stringify(parsed, null, 2), "utf8") + await vscode.workspace.fs.writeFile(uri, content) + removed = true + } catch (err) { + console.warn("[Kilo New] KiloProvider: Failed to remove legacy MCP from", uri.fsPath, err) + } + } + + return removed + } + private async fetchAndSendMcpStatus(): Promise { if (!this.client) { if (this.cachedMcpStatusMessage) {