feat(mcp-web): block stdio MCP creation at the form when Box is unavailable

When Box is disabled in config (``box.enabled = false``) or unreachable,
saving a new MCP server in stdio mode produced one that could never
start — the user would only learn that from the runtime error on the
detail page. Stop the user before they save instead.

Both MCP forms (the page-level ``MCPForm.tsx`` and the older dialog
``MCPFormDialog.tsx``) now:

- Disable the ``stdio`` option in the mode select when Box is
  unavailable, with a small "(requires Box)" suffix so the reason is
  obvious. Existing stdio configs still display their current value
- Show ``BoxUnavailableNotice`` inline under the mode select when the
  currently-selected mode is stdio and Box is unavailable, so editing
  a stale stdio config makes the cause visible
- Disable the Save / Submit button while stdio is selected under that
  condition. ``MCPForm`` exposes a new ``onSaveBlockedChange`` prop
  so the parent ``MCPDetailContent`` can disable both its Submit and
  Save buttons. ``MCPFormDialog`` disables its Save button locally
- Refuse the submit handler too (Enter-key path) with a toast carrying
  the same i18n message

i18n: ``mcp.boxRequired`` (short tag in the disabled option) and
``mcp.stdioBlockedByBoxToast`` added to all 8 locales.

Backend runtime gate (``_init_stdio_python_server`` refusal +
``BOX_UNAVAILABLE`` error_phase + retry short-circuit) stays in place
as the last line of defence for API bypass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Junyan Qin
2026-05-20 18:03:47 +08:00
parent 216b1b9f03
commit aa8d53dde6
11 changed files with 93 additions and 4 deletions

View File

@@ -744,6 +744,9 @@ const enUS = {
'Stdio MCP servers require the Box sandbox, which is currently unreachable.',
boxStdioRefusedSuggestion:
'Enable Box (box.enabled = true) and ensure the runtime is healthy, or switch this server to http/sse mode.',
boxRequired: 'requires Box',
stdioBlockedByBoxToast:
'Stdio MCP cannot be saved while the Box sandbox is disabled or unreachable. Enable Box or pick http/sse.',
toolsFound: 'tools',
unknownError: 'Unknown error',
noToolsFound: 'No tools found',

View File

@@ -758,6 +758,9 @@ const esES = {
'Los servidores MCP en modo stdio requieren el sandbox de Box, actualmente no accesible.',
boxStdioRefusedSuggestion:
'Active Box (box.enabled = true) y asegúrese de que el runtime está conectado, o cambie este servidor a modo http/sse.',
boxRequired: 'requiere Box',
stdioBlockedByBoxToast:
'No se puede guardar el MCP en modo stdio mientras el sandbox de Box está desactivado o no disponible. Active Box o seleccione modo http/sse.',
toolsFound: 'herramientas',
unknownError: 'Error desconocido',
noToolsFound: 'No se encontraron herramientas',

View File

@@ -749,6 +749,9 @@ const jaJP = {
'Stdio モードの MCP サーバーは Box サンドボックスを必要としますが、現在接続できません。',
boxStdioRefusedSuggestion:
'Box を有効化box.enabled = trueしてランタイムの接続を確認するか、このサーバーを http/sse モードに切り替えてください。',
boxRequired: 'Box が必要',
stdioBlockedByBoxToast:
'Box サンドボックスが無効または利用できないため、stdio モードの MCP は保存できません。Box を有効化するか、http/sse モードに切り替えてください。',
toolsFound: '個のツール',
unknownError: '不明なエラー',
noToolsFound: 'ツールが見つかりません',

View File

@@ -754,6 +754,9 @@ const ruRU = {
'MCP-серверы в режиме stdio требуют песочницу Box, которая сейчас недоступна.',
boxStdioRefusedSuggestion:
'Включите Box (box.enabled = true) и убедитесь, что среда работает, либо переключите этот сервер в режим http/sse.',
boxRequired: 'требуется Box',
stdioBlockedByBoxToast:
'Сохранить MCP в режиме stdio нельзя: песочница Box отключена или недоступна. Включите Box либо выберите режим http/sse.',
toolsFound: 'инструментов',
unknownError: 'Неизвестная ошибка',
noToolsFound: 'Инструменты не найдены',

View File

@@ -734,6 +734,9 @@ const thTH = {
'MCP server แบบ stdio ต้องใช้ Sandbox Box ซึ่งขณะนี้เชื่อมต่อไม่ได้',
boxStdioRefusedSuggestion:
'กรุณาเปิดใช้งาน Box (box.enabled = true) และตรวจสอบว่ารันไทม์ทำงานปกติ หรือเปลี่ยน MCP server เป็นโหมด http/sse',
boxRequired: 'ต้องใช้ Box',
stdioBlockedByBoxToast:
'ไม่สามารถบันทึก MCP โหมด stdio เนื่องจาก Sandbox Box ถูกปิดใช้งานหรือไม่พร้อมใช้งาน กรุณาเปิดใช้งาน Box หรือเลือกโหมด http/sse',
toolsFound: 'เครื่องมือ',
unknownError: 'ข้อผิดพลาดที่ไม่ทราบสาเหตุ',
noToolsFound: 'ไม่พบเครื่องมือ',

View File

@@ -748,6 +748,9 @@ const viVN = {
'MCP server ở chế độ stdio cần Sandbox Box, hiện không thể kết nối.',
boxStdioRefusedSuggestion:
'Hãy bật Box (box.enabled = true) và đảm bảo runtime hoạt động, hoặc chuyển server này sang chế độ http/sse.',
boxRequired: 'cần Box',
stdioBlockedByBoxToast:
'Không thể lưu MCP ở chế độ stdio khi Sandbox Box bị tắt hoặc không khả dụng. Hãy bật Box hoặc chọn chế độ http/sse.',
toolsFound: 'công cụ',
unknownError: 'Lỗi không xác định',
noToolsFound: 'Không tìm thấy công cụ nào',

View File

@@ -716,6 +716,9 @@ const zhHans = {
'Stdio 模式的 MCP 服务器依赖 Box 沙箱,目前无法连接。',
boxStdioRefusedSuggestion:
'请启用 Boxbox.enabled = true并确认运行时连接正常或将此服务器切换到 http/sse 模式。',
boxRequired: '需要 Box',
stdioBlockedByBoxToast:
'Box 沙箱已禁用或不可用,无法保存 stdio 模式的 MCP。请启用 Box 或改为 http/sse 模式。',
toolsFound: '个工具',
unknownError: '未知错误',
noToolsFound: '未找到任何工具',

View File

@@ -715,6 +715,9 @@ const zhHant = {
'Stdio 模式的 MCP 伺服器依賴 Box 沙箱,目前無法連線。',
boxStdioRefusedSuggestion:
'請啟用 Boxbox.enabled = true並確認執行時連線正常或將此伺服器切換到 http/sse 模式。',
boxRequired: '需要 Box',
stdioBlockedByBoxToast:
'Box 沙箱已停用或無法使用,無法儲存 stdio 模式的 MCP。請啟用 Box 或改為 http/sse 模式。',
toolsFound: '個工具',
unknownError: '未知錯誤',
noToolsFound: '未找到任何工具',