[Bug]: Scope MCP server health by backend and connection revision
Bug Description
MCP health is stored in one global map keyed only by a server's non-secret structure. The active backend and connection revision are absent from both the key and the subscription. Two backends with the same MCP server name, URL, and auth strategy therefore share one verdict even when their credentials or network reachability differ. A delayed probe from backend A can resolve into the entry displayed on backend B.
This is a realistic multi-backend workflow: the same GitHub, Slack, or other catalog MCP definition is commonly installed against multiple agent servers, while credentials and reachability remain backend-specific.
Steps to Reproduce
Run Agent Canvas with npm run dev and register two local backends.
- Configure the same MCP server structure on backends A and B, but use different credentials or network reachability.
- Probe the server on A and record its health result.
- Switch to B and inspect the same server's health before probing it there.
- Start a slow probe on A, switch to B before it resolves, and observe where the result lands.
- Edit the active backend's host or API key and inspect whether the existing health verdict resets.
The collision and stale-result paths were independently reproduced in the issue discussion and are covered by PR #16992.
Actual Behavior
Backend B can display backend A's healthy or credential-failure state. A probe or mutation callback begun under A can update the globally keyed entry later read by B, and connection-revision changes do not return health to unchecked.
No valid screenshot is currently attached. The image in PR #16992 points to an unrelated historical asset and must not be used as evidence for this issue. Keep the issue below ready-for-dev until correct evidence is supplied.
Expected Behavior
Health identity includes backend ID, connection revision, and non-secret server structure. Every async operation applies its result to the scope captured when that operation began.
Acceptance Criteria
- MCP health identity includes backend ID, connection revision, and non-secret server structure; secret values never enter keys or logs.
- Probes, OAuth, seeding, updates, and deletion use the backend and revision captured when the operation starts.
- A connection-revision change returns health to unchecked.
- Existing check-ID protection prevents older results from overwriting newer results within one scoped key.
- Tests cover identical servers on two backends, backend switches during probes and mutation callbacks, revision rotation, and stale-result rejection.
Additional Context
Do not read a live scopeRef.current from an async success callback; capture scope in mutation variables or context at invocation time, as noted in the maintainer review of PR #16992. Existing #16843 and #16893 own plugin and skill query scoping respectively.
Found during a read-only whole-codebase audit of commit 11d6b4a56eb4b7a190e0cb5b2c96e524db14afc7 requested by @enyst.
Source: OpenHands/OpenHands