Skip to content

Identified reproducible Hermes MCP issue while configuring n8n MCP server #37792

Description

@ThyFriendlyFox

Summary

hermes mcp add fails with 401 Unauthorized when adding an HTTP MCP server that uses header auth with Authorization: Bearer ${MCP_N8N_API_KEY}, while hermes mcp test <name> succeeds against the same URL and token.

Environment

  • Hermes Agent v0.15.1 (2026.5.29)
  • macOS
  • MCP server: n8n instance-level MCP at http://localhost:5678/mcp-server/http
  • Auth: hermes mcp add <name> --url ... --auth header
  • Token in ~/.hermes/.env as MCP_<SERVER>_API_KEY (JWT only, no Bearer prefix)

Steps to reproduce

  1. Set MCP_N8N_API_KEY=<valid n8n MCP JWT> in ~/.hermes/.env (from n8n Settings → MCP Access).

  2. Run:

    hermes mcp add n8n --url http://localhost:5678/mcp-server/http --auth header
  3. Confirm overwrite if prompted; confirm authentication is required.

  4. Observe connection failure during the discovery probe.

Expected behavior

The discovery probe succeeds (same as hermes mcp test n8n), tools are listed, and config is saved.

Actual behavior

✗ Failed to connect: Client error '401 Unauthorized' for url 'http://localhost:5678/mcp-server/http'

Meanwhile:

hermes mcp test n8n

Connected, tools discovered (e.g. 27 tools for n8n MCP).

Root cause

cmd_mcp_add in hermes_cli/mcp_config.py builds a fresh server_config with:

server_config["headers"] = {
    "Authorization": f"Bearer ${{{env_key}}}"
}

and calls _probe_single_server(name, server_config).

_probe_single_server passes that dict to _connect_server / _run_http without resolving ${ENV} placeholders.

Runtime MCP loading via _load_mcp_config() in tools/mcp_tool.py does call load_hermes_dotenv() and _interpolate_env_vars(). Config loaded for hermes mcp test is also resolved when read through load_config().

So the add probe sends the literal header:

Authorization: Bearer ${MCP_N8N_API_KEY}

which n8n correctly rejects with 401.

Manual verification with curl:

Authorization header HTTP result
Bearer ${MCP_N8N_API_KEY} (literal) 401
Bearer <jwt> 200
Bearer Bearer <jwt> (double prefix) 401

Proposed fix

In hermes_cli/mcp_config.py, resolve env placeholders (and load dotenv) before probing — mirror _load_mcp_config() behavior:

def _resolve_mcp_server_config(config: dict) -> dict:
    from hermes_cli.env_loader import load_hermes_dotenv
    from tools.mcp_tool import _interpolate_env_vars

    load_hermes_dotenv()
    return _interpolate_env_vars(config)


def _probe_single_server(name: str, config: dict, connect_timeout: float = 30):
    config = _resolve_mcp_server_config(config)
    ...

Optional hardening in cmd_mcp_add: strip a leading Bearer from pasted tokens before saving to MCP_*_API_KEY, since the header template already adds Bearer .

Related UX / docs issues (same area)

Issue Notes
Wrong config key hermes config set mcp.servers.<name>... writes under mcp.servers; runtime reads mcp_servers (top-level). hermes mcp list shows empty until corrected.
hermes config unset Not a valid subcommand; CLI reports invalid choice for unset.
Double Bearer If MCP_*_API_KEY is Bearer <jwt> and header is Bearer ${MCP_*_API_KEY}, n8n receives Bearer Bearer ... → 401.

Workaround (until fixed)

  1. Do not re-run hermes mcp add if hermes mcp test <name> already passes; answer N when asked to save config after a failed add.

  2. Use top-level mcp_servers in ~/.hermes/config.yaml (not mcp.servers):

    mcp_servers:
      n8n:
        url: http://localhost:5678/mcp-server/http
        headers:
          Authorization: Bearer ${MCP_N8N_API_KEY}
        enabled: true
  3. In ~/.hermes/.env, store only the JWT (no Bearer prefix):

    MCP_N8N_API_KEY=eyJ...
  4. n8n MCP expects Authorization: Bearer <token> (see n8n instance-level MCP connection docs).

Local patch note (not upstream)

A temporary fix was applied locally to ~/.hermes/hermes-agent/hermes_cli/mcp_config.py (_resolve_mcp_server_config, _strip_bearer_prefix). This is overwritten on hermes update or reinstall. User config in ~/.hermes/config.yaml and ~/.hermes/.env persists across updates.

References

  • Hermes MCP config key: mcp_servers in ~/.hermes/config.yaml (hermes_cli/mcp_config.py, tools/mcp_tool.py)
  • n8n MCP HTTP endpoint: /mcp-server/http
  • Cursor MCP example (separate client): n8n/cursor-mcp.env.example in this repo

Submitted with love from Team Reagent

Team Reagent

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardtool/mcpMCP client and OAuthtype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions