mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-14 08:26:07 +00:00
feat(mcp): friendly UI message when stdio MCP refused by Box state
Previously the MCP detail dialog dumped the raw RuntimeError text from
``_init_stdio_python_server`` — English-only, prefixed with "Failed
after 4 attempts", and exposing internal config names. The retry
wrapper also kept retrying a refusal that is deterministically going
to fail again, polluting logs.
Replace the raw text with a structured signal:
- New ``MCPSessionErrorPhase.BOX_UNAVAILABLE`` enum value. The stdio
refusal path sets it before raising and uses a short opaque
discriminator (``box_disabled_in_config`` / ``box_unavailable``) as
the message body — never user-facing
- ``_lifecycle_loop_with_retry`` short-circuits on
``BOX_UNAVAILABLE``: surfaces the error immediately, no retries,
no "Failed after N attempts" prefix. Silences the warning storm
seen during smoke-testing
- ``MCPServerRuntimeInfo`` (TS type) now declares ``error_phase``,
``retry_count``, ``box_session_id``, ``box_enabled`` to match what
the backend already returns in get_runtime_info_dict()
- Both MCP detail forms (``mcp/components/mcp-form/MCPForm.tsx`` and
``plugins/mcp-server/mcp-form/MCPFormDialog.tsx``) detect
``error_phase === 'box_unavailable'`` and render a two-line
localized notice: state line ("Box disabled / unreachable") plus
remediation line ("enable Box or switch to http/sse")
- 8 locale files (en/zh-Hans/zh-Hant/ja/ru/vi/th/es) get
``mcp.boxDisabledStdioRefused``, ``mcp.boxUnavailableStdioRefused``,
``mcp.boxStdioRefusedSuggestion``
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,32 @@ function StatusDisplay({
|
||||
);
|
||||
}
|
||||
|
||||
// Stdio MCP refused because Box is disabled / unreachable. The backend
|
||||
// marks the phase so we can show a localized, actionable message instead
|
||||
// of the raw "box_disabled_in_config" / "box_unavailable" marker.
|
||||
if (runtimeInfo.error_phase === 'box_unavailable') {
|
||||
const isDisabledByConfig =
|
||||
runtimeInfo.error_message === 'box_disabled_in_config';
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2 text-red-600">
|
||||
<XCircle className="size-5" />
|
||||
<span className="font-medium">{t('mcp.connectionFailed')}</span>
|
||||
</div>
|
||||
<div className="pl-7 text-sm text-red-500 space-y-0.5">
|
||||
<div>
|
||||
{isDisabledByConfig
|
||||
? t('mcp.boxDisabledStdioRefused')
|
||||
: t('mcp.boxUnavailableStdioRefused')}
|
||||
</div>
|
||||
<div className="text-muted-foreground">
|
||||
{t('mcp.boxStdioRefusedSuggestion')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2 text-red-600">
|
||||
|
||||
@@ -77,6 +77,32 @@ function StatusDisplay({
|
||||
);
|
||||
}
|
||||
|
||||
// Stdio MCP refused because Box is disabled / unreachable. The backend
|
||||
// marks the phase so we can show a localized, actionable message instead
|
||||
// of the raw "box_disabled_in_config" / "box_unavailable" marker.
|
||||
if (runtimeInfo.error_phase === 'box_unavailable') {
|
||||
const isDisabledByConfig =
|
||||
runtimeInfo.error_message === 'box_disabled_in_config';
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2 text-red-600">
|
||||
<XCircle className="w-5 h-5" />
|
||||
<span className="font-medium">{t('mcp.connectionFailed')}</span>
|
||||
</div>
|
||||
<div className="text-sm text-red-500 pl-7 space-y-0.5">
|
||||
<div>
|
||||
{isDisabledByConfig
|
||||
? t('mcp.boxDisabledStdioRefused')
|
||||
: t('mcp.boxUnavailableStdioRefused')}
|
||||
</div>
|
||||
<div className="text-muted-foreground">
|
||||
{t('mcp.boxStdioRefusedSuggestion')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 连接失败
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
|
||||
@@ -529,8 +529,18 @@ export enum MCPSessionStatus {
|
||||
export interface MCPServerRuntimeInfo {
|
||||
status: MCPSessionStatus;
|
||||
error_message?: string;
|
||||
/** Stage at which the session failed. Frontends key off this to render
|
||||
* a localized actionable message instead of the raw ``error_message``.
|
||||
* Notable values: ``box_unavailable`` (stdio MCP refused because Box is
|
||||
* disabled / unreachable). See ``MCPSessionErrorPhase`` (backend). */
|
||||
error_phase?: string;
|
||||
retry_count?: number;
|
||||
tool_count: number;
|
||||
tools: MCPTool[];
|
||||
/** Optional ``box_session_id`` / ``box_enabled`` set when this stdio
|
||||
* server runs inside Box. Absent when Box is unavailable. */
|
||||
box_session_id?: string;
|
||||
box_enabled?: boolean;
|
||||
}
|
||||
|
||||
export type MCPServer =
|
||||
|
||||
Reference in New Issue
Block a user