Skip to content

feat(mcp): add deapi catalog entry + wire Authorization header for http api_key MCPs - #59586

Open
adampachowicz wants to merge 5 commits into
NousResearch:mainfrom
adampachowicz:feat/mcp-catalog-deapi
Open

feat(mcp): add deapi catalog entry + wire Authorization header for http api_key MCPs#59586
adampachowicz wants to merge 5 commits into
NousResearch:mainfrom
adampachowicz:feat/mcp-catalog-deapi

Conversation

@adampachowicz

Copy link
Copy Markdown

What does this PR do?

Two tightly-coupled commits:

1. fix(mcp): wire the Authorization header for http-transport catalog MCPs using auth.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 only url — no Authorization header — 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 writes headers: {Authorization: "Bearer ${VAR}"} resolved by the client's existing env interpolation; this mirrors it in the catalog installer (prefer auth.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 P2 but 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 the deapi catalog entrydeAPI'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_enabled curates the 22 real capabilities + account utilities, leaving the 17 *_price estimators 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 to auth: oauth once DCR lands).

Related Issue

Revives #51100. No existing issue for the deapi entry (searched open/closed issues + PRs for "deapi").

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • 🎯 New skill (bundled or hub) — catalog MCP entry

Changes Made

  • hermes_cli/mcp_catalog.py_build_server_config(): emit headers: {Authorization: "Bearer ${ENV}"} for http + api_key entries
  • tests/hermes_cli/test_mcp_catalog.pytest_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 entry

How to Test

  1. python -m pytest tests/hermes_cli/test_mcp_catalog.py -q → 36 passed
  2. hermes 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} + curated tools.include
  3. New session: hermes chat -q "Call the deapi get_balance tool" → returns the account balance

Checklist

Code

  • I've read the Contributing Guide
  • Conventional Commits (fix(mcp):, feat(mcp):)
  • Searched existing PRs — fix(mcp): wire Authorization header for http catalog MCPs using api_key auth #51100 is the prior art, closed unreviewed; credited via Co-authored-by
  • Only changes related to this fix/feature
  • pytest tests/hermes_cli/test_mcp_catalog.py -q — 36 passed
  • Test added for the fix
  • Tested on my platform: macOS 15 (Darwin 25.5), Hermes v0.18.0

Documentation & Housekeeping

  • Docs — manifest comments cover the auth rationale; no repo docs affected — otherwise N/A
  • cli-config.yaml.example — N/A
  • CONTRIBUTING.md / AGENTS.md — N/A
  • Cross-platform — pure Python dict-building, no platform-specific code
  • Tool descriptions/schemas — N/A

Screenshots / Logs

Verified end-to-end in a live session (catalog install → new session → MCP tool call):

┊ ⚡ mcp_deapi   0.4s
Your exact balance is 4.967697 USD.
get_available_models returned 25 models.

Disclosure: prepared with AI assistance (Claude Code); diagnosed, reviewed and live-tested by a human.

🤖 Generated with Claude Code

adampachowicz and others added 2 commits July 6, 2026 13:01
…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>
@alt-glitch alt-glitch added type/feature New feature or request tool/mcp MCP client and OAuth comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have labels Jul 6, 2026
adampachowicz and others added 3 commits July 6, 2026 13:59
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>
@adampachowicz
adampachowicz requested a review from a team July 6, 2026 11:59
@adampachowicz

Copy link
Copy Markdown
Author

Pushed three follow-up commits addressing packaging and UX gaps found in review of our own PR:

  1. fix(packaging)optional-mcps/deapi added to [tool.setuptools.data-files] so the manifest ships in the wheel (each catalog entry needs its own target, per the comment in pyproject.toml). Side note for maintainers: optional-mcps/unreal-engine appears to be missing its data-files entry too — happy to add it here or in a separate PR if wanted.
  2. feat(mcp) — bare hermes mcp add <name> now falls back to the catalog installer when <name> is a shipped entry, so mcp add deapimcp install deapi. Explicit --url/--command/--preset still always means a custom server. (+ test)
  3. feat(mcp-catalog) — manifests can declare explicit transport.headers (http-only, string→string, ${VAR} resolved by the client at connect time). Explicit headers override the automatic api_key Bearer header from this PR's base fix — covers future X-API-Key-style servers, non-Bearer prefixes and multi-header setups. (+ tests)

Full affected-suite run: pytest tests/hermes_cli/test_mcp_catalog.py tests/hermes_cli/test_mcp_config.py -q89 passed. Re-verified E2E locally: hermes mcp add deapi routes to the catalog, installs the correct block, and live get_balance works in a session.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:83 adds the generic transport.headers schema, but the submitted optional-mcps/deapi/manifest.yaml does 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_key Bearer-header fix and deapi manifest, but split out transport.headers until a reviewed catalog entry needs a non-Bearer or multi-header scheme.

This is an automated hermes-sweeper review.

Comment thread hermes_cli/mcp_catalog.py
# 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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/mcp MCP client and OAuth type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants