Hermes and mcp

I tried Hermes Agent with mcp and have no success to established the connection without issue. Get 400 error.
Tried opencode mcp and this is working without an issue. With same configuration with same openhab cloud url and API key.
Is there a special trick to solve this or is this an issue by Hermes?
Somebody out there who tried that?

Can you explain how you are trying to set this up? What values you are using, stdio vs direct vs cloud? Anything really?

Edit: Also does the 400 error have any other info in it, a message or something like that? Also i take it hermes is running locally? Or are you using something like a VPS?

EDIT 2: One last thing, just looking at hermes, are you specifying the bearer token for hermes specifically like:

mcp_servers:
  openhab:
    url: "http://openhab.local:8080/mcp" # or your https local url or https://myopenhab.org/api/hooks/<uuid>
    headers:
      Authorization: "Bearer oh.YOUR_TOKEN"

I have not yet run hermes (or claw or similar), so i’m not 100% sure. The good thing is we are using the official MCP java library, so should be very standards compliant.

Hi Dan,

thanks for your response and sorry for my late answer.

[hermes] WARNING tools.mcp_tool: Failed to connect to MCP server 'openhab': Client error '400 Bad Request' for url '``https://myopenhab.org/api/hooks/UUID``'
[hermes] For more information check: ``https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400

And my config looks like:

mcp_servers:
openhab:
url: ``https://myopenhab.org/api/hooks/uuid
transport: streamable-http
headers:
Authorization: Bearer ${OPENHAB_API_KEY}
n8n:
url: ``http://192.168.0.50:5678/mcp-server/http
headers:
Authorization: Bearer ${N8N_API_KEY}
linear:
url: ``https://mcp.linear.app/mcp
auth: oauth
enabled: true

So MCP for n8n isn’t a problem it’s working but openhab doesn’t work. As i told before… Only in hermes. URL is working in opencode.

Dunno why formatting goes wrong here…

openHAB MCP + Hermes Agent: HTTP 400 on connect — resolved

TL;DR — It was never the URL or the token. Hermes advertises a non-standard MCP client capability (sampling.tools) that openHAB’s strict Java SDK rejects with 400. Disabling sampling/elicitation for the openHAB server fixes it.


The symptom

Hermes is configured with the openHAB cloud hook URL and a bearer token header:

mcp_servers:
  openhab:
    url: https://myopenhab.org/api/hooks/<your-uuid>
    headers:
      Authorization: Bearer <your-token>

Hermes fails to connect:

WARNING tools.mcp_tool: MCP server 'openhab' failed initial connection
HTTPStatusError: Client error '400 Bad Request'
for url 'https://myopenhab.org/api/hooks/<your-uuid>'

The exact same URL and token work in other clients (e.g. opencode). So the credentials and the webhook registration are fine — this is not an auth problem.


The real cause

The 400 comes from the MCP initialize handshake, before any tool call.

Hermes (Python MCP SDK over Streamable HTTP) advertises a non-standard client capability in its initialize request:

{
  "capabilities": {
    "sampling": {
      "tools": {}
    }
  }
}

openHAB’s MCP server uses the official Java MCP SDK, which parses requests with strict settings (FAIL_ON_UNKNOWN_PROPERTIES). Its ClientCapabilities.Sampling model has no tools field, so it rejects the entire message:

Invalid message format: Unrecognized field "tools"
(class io.modelcontextprotocol.spec.McpSchema$ClientCapabilities$Sampling),
not marked as ignorable (0 known properties: )

In short:

  • openHAB’s server is strict about unknown capability fields.
  • Hermes sends an extra field the strict parser doesn’t know.
  • → HTTP 400 Bad Request on every connect attempt.

This is why the identical URL + token work everywhere else — most clients don’t advertise sampling.tools / elicitation, so openHAB never sees the unknown field.


The fix

Tell Hermes not to announce the sampling/elicitation capabilities for the openHAB server (per-server toggle):

mcp_servers:
  openhab:
    url: https://myopenhab.org/api/hooks/<your-uuid>
    headers:
      Authorization: Bearer ${OPENHAB_API_KEY}
    sampling:
      enabled: false
    elicitation:
      enabled: false

sampling.enabled: false stops Hermes sending capabilities.sampling.tools — exactly the field openHAB rejects. elicitation.enabled: false does the same for the related capability.

After a restart it connects cleanly and registers the tools:

INFO tools.mcp_tool: MCP server 'openhab' (HTTP): registered 30 tool(s):
mcp__openhab__get_semantic_model, mcp__openhab__search_items, ...

Note: sampling / elicitation are only useful if you want an MCP server to make LLM calls back to the agent. openHAB is a plain tool server, so disabling them costs nothing.


Suggestion for upstream

  • Hermes side: the sampling.tools capability is (ahead of) what many servers accept. It would be nice if it were only sent when the server negotiates support.
  • openHAB side: tolerating unknown fields in ClientCapabilities (@JsonIgnoreProperties(ignoreUnknown = true)) instead of failing the whole handshake would avoid pushing the problem onto every client.

The per-server toggle above is a working workaround either way.

This solution is AI generated.

@digitaldan solution for Hermes is set.