Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/types/src/__tests__/global-settings.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
DEFAULT_DESTRUCTIVE_COMMAND_GUARD_ENABLED,
DEFAULT_SHOW_MCP_DESCRIPTIONS,
GLOBAL_SETTINGS_KEYS,
globalSettingsSchema,
} from "../global-settings.js"
Expand All @@ -20,3 +21,20 @@ describe("destructive command guard global setting", () => {
expect(() => globalSettingsSchema.parse({ destructiveCommandGuardEnabled: "true" })).toThrow()
})
})

describe("MCP description visibility global setting", () => {
it("preserves existing description visibility by default", () => {
expect(DEFAULT_SHOW_MCP_DESCRIPTIONS).toBe(true)
})

it("accepts and exposes the persisted setting", () => {
expect(globalSettingsSchema.parse({ showMcpDescriptions: false })).toEqual({
showMcpDescriptions: false,
})
expect(GLOBAL_SETTINGS_KEYS).toContain("showMcpDescriptions")
})

it("rejects non-boolean setting values", () => {
expect(() => globalSettingsSchema.parse({ showMcpDescriptions: "false" })).toThrow()
})
})
10 changes: 10 additions & 0 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ export const MAX_CHECKPOINT_TIMEOUT_SECONDS = 60
*/
export const DEFAULT_CHECKPOINT_TIMEOUT_SECONDS = 15

/**
* Whether MCP-supplied tool and resource descriptions are shown in the UI.
*/
export const DEFAULT_SHOW_MCP_DESCRIPTIONS = true

/**
* GlobalSettings
*/
Expand Down Expand Up @@ -241,6 +246,11 @@ export const globalSettingsSchema = z.object({
telemetrySetting: telemetrySettingsSchema.optional(),

mcpEnabled: z.boolean().optional(),
/**
* Whether MCP-supplied tool and resource descriptions are shown in the UI.
* @default true
*/
showMcpDescriptions: z.boolean().optional(),

mode: z.string().optional(),
modeApiConfigs: z.record(z.string(), z.string()).optional(),
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/vscode-extension-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ export type ExtensionState = Pick<
| "includeCurrentCost"
| "maxGitStatusFiles"
| "requestDelaySeconds"
| "showMcpDescriptions"
| "showWorktreesInHomeScreen"
| "disabledTools"
> & {
Expand Down
4 changes: 4 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
DEFAULT_WRITE_DELAY_MS,
DEFAULT_DIFF_FUZZY_THRESHOLD,
DEFAULT_DESTRUCTIVE_COMMAND_GUARD_ENABLED,
DEFAULT_SHOW_MCP_DESCRIPTIONS,
DEFAULT_AUTO_CLOSE_ZOO_OPENED_FILES,
DEFAULT_AUTO_CLOSE_ZOO_OPENED_FILES_AFTER_USER_EDITED,
DEFAULT_AUTO_CLOSE_ZOO_OPENED_NEW_FILES,
Expand Down Expand Up @@ -2604,6 +2605,7 @@ export class ClineProvider
terminalZdotdir,
terminalProfile,
mcpEnabled,
showMcpDescriptions,
currentApiConfigName,
listApiConfigMeta,
pinnedApiConfigs,
Expand Down Expand Up @@ -2767,6 +2769,7 @@ export class ClineProvider
terminalZdotdir: terminalZdotdir ?? false,
terminalProfile,
mcpEnabled: mcpEnabled ?? true,
showMcpDescriptions: showMcpDescriptions ?? DEFAULT_SHOW_MCP_DESCRIPTIONS,
currentApiConfigName: currentApiConfigName ?? "default",
listApiConfigMeta: listApiConfigMeta ?? [],
pinnedApiConfigs: pinnedApiConfigs ?? {},
Expand Down Expand Up @@ -3003,6 +3006,7 @@ export class ClineProvider
mode: stateValues.mode ?? defaultModeSlug,
language: stateValues.language ?? formatLanguage(vscode.env.language),
mcpEnabled: stateValues.mcpEnabled ?? true,
showMcpDescriptions: stateValues.showMcpDescriptions ?? DEFAULT_SHOW_MCP_DESCRIPTIONS,
mcpServers: this.mcpHub?.getAllServers() ?? [],
currentApiConfigName: stateValues.currentApiConfigName ?? "default",
listApiConfigMeta: stateValues.listApiConfigMeta ?? [],
Expand Down
22 changes: 22 additions & 0 deletions src/core/webview/__tests__/ClineProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ORGANIZATION_ALLOW_ALL,
DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
DEFAULT_DIFF_FUZZY_THRESHOLD,
DEFAULT_SHOW_MCP_DESCRIPTIONS,
DEFAULT_WRITE_DELAY_MS,
providerIdentifiers,
} from "@roo-code/types"
Expand Down Expand Up @@ -1352,6 +1353,27 @@ describe("ClineProvider", () => {
expect(postedState.apiConfiguration).toMatchObject(expectedConfiguration)
})

it.each([true, false])("returns a saved MCP description visibility value of %s", async (value) => {
await provider.resolveWebviewView(mockWebviewView)
await provider.contextProxy.setValue("showMcpDescriptions", value)

const state = await provider.getState()
const postedState = await provider.getStateToPostToWebview()

expect(state.showMcpDescriptions).toBe(value)
expect(postedState.showMcpDescriptions).toBe(value)
})

test("shows MCP descriptions by default in runtime and posted state", async () => {
await provider.resolveWebviewView(mockWebviewView)

const state = await provider.getState()
const postedState = await provider.getStateToPostToWebview()

expect(state.showMcpDescriptions).toBe(DEFAULT_SHOW_MCP_DESCRIPTIONS)
expect(postedState.showMcpDescriptions).toBe(DEFAULT_SHOW_MCP_DESCRIPTIONS)
})

test("getState returns the saved destructive command guard setting", async () => {
await provider.contextProxy.setValue("destructiveCommandGuardEnabled", true)

Expand Down
14 changes: 14 additions & 0 deletions src/core/webview/__tests__/webviewMessageHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,20 @@ describe("webviewMessageHandler - mcpEnabled", () => {
})
})

describe("webviewMessageHandler - showMcpDescriptions", () => {
it.each([true, false])("persists %s through the generic settings path", async (value) => {
vi.clearAllMocks()

await webviewMessageHandler(mockClineProvider, {
type: "updateSettings",
updatedSettings: { showMcpDescriptions: value },
})

expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("showMcpDescriptions", value)
expect(mockClineProvider.postStateToWebview).toHaveBeenCalledTimes(1)
})
})

describe("webviewMessageHandler - destructiveCommandGuardEnabled", () => {
beforeEach(() => {
vi.clearAllMocks()
Expand Down
3 changes: 3 additions & 0 deletions webview-ui/src/components/chat/ChatRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export const ChatRowContent = ({
const {
mcpServers,
alwaysAllowMcp,
showMcpDescriptions,
currentCheckpoint,
mode,
apiConfiguration,
Expand Down Expand Up @@ -1661,6 +1662,7 @@ export const ChatRowContent = ({
// Always use the actual URI from the request
uri: useMcpServer.uri || "",
}}
showDescription={showMcpDescriptions}
/>
)}
{useMcpServer.type === "use_mcp_tool" && (
Expand All @@ -1673,6 +1675,7 @@ export const ChatRowContent = ({
server={server}
useMcpServer={useMcpServer}
alwaysAllowMcp={alwaysAllowMcp}
showMcpDescriptions={showMcpDescriptions}
/>
)}
</div>
Expand Down
4 changes: 4 additions & 0 deletions webview-ui/src/components/chat/McpExecution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface McpExecutionProps {
}
useMcpServer?: ClineAskUseMcpServer
alwaysAllowMcp?: boolean
showMcpDescriptions?: boolean
}

export const McpExecution = ({
Expand All @@ -47,6 +48,7 @@ export const McpExecution = ({
server,
useMcpServer,
alwaysAllowMcp = false,
showMcpDescriptions = true,
}: McpExecutionProps) => {
const { t } = useTranslation("mcp")

Expand Down Expand Up @@ -251,6 +253,7 @@ export const McpExecution = ({
serverSource={server?.source}
alwaysAllowMcp={alwaysAllowMcp}
isInChatContext={true}
showDescription={showMcpDescriptions}
/>
</div>
)}
Expand All @@ -266,6 +269,7 @@ export const McpExecution = ({
serverSource={undefined}
alwaysAllowMcp={alwaysAllowMcp}
isInChatContext={true}
showDescription={showMcpDescriptions}
/>
</div>
)}
Expand Down
33 changes: 18 additions & 15 deletions webview-ui/src/components/mcp/McpResourceRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import type { McpResource, McpResourceTemplate } from "@roo-code/types"

type McpResourceRowProps = {
item: McpResource | McpResourceTemplate
showDescription?: boolean
}

const McpResourceRow = ({ item }: McpResourceRowProps) => {
const McpResourceRow = ({ item, showDescription = true }: McpResourceRowProps) => {
const hasUri = "uri" in item
const uri = hasUri ? item.uri : item.uriTemplate

Expand All @@ -23,20 +24,22 @@ const McpResourceRow = ({ item }: McpResourceRowProps) => {
<span className={`codicon codicon-symbol-file`} style={{ marginRight: "6px" }} />
<span style={{ fontWeight: 500, wordBreak: "break-all" }}>{uri}</span>
</div>
<div
style={{
fontSize: "12px",
opacity: 0.8,
margin: "4px 0",
}}>
{item.name && item.description
? `${item.name}: ${item.description}`
: !item.name && item.description
? item.description
: !item.description && item.name
? item.name
: "No description"}
</div>
{(item.name || showDescription) && (
<div
style={{
fontSize: "12px",
opacity: 0.8,
margin: "4px 0",
}}>
{item.name && showDescription && item.description
? `${item.name}: ${item.description}`
: !item.name && showDescription && item.description
? item.description
: item.name
? item.name
: "No description"}
</div>
)}
<div
style={{
fontSize: "12px",
Expand Down
12 changes: 10 additions & 2 deletions webview-ui/src/components/mcp/McpToolRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ type McpToolRowProps = {
serverSource?: "global" | "project"
alwaysAllowMcp?: boolean
isInChatContext?: boolean
showDescription?: boolean
}

const McpToolRow = ({ tool, serverName, serverSource, alwaysAllowMcp, isInChatContext = false }: McpToolRowProps) => {
const McpToolRow = ({
tool,
serverName,
serverSource,
alwaysAllowMcp,
isInChatContext = false,
showDescription = true,
}: McpToolRowProps) => {
const { t } = useAppTranslation()
const isToolEnabled = tool.enabledForPrompt ?? true

Expand Down Expand Up @@ -95,7 +103,7 @@ const McpToolRow = ({ tool, serverName, serverSource, alwaysAllowMcp, isInChatCo
</div>
)}
</div>
{tool.description && (
{showDescription && tool.description && (
<div className="mt-1 text-xs text-vscode-descriptionForeground">{tool.description}</div>
)}
{isToolEnabled &&
Expand Down
61 changes: 56 additions & 5 deletions webview-ui/src/components/mcp/McpView.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import React, { useState } from "react"
import { Trans } from "react-i18next"
import { VSCodeLink, VSCodePanels, VSCodePanelTab, VSCodePanelView } from "@vscode/webview-ui-toolkit/react"
import {
VSCodeCheckbox,
VSCodeLink,
VSCodePanels,
VSCodePanelTab,
VSCodePanelView,
} from "@vscode/webview-ui-toolkit/react"

import type { McpServer } from "@roo-code/types"
import { DEFAULT_SHOW_MCP_DESCRIPTIONS, type McpServer } from "@roo-code/types"

import { vscode } from "@src/utils/vscode"
import { useExtensionState } from "@src/context/ExtensionStateContext"
Expand Down Expand Up @@ -31,14 +37,27 @@ import { McpErrorRow } from "./McpErrorRow"
interface McpViewProps {
mcpEnabled?: boolean
setMcpEnabled?: (value: boolean) => void
showMcpDescriptions?: boolean
setShowMcpDescriptions?: (value: boolean) => void
}

const McpView = ({ mcpEnabled: propsMcpEnabled, setMcpEnabled }: McpViewProps = {}) => {
const { mcpServers: servers, alwaysAllowMcp, mcpEnabled: contextMcpEnabled } = useExtensionState()
const McpView = ({
mcpEnabled: propsMcpEnabled,
setMcpEnabled,
showMcpDescriptions: propsShowMcpDescriptions,
setShowMcpDescriptions,
}: McpViewProps = {}) => {
const {
mcpServers: servers,
alwaysAllowMcp,
mcpEnabled: contextMcpEnabled,
showMcpDescriptions: contextShowMcpDescriptions,
} = useExtensionState()

// When rendered inside SettingsView the value is buffered in `cachedState` and
// only persisted on Save. Fall back to live extension state when used uncontrolled.
const mcpEnabled = propsMcpEnabled ?? contextMcpEnabled
const showMcpDescriptions = propsShowMcpDescriptions ?? contextShowMcpDescriptions ?? DEFAULT_SHOW_MCP_DESCRIPTIONS

const { t } = useAppTranslation()
const { isOverThreshold, title, message } = useTooManyTools()
Expand Down Expand Up @@ -66,6 +85,27 @@ const McpView = ({ mcpEnabled: propsMcpEnabled, setMcpEnabled }: McpViewProps =

<McpEnabledToggle mcpEnabled={mcpEnabled} setMcpEnabled={setMcpEnabled} />

{mcpEnabled && (
<div style={{ marginBottom: "20px" }}>
<VSCodeCheckbox
checked={showMcpDescriptions}
onChange={(event) => {
const target = event.target as HTMLInputElement
setShowMcpDescriptions?.(target.checked)
}}>
<span style={{ fontWeight: "500" }}>{t("mcp:showDescriptions.title")}</span>
</VSCodeCheckbox>
<p
style={{
fontSize: "12px",
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
{t("mcp:showDescriptions.description")}
</p>
</div>
)}

{mcpEnabled && (
<>
{/* Too Many Tools Warning */}
Expand Down Expand Up @@ -101,6 +141,7 @@ const McpView = ({ mcpEnabled: propsMcpEnabled, setMcpEnabled }: McpViewProps =
key={`${server.name}-${server.source || "global"}`}
server={server}
alwaysAllowMcp={alwaysAllowMcp}
showMcpDescriptions={showMcpDescriptions}
/>
))}
</div>
Expand Down Expand Up @@ -183,7 +224,15 @@ const McpView = ({ mcpEnabled: propsMcpEnabled, setMcpEnabled }: McpViewProps =
)
}

const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowMcp?: boolean }) => {
const ServerRow = ({
server,
alwaysAllowMcp,
showMcpDescriptions,
}: {
server: McpServer
alwaysAllowMcp?: boolean
showMcpDescriptions: boolean
}) => {
const { t } = useAppTranslation()
const [isExpanded, setIsExpanded] = useState(false)
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
Expand Down Expand Up @@ -377,6 +426,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
serverName={server.name}
serverSource={server.source || "global"}
alwaysAllowMcp={alwaysAllowMcp}
showDescription={showMcpDescriptions}
/>
))}
</div>
Expand All @@ -403,6 +453,7 @@ const ServerRow = ({ server, alwaysAllowMcp }: { server: McpServer; alwaysAllowM
<McpResourceRow
key={"uriTemplate" in item ? item.uriTemplate : item.uri}
item={item}
showDescription={showMcpDescriptions}
/>
),
)}
Expand Down
Loading
Loading