Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,19 @@ export function ActionSelector({
/>
)}

{title && (
<Text className="font-medium text-[13px] text-primary" title={title}>
{compactHomePath(title)}
</Text>
)}
{title &&
(typeof title === "string" ? (
<Text
className="font-medium text-[13px] text-primary"
title={title}
>
{compactHomePath(title)}
</Text>
) : (
<Text className="font-medium text-[13px] text-primary">
{title}
</Text>
))}

{pendingAction && <Box>{pendingAction}</Box>}

Expand Down
2 changes: 1 addition & 1 deletion apps/code/src/renderer/components/action-selector/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface StepAnswer {
}

export interface ActionSelectorProps {
title: string;
title: ReactNode;
pendingAction?: ReactNode;
question: ReactNode;
options: SelectorOption[];
Expand Down
70 changes: 70 additions & 0 deletions apps/code/src/renderer/components/permissions/McpPermission.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ActionSelector } from "@components/ActionSelector";
import { parseMcpToolKey } from "@features/mcp-apps/utils/mcp-app-host-utils";
import {
getPostHogExecDisplay,
isPostHogExecTool,
} from "@features/mcp-apps/utils/posthog-exec-display";
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";

export function McpPermission({
toolCall,
options,
onSelect,
onCancel,
}: BasePermissionProps) {
const mcpToolName = (
toolCall._meta as { claudeCode?: { toolName?: string } } | undefined
)?.claudeCode?.toolName;

if (!mcpToolName) {
return (
<DefaultPermission
toolCall={toolCall}
options={options}
onSelect={onSelect}
onCancel={onCancel}
/>
);
}

const { serverName: defaultServerName, toolName: defaultToolName } =
parseMcpToolKey(mcpToolName);
const posthogDisplay = isPostHogExecTool(mcpToolName)
? getPostHogExecDisplay(toolCall.rawInput)
: null;
const serverName = posthogDisplay ? "posthog" : defaultServerName;
const toolName = posthogDisplay?.label ?? defaultToolName;
const fullInput = formatInput(toolCall.rawInput);

return (
<ActionSelector
title={
<>
<span className="text-gray-10">{serverName}</span>
{" - "}
{toolName}
<span className="text-gray-10">{" (MCP)"}</span>
</>
}
pendingAction={
fullInput ? (
<Box className="max-h-[30vh] overflow-auto">
<Code
variant="ghost"
className="whitespace-pre-wrap break-all text-[13px]"
>
{fullInput}
</Code>
</Box>
) : undefined
}
question="Do you want to proceed?"
options={toSelectorOptions(options)}
onSelect={onSelect}
onCancel={onCancel}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,57 @@ export const Default: Story = {
},
};

function buildMcpToolCallData(
mcpToolName: string,
rawInput: Record<string, unknown>,
) {
return {
toolCallId: `story-${Date.now()}`,
title: mcpToolName.split("__").slice(2).join("__") || mcpToolName,
kind: "other" as const,
rawInput,
content: [],
_meta: { claudeCode: { toolName: mcpToolName } },
};
}

const posthogExecInput = {
command: 'call execute-sql {"query":"select 1"}',
};
export const McpPostHogExec: Story = {
args: {
toolCall: buildMcpToolCallData("mcp__posthog__exec", posthogExecInput),
options: buildPermissionOptions("mcp__posthog__exec", posthogExecInput),
},
};

const githubIssueInput = {
owner: "PostHog",
repo: "posthog",
title: "Investigate intermittent flake in foo test",
body: "Seen on CI runs 12345 and 67890 — appears related to fixture cleanup ordering.",
labels: ["bug", "ci"],
};
export const McpGithubCreateIssue: Story = {
args: {
toolCall: buildMcpToolCallData(
"mcp__github__create_issue",
githubIssueInput,
),
options: buildPermissionOptions(
"mcp__github__create_issue",
githubIssueInput,
),
},
};

export const McpNoArgs: Story = {
args: {
toolCall: buildMcpToolCallData("mcp__example__ping", {}),
options: buildPermissionOptions("mcp__example__ping", {}),
},
};

const exitPlanModeInput = {
plan: `# Add Dark Mode Support

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DeletePermission } from "./DeletePermission";
import { EditPermission } from "./EditPermission";
import { ExecutePermission } from "./ExecutePermission";
import { FetchPermission } from "./FetchPermission";
import { McpPermission } from "./McpPermission";
import { MovePermission } from "./MovePermission";
import { QuestionPermission } from "./QuestionPermission";
import { ReadPermission } from "./ReadPermission";
Expand All @@ -30,9 +31,14 @@ export function PermissionSelector({
onCancel,
}: PermissionSelectorProps) {
const props = { toolCall, options, onSelect, onCancel };
const codeToolKind = (toolCall._meta as { codeToolKind?: string } | undefined)
?.codeToolKind;
const kind = codeToolKind ?? (toolCall.kind as string);
const meta = toolCall._meta as
| { codeToolKind?: string; claudeCode?: { toolName?: string } }
| undefined;
const agentToolName = meta?.claudeCode?.toolName;
if (agentToolName?.startsWith("mcp__")) {
return <McpPermission {...props} />;
}
const kind = meta?.codeToolKind ?? (toolCall.kind as string);

switch (kind) {
case "execute":
Expand Down
Loading