diff --git a/messages/en.json b/messages/en.json index a57aa8176..aabdc5903 100644 --- a/messages/en.json +++ b/messages/en.json @@ -810,6 +810,10 @@ "public": "Featured", "publicDescription": "Featured for all users to use", "featured": "Featured", - "featuredDescription": "Featured for all users to use" + "featuredDescription": "Featured for all users to use", + "authorizationRequired": "Authorization Required", + "authorizationRequiredDescription": "{serverName} requires authorization to access its tools.", + "authorize": "Authorize", + "authorizationFailed": "Authorization failed" } } diff --git a/messages/es.json b/messages/es.json index 812194058..883fc6172 100644 --- a/messages/es.json +++ b/messages/es.json @@ -374,6 +374,10 @@ "mcpServerCustomizationDescription": "Las instrucciones de personalización del servidor MCP se añadirán al prompt del sistema cuando el servidor MCP esté disponible.", "toolCustomizationInstructionsPlaceholder": "Las instrucciones de personalización de herramientas no están disponibles.", "mcpServerCustomizationPlaceholder": "ej. Si el valor de entrada es email, siempre ingresa el email en el formato ejemplo@ejemplo.com.", + "authorizationRequired": "Autorización Requerida", + "authorizationRequiredDescription": "{serverName} requiere autorización para acceder a sus herramientas.", + "authorize": "Autorizar", + "authorizationFailed": "Error de autorización", "noInstructions": "Ninguno" }, "Error": {}, @@ -465,7 +469,7 @@ "buildAutomationDescription": "Conecta varios nodos para automatizar tareas complejas. Cada nodo maneja funciones específicas, y los datos fluyen secuencialmente para su procesamiento.", "chatbotToolTitle": "Usar como Herramientas de Chatbot", "chatbotToolDescription": "El propósito principal de los flujos de trabajo es usarlos como herramientas en conversaciones de chatbot. Convierte tareas repetitivas en flujos de trabajo para una fácil ejecución durante los chats.", - "parameterBasedTitle": "️ Inicio Basado en Parámetros", + "parameterBasedTitle": " Inicio Basado en Parámetros", "parameterBasedDescription": "Los nodos de entrada definen estructuras de parámetros, no disparadores. Especifican el formato de datos necesario cuando el chatbot llama a este flujo de trabajo como herramienta.", "exampleTitle": "Ejemplo de Uso", "exampleDescription": "Crea un flujo de trabajo \"Escribir Email → Traducir → Enviar\", luego ejecútalo fácilmente en conversaciones de chatbot con \"@email_workflow\".", diff --git a/messages/fr.json b/messages/fr.json index 69c692b5d..6582418cb 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -374,6 +374,10 @@ "mcpServerCustomizationDescription": "Les instructions de personnalisation du serveur MCP seront ajoutées à l'invite système lorsque le serveur MCP sera disponible.", "toolCustomizationInstructionsPlaceholder": "Les instructions de personnalisation d'outils ne sont pas disponibles.", "mcpServerCustomizationPlaceholder": "ex. Si la valeur d'entrée est un email, toujours entrer l'email au format exemple@exemple.com.", + "authorizationRequired": "Autorisation Requise", + "authorizationRequiredDescription": "{serverName} nécessite une autorisation pour accéder à ses outils.", + "authorize": "Autoriser", + "authorizationFailed": "Échec de l'autorisation", "noInstructions": "Aucun" }, "Error": {}, @@ -465,7 +469,7 @@ "buildAutomationDescription": "Connectez divers nœuds pour automatiser des tâches complexes. Chaque nœud gère des fonctions spécifiques, et les données circulent séquentiellement pour le traitement.", "chatbotToolTitle": "Utiliser comme Outils de Chatbot", "chatbotToolDescription": "Le but principal des flux de travail est de les utiliser comme outils dans les conversations de chatbot. Transformez les tâches répétitives en flux de travail pour une exécution facile pendant les chats.", - "parameterBasedTitle": "️ Démarrage Basé sur les Paramètres", + "parameterBasedTitle": " Démarrage Basé sur les Paramètres", "parameterBasedDescription": "Les nœuds d'entrée définissent des structures de paramètres, pas des déclencheurs. Ils spécifient le format de données nécessaire quand le chatbot appelle ce flux de travail comme outil.", "exampleTitle": "Exemple d'Utilisation", "exampleDescription": "Créez un flux de travail \"Écrire Email → Traduire → Envoyer\", puis exécutez-le facilement dans les conversations de chatbot avec \"@email_workflow\".", diff --git a/messages/ja.json b/messages/ja.json index 538685ab2..e195450bf 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -373,6 +373,10 @@ "mcpServerCustomizationDescription": "MCPサーバーカスタマイゼーション指示は、MCPサーバーが利用可能な場合にシステムプロンプトに追加されます。", "toolCustomizationInstructionsPlaceholder": "ツールカスタマイゼーション指示は利用できません。", "mcpServerCustomizationPlaceholder": "例:入力値がメールの場合、常にexample@example.comの形式でメールを入力してください。", + "authorizationRequired": "認証が必要です", + "authorizationRequiredDescription": "{serverName} のツールにアクセスするには認証が必要です。", + "authorize": "認証", + "authorizationFailed": "認証に失敗しました", "noInstructions": "なし" }, "Error": {}, @@ -464,7 +468,7 @@ "buildAutomationDescription": "様々なノードを接続して複雑なタスクを自動化します。各ノードは特定の機能を担当し、データが順次流れて処理されます。", "chatbotToolTitle": "チャットボットツールとして活用", "chatbotToolDescription": "ワークフローの主な目的は、チャットボットの会話でツールとして使用することです。反復的なタスクをワークフローに変換して、チャット中に簡単に実行できます。", - "parameterBasedTitle": "️ パラメータベースの開始", + "parameterBasedTitle": " パラメータベースの開始", "parameterBasedDescription": "入力ノードはトリガーではなく、パラメータ構造を定義します。チャットボットがこのワークフローをツールとして呼び出すときに必要なデータ形式を指定します。", "exampleTitle": "使用例", "exampleDescription": "「メール作成 → 翻訳 → 送信」ワークフローを作成しておけば、チャットボットの会話で「@メール_ワークフロー」で簡単に実行できます。", diff --git a/messages/ko.json b/messages/ko.json index b94be57dc..1562b3aa7 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -388,6 +388,10 @@ "mcpServerCustomizationDescription": "MCP 서버 사용자 지정 지침은 MCP서버를 사용할 때 시스템 프롬프트에 추가됩니다.", "toolCustomizationInstructionsPlaceholder": "도구 사용자 지정 지침이 없습니다.", "mcpServerCustomizationPlaceholder": "예) 이 MCP 서버의 툴중에 입력값이 email인 경우 항상 example@example.com 형식으로 입력해주세요.", + "authorizationRequired": "인증 필요", + "authorizationRequiredDescription": "{serverName}의 도구에 액세스하려면 인증이 필요합니다.", + "authorize": "인증", + "authorizationFailed": "인증 실패", "noInstructions": "없음" }, "Error": {}, @@ -479,7 +483,7 @@ "buildAutomationDescription": "다양한 노드들을 연결하여 복잡한 작업을 자동화하세요. 각 노드는 특정 기능을 담당하며, 데이터가 순차적으로 흘러가며 처리됩니다.", "chatbotToolTitle": "챗봇 도구로 활용", "chatbotToolDescription": "워크플로우의 주요 목적은 챗봇에서 도구로 사용하는 것입니다. 반복적인 작업을 워크플로우로 만들어 대화 중 간단히 실행할 수 있습니다.", - "parameterBasedTitle": "️ 매개변수 기반 시작", + "parameterBasedTitle": " 매개변수 기반 시작", "parameterBasedDescription": "Input 노드는 트리거가 아닌 매개변수 구조를 정의합니다. 챗봇이 이 워크플로우를 도구로 호출할 때 필요한 데이터 형식을 지정합니다.", "exampleTitle": "사용 예시", "exampleDescription": "\"이메일 작성 → 번역 → 전송\" 워크플로우를 만들어두면, 챗봇 대화에서 \"@이메일_워크플로우\"로 간편하게 실행할 수 있습니다.", diff --git a/messages/no.json b/messages/no.json index f93a37b11..cd9f72504 100644 --- a/messages/no.json +++ b/messages/no.json @@ -810,6 +810,10 @@ "publicDescription": "Offentlig for alle brukere", "featured": "Fremhevet", "featuredDescription": "Fremhevet for alle brukere", + "authorizationRequired": "Autorisasjon kreves", + "authorizationRequiredDescription": "{serverName} krever autorisasjon for å få tilgang til verktøyene.", + "authorize": "Autoriser", + "authorizationFailed": "Autorisasjon feilet", "noInstructions": "Ingen" } } diff --git a/messages/zh.json b/messages/zh.json index 742d6b36c..b07535da3 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -373,6 +373,10 @@ "mcpServerCustomizationDescription": "MCP 服务器自定义指令将在 MCP 服务器可用时添加到系统提示中。", "toolCustomizationInstructionsPlaceholder": "工具自定义指令不可用。", "mcpServerCustomizationPlaceholder": "例如:如果输入值是电子邮件,始终以 example@example.com 格式输入电子邮件。", + "authorizationRequired": "需要授权", + "authorizationRequiredDescription": "{serverName} 需要授权才能访问其工具。", + "authorize": "授权", + "authorizationFailed": "授权失败", "noInstructions": "无" }, "Error": {}, @@ -464,7 +468,7 @@ "buildAutomationDescription": "连接各种节点来自动化复杂任务。每个节点处理特定功能,数据按顺序流动处理。", "chatbotToolTitle": "用作聊天机器人工具", "chatbotToolDescription": "工作流的主要目的是在聊天机器人对话中用作工具。将重复性任务转换为工作流,在聊天中轻松执行。", - "parameterBasedTitle": "️ 基于参数的开始", + "parameterBasedTitle": " 基于参数的开始", "parameterBasedDescription": "输入节点定义参数结构,而不是触发器。它们指定聊天机器人将此工作流用作工具时所需的数据格式。", "exampleTitle": "使用示例", "exampleDescription": "创建一个\"邮件编写 → 翻译 → 发送\"工作流,然后在聊天机器人对话中用\"@邮件_工作流\"轻松执行。", diff --git a/src/components/mcp-auth-dialog.tsx b/src/components/mcp-auth-dialog.tsx new file mode 100644 index 000000000..19cdc1cc3 --- /dev/null +++ b/src/components/mcp-auth-dialog.tsx @@ -0,0 +1,73 @@ +"use client"; + +import { useCallback, useState, useEffect } from "react"; +import { mutate } from "swr"; +import { toast } from "sonner"; +import { Loader } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "ui/dialog"; +import { Button } from "ui/button"; +import { redriectMcpOauth } from "lib/ai/mcp/oauth-redirect"; +import type { MCPServerInfo } from "app-types/mcp"; + +interface MCPAuthDialogProps { + server: MCPServerInfo | undefined; + serverName: string; +} + +export function MCPAuthDialog({ server, serverName }: MCPAuthDialogProps) { + const t = useTranslations(); + const [loading, setLoading] = useState(false); + const [dismissed, setDismissed] = useState(false); + + const needsAuth = server?.status === "authorizing"; + + useEffect(() => { + if (!needsAuth) { + setDismissed(false); + } + }, [needsAuth]); + + const handleAuthorize = useCallback(() => { + if (!server) return; + setLoading(true); + redriectMcpOauth(server.id) + .then(() => mutate("/api/mcp/list")) + .catch((err) => toast.error(err?.message || t("MCP.authorizationFailed"))) + .finally(() => setLoading(false)); + }, [server, t]); + + if (!server || !needsAuth || dismissed) return null; + + return ( + + ); +} diff --git a/src/components/message-parts.tsx b/src/components/message-parts.tsx index 366d989c8..9725d950b 100644 --- a/src/components/message-parts.tsx +++ b/src/components/message-parts.tsx @@ -1,5 +1,6 @@ "use client"; +import { mutate } from "swr"; import { FileUIPart, getToolName, ToolUIPart, UIMessage } from "ai"; import { Check, @@ -43,6 +44,8 @@ import { ChatMetadata, ChatModel, ManualToolConfirmTag } from "app-types/chat"; import { useTranslations } from "next-intl"; import { extractMCPToolId } from "lib/ai/mcp/mcp-tool-id"; import { Separator } from "ui/separator"; +import { useMcpList } from "@/hooks/queries/use-mcp-list"; +import { MCPAuthDialog } from "./mcp-auth-dialog"; import { TextShimmer } from "ui/text-shimmer"; import equal from "lib/equal"; @@ -755,6 +758,7 @@ export const ToolMessagePart = memo( isManualToolInvocation, }: ToolMessagePartProps) => { const t = useTranslations(""); + const { data: mcpList } = useMcpList(); const { output, toolCallId, state, input, errorText } = part; @@ -935,6 +939,16 @@ export const ToolMessagePart = memo( return extractMCPToolId(toolName); }, [toolName]); + const mcpServer = useMemo(() => { + return mcpList?.find((s) => s.name === mcpServerName); + }, [mcpList, mcpServerName]); + + useEffect(() => { + if (mcpServerName && (output as any)?.isError) { + mutate("/api/mcp/list"); + } + }, [mcpServerName, output]); + const isExpanded = useMemo(() => { return expanded || result === null || isWorkflowTool; }, [expanded, result, isWorkflowTool]); @@ -949,6 +963,8 @@ export const ToolMessagePart = memo( return (