import { ActionIcon, Alert, Box, Button, Code, CopyButton, Divider, Group, Loader, Modal, Stack, Table, Text, TextInput, Tooltip, } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { IconCopy, IconCheck, IconTrash } from "@tabler/icons-react"; import { useCallback, useEffect, useState } from "react"; import * as api from "../api"; import type { MCPToken, MCPTokenCreated } from "../api"; import { formatDateTimeShort } from "./format"; interface Props { opened: boolean; onClose: () => void; } export function MCPTokensModal({ opened, onClose }: Props) { const [tokens, setTokens] = useState([]); const [loading, setLoading] = useState(false); const [newName, setNewName] = useState(""); const [creating, setCreating] = useState(false); const [justCreated, setJustCreated] = useState(null); const reload = useCallback(async () => { setLoading(true); try { setTokens(await api.listMCPTokens()); } catch (e) { notifications.show({ color: "red", message: (e as Error).message }); } finally { setLoading(false); } }, []); useEffect(() => { if (opened) { reload(); setJustCreated(null); setNewName(""); } }, [opened, reload]); const create = async () => { const name = newName.trim() || "default"; setCreating(true); try { const t = await api.createMCPToken(name); setJustCreated(t); setNewName(""); await reload(); } catch (e) { notifications.show({ color: "red", message: (e as Error).message }); } finally { setCreating(false); } }; const revoke = async (id: string) => { if (!confirm("Revocar este token? Quien lo este usando dejara de tener acceso.")) return; try { await api.revokeMCPToken(id); await reload(); } catch (e) { notifications.show({ color: "red", message: (e as Error).message }); } }; const mcpURL = `${window.location.origin}/mcp`; const claudeCmd = justCreated ? `claude mcp add kanban --transport http ${mcpURL} --header "Authorization: Bearer ${justCreated.token}"` : ""; return ( Cada token deja conectar un cliente Claude al kanban como tu usuario. El valor solo aparece UNA vez al crearlo. Si lo pierdes, generas otro y revocas el antiguo. setNewName(e.currentTarget.value)} style={{ flex: 1 }} disabled={creating} /> {justCreated && ( {justCreated.token} {({ copied, copy }) => ( {copied ? : } )} Pega este comando en tu PC para registrar el MCP en Claude Code: {claudeCmd} {({ copied, copy }) => ( {copied ? : } )} )} {loading ? ( ) : tokens.length === 0 ? ( Sin tokens. Genera uno arriba. ) : ( Nombre Creado Ultimo uso {tokens.map((t) => ( {t.name} {formatDateTimeShort(t.created_at)} {t.last_used_at ? formatDateTimeShort(t.last_used_at) : nunca} revoke(t.id)}> ))}
)} Endpoint MCP: {mcpURL}
); }