github →

New request

#1977: tracking: profile-keyed MCP server registry — agent-side follow-up to #1968

We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.

Issue
holdupstream-changetracking

Summary

Layer-2 follow-up to #1968. PR #1976 fixed the headline symptom (single non-default profile per WebUI process now loads its MCP servers correctly), but a deeper issue remains in hermes-agent that this issue tracks until the upstream change lands.

What's still broken

Concurrent multi-profile use of MCP servers within the same WebUI process. Once profile A registers a server named postgres, profile B's discovery sees 'postgres' in _servers and skips it — even if B's postgres config points at a different binary, env, or DB.

# tools/mcp_tool.py:1607 (hermes-agent)
_servers: Dict[str, MCPServerTask] = {}

# tools/mcp_tool.py:3065-3068 (hermes-agent)
new_servers = {
    k: v
    for k, v in servers.items()
    if k not in _servers and _parse_boolish(v.get("enabled", True), default=True)
}

Why this can't be fixed in WebUI

_servers is a process-global dict in the agent's tools/mcp_tool.py. The WebUI calls discover_mcp_tools() and gets back tools registered under that global dict — there's no API to scope discovery by profile or to re-key existing entries.

What the upstream fix looks like

Two changes in hermes-agent:

  1. Re-key _servers by (profile_home, name)Dict[Tuple[str, str], MCPServerTask] instead of Dict[str, MCPServerTask]. Existing single-profile callers see no behavior change because their keys all share the same profile_home.

  2. Accept an explicit profile_home arg in discover_mcp_tools() — defaulting to get_hermes_home() so existing callers work unchanged. The WebUI then passes the session's profile home explicitly: discover_mcp_tools(profile_home=_profile_home). This also fixes a thread-safety hazard documented in #195 — discovery wouldn't depend on a process-global env var read at exactly the right moment.

Status

  • Layer 1 (this repo, #1976): ✅ Shipped — relocates the discovery call past the per-session HERMES_HOME mutation. Fixes single non-default profile use.
  • Layer 2 (hermes-agent): ⏳ Needs upstream issue + PR. Tracking here so we don't forget.

Until layer 2 lands, this issue stays hold + upstream-change. When the agent-side change ships, the WebUI side can then optionally pass profile_home=_profile_home explicitly (small follow-up here) to remove the env-var indirection entirely.

Related

  • #1968 — original bug report (closed by #1976)
  • #1976 — layer-1 PR (this repo)
  • #195 — os.environ race between concurrent agent sessions (broader issue, same root substrate)
  • #497, #498, #1925 — other architecture issues that point at the same "WebUI shouldn't have process-global agent state" theme
Assessmentadvisory
chore easy70% confidence

Tracking an upstream agent-side concurrency fix is a dependency coordination task with no direct WebUI code changes required until hermes-agent lands the re-key.

Likely files
  • api/routes.py
  • api/mcp_bridge.py
  • static/js/mcp.js
Create the request

This opens a fresh agent run and a draft PR for issue #1977.

Cancel