Skip to content

Bug: Paperclip MCP from Hermes fails out-of-the-box (missing default companyId + docker hostname not in allowlist)#83

Merged
leebaroneau merged 4 commits into
mainfrom
bug/82-paperclip-mcp-default-envs
May 22, 2026
Merged

Bug: Paperclip MCP from Hermes fails out-of-the-box (missing default companyId + docker hostname not in allowlist)#83
leebaroneau merged 4 commits into
mainfrom
bug/82-paperclip-mcp-default-envs

Conversation

@leebaroneau
Copy link
Copy Markdown
Owner

@leebaroneau leebaroneau commented May 22, 2026

Fixes #82

Summary

Every fresh template-agent spin-up hits stacked failures the first time a Hermes profile calls the Paperclip MCP plugin. This PR bakes the missing defaults into the template so the bug stops repeating.

What broke

Three issues, all on the path between Hermes and the Paperclip API:

  1. Hermes filters env when spawning MCP subprocesses — only keys listed in mcp_servers.<name>.env get forwarded. The previous hermes-runtime/templates/config.yaml had no env: block on the paperclip MCP, so server.mjs started with no API key and defaulted to 127.0.0.1:3100 (nothing listening from the Hermes container) → every tool call surfaced as fetch failed to the model.
  2. The docker service name paperclip is not in the default allowlist — Hermes is hardcoded to call http://paperclip:3100 in compose.yaml:71, but PAPERCLIP_ALLOWED_HOSTNAMES defaulted to localhost,127.0.0.1. Paperclip 403s with Hostname 'paperclip' is not allowed.
  3. PAPERCLIP_DEFAULT_COMPANY_ID is left undocumented — the MCP plugin falls back to this env when the model doesn't pass companyId as an argument. Empty → companyId is required error mid-conversation. Operators have no way to know it must be set before the MCP plugin works.

All three baked into the template means every new deployment from this repo repeats the bug.

Changes

  • hermes-runtime/templates/config.yaml: add env: block to the paperclip MCP server config that forwards PAPERCLIP_API_KEY, PAPERCLIP_API_BASE, PAPERCLIP_DEFAULT_COMPANY_ID, PAPERCLIP_PROFILE_SYNC_API_KEY via ${VAR} placeholders (Hermes interpolates from os.environ at spawn time).
  • compose.yaml: include paperclip in the default PAPERCLIP_ALLOWED_HOSTNAMES — it's structural to how the Hermes service in this compose reaches Paperclip, not site-specific.
  • .env.example + .env.coolify.example: mirror the allowlist change in the example value, and add a comment block above PAPERCLIP_DEFAULT_COMPANY_ID= flagging it as required-before-MCP-works.

Found on

Genvest agent-genvest Coolify deployment on 2026-05-22 — the Head of Customer Service Hermes profile tried to assign a Paperclip ticket via Telegram and reported "Paperclip isn't connecting right now". The underlying errors in the Hermes session log were companyId is required, Hostname 'paperclip' is not allowed, and fetch failed.

Caveat — existing deployments

bootstrap-profiles.sh::sync_mcp_servers_from_template only ADDS missing mcp_servers entries to a profile's config.yaml; it does NOT update existing ones. So this template change fixes new deployments only — existing profile config.yaml files keep their old paperclip MCP entry with no env: block. The Genvest droplet was patched per-profile manually as part of the live fix.

A follow-up to make sync_mcp_servers_from_template reconcile env blocks on existing entries would prevent the same recovery toil next time. Out of scope here — flagging for the in-flight MCP overlay design (story/84).

Test plan

  • Pull this branch into a fresh deployment from .env.example (or .env.coolify.example) with PAPERCLIP_DEFAULT_COMPANY_ID filled in.
  • From inside Hermes: hermes -p <profile> mcp test paperclip → 8 tools discovered, no "Missing PAPERCLIP_API_KEY" warning in logs/mcp-stderr.log.
  • Through a chat path (Telegram or local CLI): ask the agent to list/create a Paperclip issue with no companyId argument; verify it returns real data instead of companyId is required or fetch failed.

…_DEFAULT_COMPANY_ID as required

The Hermes service in this compose calls Paperclip at http://paperclip:3100, so
the docker service name 'paperclip' must be in PAPERCLIP_ALLOWED_HOSTNAMES or
the API rejects every MCP call with 403. Make that the structural default.

Also annotate PAPERCLIP_DEFAULT_COMPANY_ID in the .env templates so operators
know it must be set before the Paperclip MCP plugin will work from inside
Hermes — empty causes "companyId is required" errors mid-conversation.

Fixes #82
Hermes filters the environment when spawning MCP subprocesses — only keys
listed in mcp_servers.<name>.env get forwarded. The previous template had no
env block on the paperclip MCP, so /opt/paperclip/mcp-paperclip/server.mjs
started with no PAPERCLIP_API_KEY and a default base URL of 127.0.0.1:3100.
From the Hermes container, 127.0.0.1:3100 has nothing listening, so every
tool call surfaced as "fetch failed" to the model (and the bot reported
"Paperclip isn't connecting right now" to the user).

Add a minimal env block that forwards the four envs the MCP server reads,
using ${VAR} placeholders that Hermes interpolates from os.environ at spawn
time (see tools/mcp_tool.py::_interpolate_env_vars).

Note: bootstrap-profiles.sh::sync_mcp_servers_from_template only ADDS
missing mcp_servers entries — it does not update existing ones. So this
template change fixes new deployments only; existing profile config.yaml
files need a separate per-profile patch to pick up the new env block.

Fixes #82
Previously sync_mcp_servers_from_template only copied template entries
that were ENTIRELY missing from a profile's config.yaml. If an entry
already existed (e.g. paperclip MCP from an older deployment), template
updates to its env block were silently ignored — operators had to patch
every profile by hand. That's exactly the recovery toil we just hit when
adding PAPERCLIP_API_KEY/PAPERCLIP_API_BASE/PAPERCLIP_DEFAULT_COMPANY_ID/
PAPERCLIP_PROFILE_SYNC_API_KEY to the paperclip MCP env block.

Extend the sync to also MERGE missing env keys onto existing entries:

  - Template env keys not in the profile's env block are added.
  - Existing env values in the profile are NEVER overwritten (preserves
    operator customisations).
  - Non-env fields on existing entries (command, args, timeout, etc.) are
    still NEVER touched.
  - Operation is idempotent — running the bootstrap again is a no-op once
    the profile is in sync.

Net effect: next image rebuild + container restart will pick up template
env additions automatically, on every existing profile, without manual
intervention.

Fixes #82
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 22, 2026

Merge gate failing — the following must be resolved before merging:

  • linked issue must be in status:review, but is in no status.
  • required CI status check(s) not green: pr-closed / handle (pending)

Branch protection on main requires pipeline/merge-gate to be green.

…default-envs

# Conflicts:
#	hermes-runtime/scripts/bootstrap-profiles.sh
@leebaroneau leebaroneau merged commit 92a2ac8 into main May 22, 2026
6 checks passed
@leebaroneau leebaroneau deleted the bug/82-paperclip-mcp-default-envs branch May 22, 2026 12:54
@github-actions
Copy link
Copy Markdown

PR-Issue link check failed

Linked issue is closed or doesn't exist. Reference an open issue with Closes #N / Fixes #N / Resolves #N / Refs #N.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Paperclip MCP from Hermes fails out-of-the-box (missing default companyId + docker hostname not in allowlist)

1 participant