mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-07 16:19:05 +08:00
* feat: pre-flight MCP test before save (#785) Validate MCP server connectivity via POST /api/mcp/test before saving in both the marketplace install modal and the custom-server editor. - Add McpService.testServer() using MCPClient from @openhands/typescript-client - Add useTestMcpServer() useMutation hook - InstallServerModal: test before addMcpServer; show inline error on failure, keep modal open (onClose not called); button shows Verifying… then Saving… - CustomServerEditor: same pre-flight pattern before add/update; also exposes a standalone Test Connection button via MCPServerForm's new onTest prop - MCPServerForm: add onTest/isTestPending/testMessage props; extract buildConfig helper; add handleTestClick using formRef; render Test Connection button and testMessage inline above action buttons - Add i18n keys: MCP$TEST_BUTTON, MCP$VERIFYING, MCP$TEST_SUCCESS, MCP$TEST_ERROR_TIMEOUT, MCP$TES MCP$TEST_ERROR_TIMEOUT, MCP$TES MCP$TEST_ERROR_TIMEOUT, MCP$TES MCP$TEST_ERROR_TIMEOUT, MCP$TES MCP$TEST_ERROR_TIMEOUT, MCP$TES + keeps modal open, success path, Verifying label) Closes #785 Co-authored-by: openhands <openhands@all-hands.dev> * test: stub McpService.testServer in tests that save through the pre-flight Three test suites click a submit button whose handler now runs the pre-flight connectivity test before calling saveSettings. None of them mocked McpService.testServer, so the mutation errored out before reaching the save step. Add vi.spyOn(McpService, 'testServer').mockResolvedValue({ ok: true, tools: [] }) to the beforeEach of each affected suite so the test-then-save flow resolves as expected and the existing assertions remain valid. Co-authored-by: openhands <openhands@all-hands.dev> * fix: decode HTML entities in MCP test-server error messages The Python backend passes error strings through html.escape(), so apostrophes arrive as ' and slashes as /. Add a one-liner decodeHtmlEntities() helper in McpService that uses a temporary <textarea> to let the browser's own HTML parser decode the string before it reaches any UI component. Decoding happens once, at the API boundary, so every consumer (InstallServerModal, CustomServerEditor, etc.) automatically gets clean text without needing its own unescaping logic. Add a focused McpService unit test (4 cases) that mocks MCPClient via vi.hoisted + vi.mock to exercise the real decoding path: - success responses pass through unchanged - ' / / entities decoded in the error field - numeric (<) and hex (s) entities decoded - stdio config mapped to the correct MCPServerSpec shape Co-authored-by: openhands <openhands@all-hands.dev> * fix: render MCP error strings as plain text with newlines Two bugs in the error message display path: 1. HTML-entity encoding: react-i18next escapes interpolated values by default (\' -> ', / -> /). Fix by using the no-escape prefix {{-error}} in the MCP$TEST_ERROR_UNKNOWN translation string so the raw error text is interpolated verbatim. 2. Newlines ignored: the \n in multi-line Python tracebacks was swallowed by the browser. Fix by adding whitespace-pre-wrap to the <p> elements in install-server-modal (globalError) and mcp-server-form (testMessage) so \n renders as a visual line break. Also revert the previous decodeHtmlEntities approach from the service layer — the backend does not HTML-escape thlayer — the backend does nwas introduced by i18next, not the server. Update McpService telayer — the backend does not HTML-escape thlayer — the backend dngs in the translation layer instead. Co-authored-by: openhands <openhands@all-hands.dev> --------- Co-authored-by: openhands <openhands@all-hands.dev>