diff --git a/web/src/app/home/mcp/components/mcp-form/MCPForm.tsx b/web/src/app/home/mcp/components/mcp-form/MCPForm.tsx index 985be21e..860e763a 100644 --- a/web/src/app/home/mcp/components/mcp-form/MCPForm.tsx +++ b/web/src/app/home/mcp/components/mcp-form/MCPForm.tsx @@ -40,6 +40,13 @@ import { CardTitle, } from '@/components/ui/card'; import { httpClient } from '@/app/infra/http/HttpClient'; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from '@/components/ui/tabs'; +import MCPReadme from '@/app/home/mcp/components/mcp-form/MCPReadme'; import { MCPServerRuntimeInfo, MCPTool, @@ -264,35 +271,10 @@ function RuntimePanel({ const isConnected = !mcpTesting && runtimeInfo.status === MCPSessionStatus.CONNECTED; - // Only treat an explicit error (or box-unavailable) as failed; while testing, - // connecting, or in an initial/unresolved state, show "connecting" so we - // don't flash "connection failed" during a normal connection attempt. - const isFailed = - !mcpTesting && - (runtimeInfo.status === MCPSessionStatus.ERROR || - runtimeInfo.error_phase === 'box_unavailable'); const tools = runtimeInfo.tools || []; return (
-
-
-

{t('mcp.title')}

-

- {isConnected - ? t('mcp.toolCount', { count: tools.length }) - : isFailed - ? t('mcp.connectionFailedStatus') - : t('mcp.connecting')} -

-
- {isConnected && ( - - {t('mcp.toolCount', { count: tools.length })} - - )} -
- {!isConnected && (
@@ -434,6 +416,9 @@ const MCPForm = forwardRef(function MCPForm( const [runtimeInfo, setRuntimeInfo] = useState( null, ); + // README markdown captured from LangBot Space at install time, surfaced in + // the Docs tab of the detail panel. Empty for manually-created servers. + const [readme, setReadme] = useState(''); const pollingIntervalRef = useRef(null); const watchMode = form.watch('mode'); const { @@ -611,6 +596,7 @@ const MCPForm = forwardRef(function MCPForm( setStdioArgs(newStdioArgs); form.reset(formValues); setRuntimeInfo(server.runtime_info ?? null); + setReadme(server.readme ?? ''); } catch (error) { console.error('Failed to load server:', error); toast.error(t('mcp.loadFailed')); @@ -1063,6 +1049,45 @@ const MCPForm = forwardRef(function MCPForm( /> ); + // In edit mode the right side shows a tablist switching between the live + // Tools list and the Docs (README captured from LangBot Space at install). + // Create mode has neither, so it falls back to the bare runtime placeholder. + // The tool count lives in the tab label (only when connected); the panel + // body itself no longer repeats a title/subtitle. + const toolsConnected = + !mcpTesting && runtimeInfo?.status === MCPSessionStatus.CONNECTED; + const toolsCount = runtimeInfo?.tools?.length ?? 0; + const toolsTabLabel = toolsConnected + ? `${t('mcp.tabTools')} ${toolsCount}` + : t('mcp.tabTools'); + + const detailPanel = isEditMode ? ( + + + + {t('mcp.tabDocs')} + + + {toolsTabLabel} + + + + + + + {runtimePanel} + + + ) : ( + runtimePanel + ); + if (layout === 'split') { return (
@@ -1078,7 +1103,7 @@ const MCPForm = forwardRef(function MCPForm(
- {runtimePanel} + {detailPanel}
@@ -1093,7 +1118,7 @@ const MCPForm = forwardRef(function MCPForm( className="space-y-5" > {sideHeader} - {runtimePanel} + {detailPanel} {configSection} {sideFooter} diff --git a/web/src/i18n/locales/en-US.ts b/web/src/i18n/locales/en-US.ts index 2313b723..c89e6fa7 100644 --- a/web/src/i18n/locales/en-US.ts +++ b/web/src/i18n/locales/en-US.ts @@ -2,7 +2,7 @@ const enUS = { sidebar: { home: 'Home', extensions: 'Extensions', - installedPlugins: 'Installed Extensions', + installedPlugins: 'Installed', pluginMarket: 'Extension Market', mcpServers: 'MCP Servers', addExtension: 'Add Extension', @@ -765,6 +765,9 @@ const enUS = { toolsFound: 'tools', unknownError: 'Unknown error', noToolsFound: 'No tools found', + tabTools: 'Tools', + tabDocs: 'Docs', + noReadme: 'No documentation available', parseResultFailed: 'Failed to parse test result', noResultReturned: 'Test returned no result', getTaskFailed: 'Failed to get task status', diff --git a/web/src/i18n/locales/es-ES.ts b/web/src/i18n/locales/es-ES.ts index 40f30bbd..6e609241 100644 --- a/web/src/i18n/locales/es-ES.ts +++ b/web/src/i18n/locales/es-ES.ts @@ -2,7 +2,7 @@ const esES = { sidebar: { home: 'Inicio', extensions: 'Extensiones', - installedPlugins: 'Plugins instalados', + installedPlugins: 'Instalados', pluginMarket: 'Tienda', mcpServers: 'Servidores MCP', addExtension: 'Añadir extensión', @@ -779,6 +779,9 @@ const esES = { toolsFound: 'herramientas', unknownError: 'Error desconocido', noToolsFound: 'No se encontraron herramientas', + tabTools: 'Herramientas', + tabDocs: 'Documentación', + noReadme: 'No hay documentación disponible', parseResultFailed: 'Error al analizar el resultado de la prueba', noResultReturned: 'La prueba no devolvió resultados', getTaskFailed: 'Error al obtener el estado de la tarea', diff --git a/web/src/i18n/locales/ja-JP.ts b/web/src/i18n/locales/ja-JP.ts index 845b6cc7..3d70cbcd 100644 --- a/web/src/i18n/locales/ja-JP.ts +++ b/web/src/i18n/locales/ja-JP.ts @@ -2,7 +2,7 @@ const jaJP = { sidebar: { home: 'ホーム', extensions: '拡張機能', - installedPlugins: 'インストール済みプラグイン', + installedPlugins: 'インストール済み', pluginMarket: 'プラグインマーケット', mcpServers: 'MCPサーバー', addExtension: '拡張機能を追加', @@ -770,6 +770,9 @@ const jaJP = { toolsFound: '個のツール', unknownError: '不明なエラー', noToolsFound: 'ツールが見つかりません', + tabTools: 'ツール', + tabDocs: 'ドキュメント', + noReadme: 'ドキュメントがありません', parseResultFailed: 'テスト結果の解析に失敗しました', noResultReturned: 'テスト結果が返されませんでした', getTaskFailed: 'タスクステータスの取得に失敗しました', diff --git a/web/src/i18n/locales/ru-RU.ts b/web/src/i18n/locales/ru-RU.ts index 66421cbb..5909e26d 100644 --- a/web/src/i18n/locales/ru-RU.ts +++ b/web/src/i18n/locales/ru-RU.ts @@ -2,7 +2,7 @@ const ruRU = { sidebar: { home: 'Главная', extensions: 'Расширения', - installedPlugins: 'Установленные плагины', + installedPlugins: 'Установленные', pluginMarket: 'Маркетплейс', mcpServers: 'MCP-серверы', addExtension: 'Добавить расширение', @@ -775,6 +775,9 @@ const ruRU = { toolsFound: 'инструментов', unknownError: 'Неизвестная ошибка', noToolsFound: 'Инструменты не найдены', + tabTools: 'Инструменты', + tabDocs: 'Документация', + noReadme: 'Документация отсутствует', parseResultFailed: 'Не удалось разобрать результат теста', noResultReturned: 'Тест не вернул результат', getTaskFailed: 'Не удалось получить статус задачи', diff --git a/web/src/i18n/locales/th-TH.ts b/web/src/i18n/locales/th-TH.ts index 4e6e32f8..1d8425dd 100644 --- a/web/src/i18n/locales/th-TH.ts +++ b/web/src/i18n/locales/th-TH.ts @@ -2,7 +2,7 @@ const thTH = { sidebar: { home: 'หน้าแรก', extensions: 'ส่วนขยาย', - installedPlugins: 'ปลั๊กอินที่ติดตั้ง', + installedPlugins: 'ที่ติดตั้งแล้ว', pluginMarket: 'ตลาดปลั๊กอิน', mcpServers: 'เซิร์ฟเวอร์ MCP', addExtension: 'เพิ่มส่วนขยาย', @@ -755,6 +755,9 @@ const thTH = { toolsFound: 'เครื่องมือ', unknownError: 'ข้อผิดพลาดที่ไม่ทราบสาเหตุ', noToolsFound: 'ไม่พบเครื่องมือ', + tabTools: 'เครื่องมือ', + tabDocs: 'เอกสาร', + noReadme: 'ไม่มีเอกสาร', parseResultFailed: 'ไม่สามารถแยกวิเคราะห์ผลการทดสอบได้', noResultReturned: 'การทดสอบไม่ส่งผลลัพธ์กลับมา', getTaskFailed: 'ไม่สามารถดึงสถานะงานได้', diff --git a/web/src/i18n/locales/vi-VN.ts b/web/src/i18n/locales/vi-VN.ts index ffd49fa0..498f9001 100644 --- a/web/src/i18n/locales/vi-VN.ts +++ b/web/src/i18n/locales/vi-VN.ts @@ -2,7 +2,7 @@ const viVN = { sidebar: { home: 'Trang chủ', extensions: 'Tiện ích mở rộng', - installedPlugins: 'Plugin đã cài đặt', + installedPlugins: 'Đã cài đặt', pluginMarket: 'Chợ ứng dụng', mcpServers: 'Máy chủ MCP', addExtension: 'Thêm tiện ích mở rộng', @@ -769,6 +769,9 @@ const viVN = { toolsFound: 'công cụ', unknownError: 'Lỗi không xác định', noToolsFound: 'Không tìm thấy công cụ nào', + tabTools: 'Công cụ', + tabDocs: 'Tài liệu', + noReadme: 'Không có tài liệu', parseResultFailed: 'Phân tích kết quả kiểm tra thất bại', noResultReturned: 'Kiểm tra không trả về kết quả', getTaskFailed: 'Lấy trạng thái tác vụ thất bại', diff --git a/web/src/i18n/locales/zh-Hans.ts b/web/src/i18n/locales/zh-Hans.ts index 5c885d5d..3364fa15 100644 --- a/web/src/i18n/locales/zh-Hans.ts +++ b/web/src/i18n/locales/zh-Hans.ts @@ -2,7 +2,7 @@ const zhHans = { sidebar: { home: '首页', extensions: '扩展', - installedPlugins: '已安装扩展', + installedPlugins: '已安装', pluginMarket: '扩展市场', mcpServers: 'MCP 服务器', addExtension: '添加扩展', @@ -737,6 +737,9 @@ const zhHans = { toolsFound: '个工具', unknownError: '未知错误', noToolsFound: '未找到任何工具', + tabTools: '工具', + tabDocs: '文档', + noReadme: '暂无文档', parseResultFailed: '解析测试结果失败', noResultReturned: '测试未返回结果', getTaskFailed: '获取任务状态失败', diff --git a/web/src/i18n/locales/zh-Hant.ts b/web/src/i18n/locales/zh-Hant.ts index 855c1756..6d9b08b6 100644 --- a/web/src/i18n/locales/zh-Hant.ts +++ b/web/src/i18n/locales/zh-Hant.ts @@ -2,7 +2,7 @@ const zhHant = { sidebar: { home: '首頁', extensions: '擴展', - installedPlugins: '已安裝外掛', + installedPlugins: '已安裝', pluginMarket: '外掛市場', mcpServers: 'MCP 伺服器', addExtension: '添加擴展', @@ -736,6 +736,9 @@ const zhHant = { toolsFound: '個工具', unknownError: '未知錯誤', noToolsFound: '未找到任何工具', + tabTools: '工具', + tabDocs: '文件', + noReadme: '暫無文件', parseResultFailed: '解析測試結果失敗', noResultReturned: '測試未返回結果', getTaskFailed: '獲取任務狀態失敗',