Skip to content

fix(mcp): fetch the server list from /api/mcp/servers - #735

Open
r0h1tb wants to merge 1 commit into
outsourc-e:mainfrom
r0h1tb:fix/mcp-list-endpoint
Open

fix(mcp): fetch the server list from /api/mcp/servers#735
r0h1tb wants to merge 1 commit into
outsourc-e:mainfrom
r0h1tb:fix/mcp-list-endpoint

Conversation

@r0h1tb

@r0h1tb r0h1tb commented Aug 1, 2026

Copy link
Copy Markdown

Fixes #725

Problem

The workspace requests GET /api/mcp from the gateway, which answers:

{"detail":"No such API endpoint: /api/mcp"}

The capability probe reads that 404 as "no MCP support", so the MCP screen shows "Not available on this backend. Connect to a Hermes Agent gateway to unlock MCP Servers" — even when MCP is configured and working. As the reporter noted, sessions, skills, memory, config and jobs all load; only MCP fails.

The list is served at /api/mcp/servers.

Two call sites, not one

  • src/server/gateway-capabilities.tsprobeMcp() requested /api/mcp on both the dashboard and the gateway. This is what gates the screen.
  • src/routes/api/mcp.ts — the GET handler fetched the list from the same wrong path.

Fixing only the probe would have unlocked the screen and then failed to load any servers, so both are changed.

Fix

Both now go through fetchMcpList() in the new src/server/mcp-upstream.ts, which requests /api/mcp/servers and falls back to /api/mcp on 404 only — so gateways still serving the list at the old path keep working, while a 401 or 5xx is returned as-is instead of being masked behind a second request.

The POST /api/mcp create path is a different endpoint and is deliberately untouched.

Tests

marks MCP available when the dashboard only serves /api/mcp/servers reproduces the bug: it fails on the current code with expected false to be true, and passes with this change.

Three existing mocks in gateway-capabilities.test.ts needed updating. They 404 /api/mcp but have a catch-all returning 200 {ok:true}, so the new request would have hit the catch-all and flipped those assertions from false to true. They now 404 both paths, preserving the original intent.

src/server/__tests__/mcp-upstream.test.ts covers path preference, the 404 fallback, both paths missing, no-retry on 401/403/500/502, and init forwarding.

Verification

Full suite before this change: 13 failed | 105 passed (118 files), 38 failed | 704 passed (742 tests).
After: 13 failed | 106 passed (119 files), 38 failed | 713 passed (751 tests).

Same 38 pre-existing failures (e2e specs needing a browser, the mcp store tests, i18n); the +9 passing are the tests added here. No regressions.

The workspace requested GET /api/mcp from the gateway, which answers
{"detail":"No such API endpoint: /api/mcp"}. The capability probe read that
404 as "no MCP support", so the MCP screen showed "Not available on this
backend" even when MCP was configured and working — sessions, skills, memory,
config and jobs all loaded fine, only MCP failed.

The list is served at /api/mcp/servers.

Two call sites had the wrong path, not one: probeMcp() in gateway-capabilities
gated the screen, and the GET handler in routes/api/mcp.ts fetched the list.
Fixing only the probe would have unlocked the screen and then failed to load
any servers.

Both now go through fetchMcpList() in server/mcp-upstream.ts, which requests
/api/mcp/servers and falls back to /api/mcp on 404 so gateways still serving
the list there keep working. Only 404 retries — 401 and 5xx are returned as-is
rather than masked behind a second request.

The POST create path is a different endpoint and is left alone.

Existing gateway-capabilities tests 404'd /api/mcp but had a catch-all
returning 200, so the new request would have hit it and flipped those
assertions; their mocks now 404 both paths. Adds a regression test for a
dashboard that serves only /api/mcp/servers (fails without this change) and
unit tests for the fallback.

Fixes outsourc-e#725
@r0h1tb
r0h1tb requested a review from outsourc-e as a code owner August 1, 2026 09:10
@r0h1tb

r0h1tb commented Aug 1, 2026

Copy link
Copy Markdown
Author

Notes to make this quick to review.

The whole behavioural change is two paths. probeMcp() in gateway-capabilities.ts and the GET handler in routes/api/mcp.ts both requested /api/mcp; both now go through fetchMcpList(), which asks for /api/mcp/servers first. Everything else in the diff is tests.

Verify in ~60 seconds — the regression test fails on main and passes here:

npx vitest run src/server/__tests__/gateway-capabilities.test.ts -t "only serves"
# => 1 passed

git stash && npx vitest run src/server/__tests__/gateway-capabilities.test.ts -t "only serves"
# => AssertionError: expected false to be true
git stash pop

One thing worth a second look, since it's the only non-obvious edit: I changed three existing mocks in gateway-capabilities.test.ts. They 404 /api/mcp, but the mock has a catch-all returning 200 {ok:true} — so the new /api/mcp/servers request would have fallen through to it and flipped those assertions from false to true. They now 404 both paths, which keeps the original intent (dashboard/gateway without MCP ⇒ capability=false). Without that, the suite would have gone green while quietly testing the opposite of what it says.

Backwards compatible. /api/mcp is still tried, but only on a 404 — a 401 or 5xx returns as-is rather than being masked by a retry.

Deliberately out of scope: POST /api/mcp (create) is a different endpoint with no evidence it's affected, so it's untouched.

Full suite is unchanged at 38 pre-existing failures (browser-dependent e2e, mcp store tests, i18n); passing goes 704 → 713, which is exactly the 9 tests added here.

Happy to split the shared helper out or inline it at both call sites if you'd prefer a smaller diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP page shows "Not available" — workspace calls /api/mcp instead of /api/mcp/servers

1 participant