From 308bdbc7c99ea18f946c7b630c12d296a540eac4 Mon Sep 17 00:00:00 2001 From: GHX5T-SOL <200635707+GHX5T-SOL@users.noreply.github.com> Date: Mon, 18 May 2026 15:05:42 +0200 Subject: [PATCH 1/2] Fix MCP exec permission display metadata --- .../components/permissions/McpPermission.tsx | 23 ++++++++-- .../permissions/PermissionSelector.test.tsx | 42 +++++++++++++++++++ .../permissions/PermissionSelector.tsx | 4 +- .../permissions/permission-handlers.test.ts | 27 ++++++++++++ .../claude/permissions/permission-handlers.ts | 1 + 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 apps/code/src/renderer/components/permissions/PermissionSelector.test.tsx diff --git a/apps/code/src/renderer/components/permissions/McpPermission.tsx b/apps/code/src/renderer/components/permissions/McpPermission.tsx index 375926665..0f272a83b 100644 --- a/apps/code/src/renderer/components/permissions/McpPermission.tsx +++ b/apps/code/src/renderer/components/permissions/McpPermission.tsx @@ -8,7 +8,24 @@ import { import { formatInput } from "@features/sessions/components/session-update/toolCallUtils"; import { Box, Code } from "@radix-ui/themes"; import { DefaultPermission } from "./DefaultPermission"; -import { type BasePermissionProps, toSelectorOptions } from "./types"; +import { + type BasePermissionProps, + type PermissionToolCall, + toSelectorOptions, +} from "./types"; + +export function getMcpPermissionToolName( + toolCall: PermissionToolCall, +): string | undefined { + const metaToolName = ( + toolCall._meta as { claudeCode?: { toolName?: unknown } } | undefined + )?.claudeCode?.toolName; + if (typeof metaToolName === "string") return metaToolName; + + const rawToolName = (toolCall.rawInput as { toolName?: unknown } | undefined) + ?.toolName; + return typeof rawToolName === "string" ? rawToolName : undefined; +} export function McpPermission({ toolCall, @@ -16,9 +33,7 @@ export function McpPermission({ onSelect, onCancel, }: BasePermissionProps) { - const mcpToolName = ( - toolCall._meta as { claudeCode?: { toolName?: string } } | undefined - )?.claudeCode?.toolName; + const mcpToolName = getMcpPermissionToolName(toolCall); if (!mcpToolName) { return ( diff --git a/apps/code/src/renderer/components/permissions/PermissionSelector.test.tsx b/apps/code/src/renderer/components/permissions/PermissionSelector.test.tsx new file mode 100644 index 000000000..ace911295 --- /dev/null +++ b/apps/code/src/renderer/components/permissions/PermissionSelector.test.tsx @@ -0,0 +1,42 @@ +import { Theme } from "@radix-ui/themes"; +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import { PermissionSelector } from "./PermissionSelector"; + +describe("PermissionSelector", () => { + it("renders MCP permissions from rawInput toolName when metadata is missing", () => { + render( + + + , + ); + + expect( + screen.getByText( + (_, element) => + element?.textContent === "posthog - Read execute-sql (MCP)", + ), + ).toBeInTheDocument(); + expect(screen.queryByText(/^exec$/)).not.toBeInTheDocument(); + }); +}); diff --git a/apps/code/src/renderer/components/permissions/PermissionSelector.tsx b/apps/code/src/renderer/components/permissions/PermissionSelector.tsx index b89ad00d0..81d499e2b 100644 --- a/apps/code/src/renderer/components/permissions/PermissionSelector.tsx +++ b/apps/code/src/renderer/components/permissions/PermissionSelector.tsx @@ -4,7 +4,7 @@ import { DeletePermission } from "./DeletePermission"; import { EditPermission } from "./EditPermission"; import { ExecutePermission } from "./ExecutePermission"; import { FetchPermission } from "./FetchPermission"; -import { McpPermission } from "./McpPermission"; +import { getMcpPermissionToolName, McpPermission } from "./McpPermission"; import { MovePermission } from "./MovePermission"; import { QuestionPermission } from "./QuestionPermission"; import { ReadPermission } from "./ReadPermission"; @@ -34,7 +34,7 @@ export function PermissionSelector({ const meta = toolCall._meta as | { codeToolKind?: string; claudeCode?: { toolName?: string } } | undefined; - const agentToolName = meta?.claudeCode?.toolName; + const agentToolName = getMcpPermissionToolName(toolCall); if (agentToolName?.startsWith("mcp__")) { return ; } diff --git a/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts b/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts index 15a3ee00b..dfcc425b1 100644 --- a/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts +++ b/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts @@ -74,6 +74,33 @@ describe("canUseTool MCP approval enforcement", () => { expect.objectContaining({ toolCall: expect.objectContaining({ title: "The agent wants to call search_crm_objects (HubSpot)", + _meta: { + claudeCode: { toolName: "mcp__HubSpot__search_crm_objects" }, + }, + }), + }), + ); + }); + + it("passes metadata through generic PostHog exec approval requests", async () => { + setMcpToolApprovalStates({ + mcp__posthog__exec: "needs_approval", + }); + + const context = createContext("mcp__posthog__exec", { + toolInput: { command: "info execute-sql" }, + }); + const result = await canUseTool(context); + + expect(result.behavior).toBe("allow"); + expect(context.client.requestPermission).toHaveBeenCalledWith( + expect.objectContaining({ + toolCall: expect.objectContaining({ + rawInput: expect.objectContaining({ + command: "info execute-sql", + toolName: "mcp__posthog__exec", + }), + _meta: { claudeCode: { toolName: "mcp__posthog__exec" } }, }), }), ); diff --git a/packages/agent/src/adapters/claude/permissions/permission-handlers.ts b/packages/agent/src/adapters/claude/permissions/permission-handlers.ts index ec071bd93..6d1075b46 100644 --- a/packages/agent/src/adapters/claude/permissions/permission-handlers.ts +++ b/packages/agent/src/adapters/claude/permissions/permission-handlers.ts @@ -457,6 +457,7 @@ async function handleMcpApprovalFlow( ? [{ type: "content" as const, content: text(description) }] : [], rawInput: { ...(toolInput as Record), toolName }, + _meta: { claudeCode: { toolName } }, }, }); From 1e63cce2637ccdd087b9778dc3119210821e2222 Mon Sep 17 00:00:00 2001 From: GHX5T-SOL <200635707+GHX5T-SOL@users.noreply.github.com> Date: Mon, 18 May 2026 15:19:01 +0200 Subject: [PATCH 2/2] Simplify MCP permission selector metadata type --- .../renderer/components/permissions/PermissionSelector.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/code/src/renderer/components/permissions/PermissionSelector.tsx b/apps/code/src/renderer/components/permissions/PermissionSelector.tsx index 81d499e2b..c571e6150 100644 --- a/apps/code/src/renderer/components/permissions/PermissionSelector.tsx +++ b/apps/code/src/renderer/components/permissions/PermissionSelector.tsx @@ -31,9 +31,7 @@ export function PermissionSelector({ onCancel, }: PermissionSelectorProps) { const props = { toolCall, options, onSelect, onCancel }; - const meta = toolCall._meta as - | { codeToolKind?: string; claudeCode?: { toolName?: string } } - | undefined; + const meta = toolCall._meta as { codeToolKind?: string } | undefined; const agentToolName = getMcpPermissionToolName(toolCall); if (agentToolName?.startsWith("mcp__")) { return ;