import React, { useState } from "react"; import { Check, Copy } from "lucide-react"; import { useI18n } from "../../../../application/i18n/I18nProvider"; import type { AIToolIntegrationMode } from "../../../../infrastructure/ai/types"; import { cn } from "../../../../lib/utils"; import { useToolAccessGuidanceState } from "../../../../application/state/useToolAccessGuidanceState"; import { EXTERNAL_MCP_DISCOVERY_ENV_VAR } from "./ExternalMcpCard"; /** Build a ready-to-paste prompt so an external AI client can register Netcatty MCP itself. */ export function buildMcpOnboardingPrompt( launcherPath: string | null | undefined, discoveryPath: string | null | undefined, ): string { if (!launcherPath) { return [ "Please connect Netcatty to this session via MCP.", "In the Netcatty desktop app, open Settings → AI → Tool Access, turn on External MCP,", "then copy the generated prompt from the Tool Access section and run it here.", "After that, list the netcatty-external MCP tools and call get_environment to verify the connection.", ].join(" "); } const lines = [ "Please register Netcatty's MCP server in your MCP client configuration:", `- Server name: netcatty-external`, `- Transport: local stdio`, `- Command: ${launcherPath}`, ]; if (discoveryPath) { lines.push(`- Environment: ${EXTERNAL_MCP_DISCOVERY_ENV_VAR}=${discoveryPath}`); } lines.push( "After registering, list the server's tools and call get_environment to verify the connection.", "Keep the Netcatty desktop app running while you use these tools.", ); return lines.join("\n"); } type CopyRowProps = { value: string; label: string; copyLabel: string; copiedLabel: string; testId?: string; }; const CopyRow: React.FC = ({ value, label, copyLabel, copiedLabel, testId }) => { const [copied, setCopied] = useState(false); const canCopy = Boolean(value); const handleCopy = async () => { if (!value) return; try { await navigator.clipboard.writeText(value); setCopied(true); window.setTimeout(() => setCopied(false), 1200); } catch { // Clipboard may be unavailable; the text stays selectable in the block. } }; return (
{label}
          {value}
        
); }; export const ToolAccessGuidance: React.FC<{ mode: AIToolIntegrationMode }> = ({ mode }) => { const { t } = useI18n(); const { skillPath, commandPrefix, mcpLauncherPath, mcpDiscoveryPath } = useToolAccessGuidanceState(mode); if (mode === "skills") { return (

{t("ai.toolAccess.skills.description")}

{!skillPath ? (

{t("ai.toolAccess.skills.unavailable")}

) : null} {commandPrefix ? (

{commandPrefix}

) : null}
); } return (

{t("ai.toolAccess.mcpPrompt.description")}

{!mcpLauncherPath ? (

{t("ai.toolAccess.mcpPrompt.enableHint")}

) : null}
); };