Tim O'Farrellandopenhands 463deff24a feat: validate MCP server connectivity before saving (#785) (#816)
* 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 &#39; and slashes as &#x2F;.  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
- &#39; / &#x2F; entities decoded in the error field
- numeric (&lt;) and hex (&#x73;) 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 (\' -> &#39;, / -> &#x2F;).  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>
2026-05-27 12:56:25 -06:00
2026-05-20 14:26:36 +00:00
2026-04-24 17:33:22 -04:00

agent-canvas

Warning

This project is in alpha phase. It may be vibecoded, untested, or out of date. Learn more.

OpenHands is a platform for orchestrating coding agents across different environments. You can:

  • ⌨️ prompt agents manually
  • 🕐 run agents on a schedule
  • ⚡ trigger agents automatically — e.g. from Slack, GitHub, or Datadog.

Agents can run anywhere:

  • 🧑‍💻 on your laptop
  • 🖥️ on a remote virtual machine
  • ☁️ in our hosted cloud
  • 🏢 or inside your company’s infrastructure

The same Agent Canvas frontend can swap between each of these environments, so you can see everything in one place.

OpenHands works with any agent harness (e.g. Claude Code, Codex) or connect directly to an LLM (e.g. Anthropic, OpenAI, Gemini, Mistral, Minimax, Kimi).

If you have questions or feedback, please open a GitHub issue or join the #proj-agent-canvas channel in Slack

Screenshot 2026-05-11 at 10 13 19 AM

Quickstart

You can install OpenHands to run agents on any machine: on your laptop, on a dedicated computer like a Mac Mini, or on a server in the cloud.

The most powerful way to run OpenHands is on a server in the cloud. This allows your agents to continue running even when your laptop is shut, and makes it easier to trigger your agents through third-party services like Slack, GitHub, and Datadog. See SELF_HOSTING.md for details, especially with respect to security hardening.

Notably, you can run the backend in multiple different environments, and switch between them from the same Agent Canvas frontend. E.g. you can share an Agent Server with your team for agents doing code review and dependency updates, then have your personal agents running on your laptop.

Warning

This runs the agent-server directly on the machine you're installing on — the agent will have full access to your filesystem!

Option 1: Docker

docker pull ghcr.io/openhands/agent-canvas:1.0.0-alpha.6
export PROJECTS_PATH=~/projects  # directory containing your project folders
docker run -it --rm \
  -p 8000:8000 \
  -v ~/.openhands:/home/openhands/.openhands \
  -v ${PROJECTS_PATH}:/projects \
  ghcr.io/openhands/agent-canvas:1.0.0-alpha.6

The agent will be able to access any project under PROJECTS_PATH.

Option 2: NPM

Prerequisites: Node.js 22.12.x or later, uv

npm install -g @openhands/agent-canvas
export PROJECTS_PATH=~/projects  # directory containing your project folders
agent-canvas

Option 3: From Source

Prerequisites: Node.js 22.12.x or later, npm, uv (for running the agent server via uvx)

git clone https://github.com/OpenHands/agent-canvas.git
cd agent-canvas
npm install
npm run dev

Access the UI at http://localhost:8000. You can add additional backends directly from the UI.

Architecture

Agent Canvas is powered by the OpenHands Agent Server, a REST API for running multiple agents on a single machine. Each Agent Server runs on a single host/port; the Agent Canvas can connect to multiple Agent Servers and easily flip between them.

You can run an Agent Server anywhere:

  • Directly on your laptop (be careful!)
  • On a dedicated machine like a Mac Mini
  • On a virtual machine in the cloud
  • Inside OpenHands Cloud (our commercial offering)

The Agent Server is often paired with an Automation Server, which lets you set up agents that run on a schedule or in response to events.

image

More documentation

For contributor and developer workflows, including frontend-only mode, mock mode, environment variables, and build/test commands, see DEVELOPMENT.md.

S
Languages
TypeScript 93.7%
JavaScript 4.7%
Python 0.9%
Shell 0.3%
CSS 0.2%
Other 0.1%