diff --git a/apps/code/src/renderer/components/permissions/McpPermission.tsx b/apps/code/src/renderer/components/permissions/McpPermission.tsx
index 375926665..0bc12d1e5 100644
--- a/apps/code/src/renderer/components/permissions/McpPermission.tsx
+++ b/apps/code/src/renderer/components/permissions/McpPermission.tsx
@@ -8,7 +8,11 @@ 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,
+ getMcpPermissionToolName,
+ toSelectorOptions,
+} from "./types";
export function McpPermission({
toolCall,
@@ -16,9 +20,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..7aabae858
--- /dev/null
+++ b/apps/code/src/renderer/components/permissions/PermissionSelector.test.tsx
@@ -0,0 +1,40 @@
+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 using claudeCode.toolName metadata", () => {
+ 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..74954d9af 100644
--- a/apps/code/src/renderer/components/permissions/PermissionSelector.tsx
+++ b/apps/code/src/renderer/components/permissions/PermissionSelector.tsx
@@ -11,7 +11,7 @@ import { ReadPermission } from "./ReadPermission";
import { SearchPermission } from "./SearchPermission";
import { SwitchModePermission } from "./SwitchModePermission";
import { ThinkPermission } from "./ThinkPermission";
-import type { PermissionToolCall } from "./types";
+import { getMcpPermissionToolName, type PermissionToolCall } from "./types";
interface PermissionSelectorProps {
toolCall: PermissionToolCall;
@@ -31,10 +31,8 @@ export function PermissionSelector({
onCancel,
}: PermissionSelectorProps) {
const props = { toolCall, options, onSelect, onCancel };
- const meta = toolCall._meta as
- | { codeToolKind?: string; claudeCode?: { toolName?: string } }
- | undefined;
- const agentToolName = meta?.claudeCode?.toolName;
+ const meta = toolCall._meta as { codeToolKind?: string } | undefined;
+ const agentToolName = getMcpPermissionToolName(toolCall);
if (agentToolName?.startsWith("mcp__")) {
return ;
}
diff --git a/apps/code/src/renderer/components/permissions/types.ts b/apps/code/src/renderer/components/permissions/types.ts
index ba7cd12c8..f09ec034b 100644
--- a/apps/code/src/renderer/components/permissions/types.ts
+++ b/apps/code/src/renderer/components/permissions/types.ts
@@ -22,6 +22,15 @@ export interface BasePermissionProps {
onCancel: () => void;
}
+export function getMcpPermissionToolName(
+ toolCall: PermissionToolCall,
+): string | undefined {
+ const toolName = (
+ toolCall._meta as { claudeCode?: { toolName?: unknown } } | undefined
+ )?.claudeCode?.toolName;
+ return typeof toolName === "string" ? toolName : undefined;
+}
+
export function toSelectorOptions(
options: PermissionOption[],
): SelectorOption[] {
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 } },
},
});