feat(mcp): add deapi catalog entry + wire Authorization header for http api_key MCPs - #59586
feat(mcp): add deapi catalog entry + wire Authorization header for http api_key MCPs#59586adampachowicz wants to merge 5 commits into
Conversation
…ey auth
Installing an http-transport catalog MCP that authenticates with an API
key saves the key to ~/.hermes/.env, but the generated
mcp_servers.<name> block contained only a url - no Authorization
header. The saved key was never referenced, so the server was contacted
unauthenticated and every tool call failed (401) with no obvious cause.
The manual path (hermes mcp add) already wires this correctly
(hermes_cli/mcp_config.py): headers: {Authorization: 'Bearer ${VAR}'},
resolved by the client's existing env interpolation at connect time.
Mirror it in _build_server_config(): prefer an explicit auth.env_var,
else the first declared env name; guarded so an api_key entry with no
declared env var writes no unresolvable placeholder.
Revives NousResearch#51100 (closed unreviewed by its author to keep the queue
clean) - same diagnosis and fix, now with a catalog entry that needs it.
Co-authored-by: briandevans <252620095+briandevans@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remote Streamable-HTTP MCP at mcp.deapi.ai (39 tools: image gen, TTS, transcription incl. YouTube/X/Twitch URLs, OCR, video, music, embeddings). auth: api_key (DEAPI_API_KEY -> Authorization Bearer via the catalog header wiring). Default tool set curated to the 22 actual capabilities + account utilities; the 17 *_price estimators stay opt-in via the install-time checklist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
data-files needs one target per catalog entry (a shared glob would collapse manifests into one colliding path); without it the deapi manifest exists in the source checkout but vanishes from wheel/pip installs, leaving 'hermes mcp catalog' without the entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'hermes mcp add deapi' with no --url/--command/--preset previously died with 'Must specify --url ...' even when <name> is a shipped catalog entry. Fall back to get_entry()/install_entry() so 'mcp add deapi' and 'mcp install deapi' are equivalent for catalog MCPs; explicit transport flags still always mean a custom server and never consult the catalog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Optional http-only map written verbatim into the mcp_servers.<name>
block; ${VAR} placeholders resolve via the MCP client's existing env
interpolation at connect time, never at install time. Explicit headers
override the automatic api_key Authorization Bearer header, covering
X-API-Key style schemes, non-Bearer prefixes and multi-header servers.
Validated: http-only, string-to-string.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Pushed three follow-up commits addressing packaging and UX gaps found in review of our own PR:
Full affected-suite run: |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the catalog/manual authentication asymmetry. The core bug is present on current main: hermes_cli/mcp_catalog.py:717-720 saves api_key credentials, while _build_server_config() at hermes_cli/mcp_catalog.py:489-493 emits only url for HTTP entries unless auth is OAuth. The runtime does forward configured headers (tools/mcp_tool.py:2507-2514), and the manual path already persists a Bearer template (hermes_cli/mcp_config.py:485-507).
Problems
hermes_cli/mcp_catalog.py:83adds the generictransport.headersschema, but the submittedoptional-mcps/deapi/manifest.yamldoes not consume it. The verified fix only needs the automatic Bearer template. This broadens the catalog manifest surface without a concrete entry requiring it.
Suggested changes
- Keep the HTTP
api_keyBearer-header fix and deapi manifest, but split outtransport.headersuntil a reviewed catalog entry needs a non-Bearer or multi-header scheme.
This is an automated hermes-sweeper review.
| # http only. Extra request headers written verbatim into the | ||
| # mcp_servers.<name> block; ${VAR} placeholders are resolved by the MCP | ||
| # client's existing env interpolation at connect time, never at install | ||
| # time. Overrides the automatic Authorization header derived from |
There was a problem hiding this comment.
This generic manifest-schema extension is not consumed by the included deapi entry, which uses the automatic Bearer path. Please split it into a focused change when a reviewed catalog MCP actually requires custom/non-Bearer headers.
What does this PR do?
Two tightly-coupled commits:
1.
fix(mcp): wire the Authorization header for http-transport catalog MCPs usingauth.type: api_key. Installing such an MCP (hermes mcp install <name>) prompts for the key and saves it to~/.hermes/.env, but_build_server_config()emitted onlyurl— noAuthorizationheader — so the saved key was never sent and every tool call failed 401 with no obvious cause. The manual path (hermes mcp add,hermes_cli/mcp_config.py) already writesheaders: {Authorization: "Bearer ${VAR}"}resolved by the client's existing env interpolation; this mirrors it in the catalog installer (preferauth.env_var, else first declared env name, guarded against empty).This revives #51100 — same diagnosis and fix by @briandevans (credited via Co-authored-by), which was triaged
type/bug P2but closed by its author after ~13 days without review. The difference here: this PR ships the first catalog entry that actually exercises the code path.2.
feat(mcp): add thedeapicatalog entry — deAPI's hosted remote MCP (Streamable HTTP,mcp.deapi.ai): image generation (FLUX.2 Klein etc.), TTS, transcription (incl. YouTube/X/Twitch URLs), OCR, video, music, embeddings. 39 tools total;tools.default_enabledcurates the 22 real capabilities + account utilities, leaving the 17*_priceestimators opt-in via the install-time checklist.auth: api_key(free $5 signup credit, no card) — the server also advertises OAuth but its AS lacks Dynamic Client Registration today, so api_key is the reliable path (noted in a manifest comment; easy one-commit switch toauth: oauthonce DCR lands).Related Issue
Revives #51100. No existing issue for the deapi entry (searched open/closed issues + PRs for "deapi").
Type of Change
Changes Made
hermes_cli/mcp_catalog.py—_build_server_config(): emitheaders: {Authorization: "Bearer ${ENV}"}for http + api_key entriestests/hermes_cli/test_mcp_catalog.py—test_install_http_api_key_writes_authorization_header(asserts the persisted placeholder is unexpanded in config.yaml and the key landed in .env)optional-mcps/deapi/manifest.yaml— new catalog entryHow to Test
python -m pytest tests/hermes_cli/test_mcp_catalog.py -q→ 36 passedhermes mcp install deapi(get a free key at https://app.deapi.ai) → inspect~/.hermes/config.yaml:mcp_servers.deapi=url+headers.Authorization: Bearer ${DEAPI_API_KEY}+ curatedtools.includehermes chat -q "Call the deapi get_balance tool"→ returns the account balanceChecklist
Code
fix(mcp):,feat(mcp):)pytest tests/hermes_cli/test_mcp_catalog.py -q— 36 passedDocumentation & Housekeeping
cli-config.yaml.example— N/ACONTRIBUTING.md/AGENTS.md— N/AScreenshots / Logs
Verified end-to-end in a live session (catalog install → new session → MCP tool call):
Disclosure: prepared with AI assistance (Claude Code); diagnosed, reviewed and live-tested by a human.
🤖 Generated with Claude Code