Hermes: the 32 MCP tools
1. What? — Definition and context
Section titled “1. What? — Definition and context”An agent without tools can only talk. What makes Hermes useful is the catalogue of 32 business tools it can call to read and change the real state of the system: Odoo projects, Docker containers, Prometheus metrics, notes in the Obsidian vault.
These tools do not live in the agent’s container. They are defined in an N8N workflow (Hermes MCP Tools, 33 nodes, active) that exposes them through a single Bearer-protected MCP Server Trigger. The container knows nothing but a URL and a token.
The two MCP channels
Section titled “The two MCP channels”| Channel | Target | Tools | Usage |
|---|---|---|---|
n8n-tools | n8n:5678/mcp/hermes-tools | 32 curated business tools | The normal flow, 99% of calls |
n8n-admin | n8n-mcp:3000/mcp | 4 tools, filtered from 24 exposed | Workflow diagnostics only |
Architecture
Section titled “Architecture”2. Why? — Stakes and motivations
Section titled “2. Why? — Stakes and motivations”Why curated tools rather than direct access?
Section titled “Why curated tools rather than direct access?”It would have been quicker to give the agent generic access to the Odoo API and let it compose its own XML-RPC calls. Three reasons not to.
| Stake | What a dedicated tool brings |
|---|---|
| Surface | A tool does one thing. odoo_update_task cannot delete a project, however creative the model gets |
| Schema | Every parameter has a name, a type and a description. The model does not have to guess the shape of an Odoo domain |
| Control point | An N8N node between the agent and the target allows validating, capping, escaping and logging before execution |
The cost is real — each new tool is a node to create — but it is paid once, and it makes the agent’s behaviour predictable.
Why typed-input gateways?
Section titled “Why typed-input gateways?”The non-Odoo tools never point straight at the existing workflows. Each domain goes through a wrapper that defines its own inputs, then delegates.
Without a wrapper, the agent would have to know the internal contract of Docker Actions or of the Telegram Content Pipeline — workflows designed for other callers, whose shape can change. The wrapper decouples: it gives the agent a clean, stable MCP schema and absorbs internal changes.
3. How? — Technical implementation
Section titled “3. How? — Technical implementation”The full catalogue
Section titled “The full catalogue”Odoo — projects and tasks (10)
| Tool | Role |
|---|---|
odoo_list_projects | Lists project id + name |
odoo_create_project | Creates a project (the ORM creates the matching analytic account) |
odoo_update_project | Updates one field (name / description) |
odoo_archive_project | Archives or unarchives |
odoo_list_task_stages | Kanban stages of a project (id, name, sequence, folded) |
odoo_move_task_stage | Moves a task across the kanban |
odoo_list_tasks | Tasks of a project |
odoo_get_task | Task detail, description included |
odoo_create_task | Creates a task |
odoo_update_task | Updates one field (name / description / deadline) |
Odoo — contacts (3): odoo_search_contacts (search by name, returns contact details and address), odoo_create_contact, odoo_update_contact.
Odoo — CRM (6): crm_list_stages (pipeline stages with sequence and is_won), crm_list_leads, crm_create_lead (type=opportunity forced so the lead lands in the pipeline), crm_update_lead, crm_move_stage, crm_delete_lead — sensitive.
Odoo — timesheets (4): timesheet_report (lines from a date), timesheet_log_hours, timesheet_update, timesheet_delete — sensitive.
Obsidian vault (4): vault_search (case-insensitive grep, 3 matches per file, 60-line cap), vault_list (tracked files, 300 cap), vault_read (30,000-character cap, returns a contentHash), vault_write (confined write).
Infrastructure (5): docker_read (status / logs / list), docker_manage (start / stop / restart / update — sensitive), monitoring_alerts, monitoring_query (instant PromQL), content_generate (draft note, article or research).
The four gateways
Section titled “The four gateways”| Gateway | Inputs | Delegates to |
|---|---|---|
| Docker | dockerStack, dockerAction | Docker Actions |
| Monitoring | mode (alerts / query), promql | Local SSH → curl Prometheus 127.0.0.1:9090 |
| Content | contentType, text, url | Telegram Content Pipeline |
| Vault | vaultAction, vaultQuery, vaultContent, vaultBaseHash | Local SSH → git + grep on ~/vaults/vps-vault |
Prometheus only listens on the host loopback: the monitoring gateway therefore goes through SSH then curl, like the Docker health check. The PromQL is escaped before insertion into the command.
Confined writes in the vault
Section titled “Confined writes in the vault”vault_write is the only tool that durably changes anything outside Odoo. Its validation happens in JavaScript before the shell command is built: prefix whitelist (research/, inbox/), mandatory .md extension, anti-traversal, character checks, a 150,000-byte cap — counted in bytes, not characters.
The interesting part is read-before-overwrite, with no shared state: vault_read returns a contentHash (sha256 truncated to 12 hex characters), and overwriting an existing file requires passing that hash back as Base_Hash. Without a hash, the reply is __EXISTS__; if the file has changed since the read, __STALE_READ__.
Structured errors
Section titled “Structured errors”The gateways do not raise an exception on invalid input: they return a marker that the formatter translates into {success: false, error, hint}. __NOT_FOUND__, __BAD_PATH__, __BAD_ACTION__, __EMPTY_QUERY__, __EXISTS__, __STALE_READ__.
The side effect matters: these responses do not trigger the Global Error Handler. A typo from the agent is a business response, not an infrastructure incident — it goes straight back into the conversation with a hint about the fix.
Four pitfalls of the N8N MCP layer
Section titled “Four pitfalls of the N8N MCP layer”Security
Section titled “Security”| Surface | Protection |
|---|---|
| MCP endpoint | Bearer required — 403 without a token, verified end-to-end |
| From the Internet | /mcp/* and /mcp-test/* return 404 at Caddy; only internal n8n:5678 works |
docker_manage | Action whitelist in Docker Actions; security-stack not actionable |
| Destructive actions | docker_manage, crm_delete_lead, timesheet_delete require explicit confirmation, enforced by the system prompt |
| Vault writes | Whitelisted prefixes, anti-traversal, read-before-overwrite |
4. What if? — Outlook and limits
Section titled “4. What if? — Outlook and limits”Current limits
Section titled “Current limits”| Limit | Impact | Mitigation |
|---|---|---|
employee_id hard-coded to 1 | timesheet_log_hours always writes against the same employee | Moot today, to be parameterised if the team grows |
| Restart after every change | Any schema change forces a restart | Batch tool changes together |
| No downstream approval | Sensitive actions are protected by the prompt alone | Whitelist in Docker Actions; approval chain still to be wired |
| No sub-node can be disabled | Disabling a tool breaks the routing of every subsequent one | Delete the node rather than disable it (see the fourth pitfall) |
Evolution scenarios
Section titled “Evolution scenarios”If sensitive actions must be truly blocking:
- Reuse the
MCP Confirmation Handleralready in place for CLI Ollama rather than writing a second one. - The gateway would post a webhook and wait for the Telegram callback, exactly as
cli-ollamaalready does.
If the catalogue keeps growing:
- 32 tools still fit in a prompt, but every tool costs tokens on every turn.
- Lead: context-activated toolsets, on the model of the per-conversation
/mcpin the conversational system.
If a tool has to write somewhere other than the vault:
- The
vault_writepattern is reusable as-is: prefix whitelist, validation before command construction, hash-based read-before-overwrite. - The expensive part — chunked transfer and integrity checking — is already written.
Troubleshooting
Section titled “Troubleshooting”# The catalogue as the agent sees itdocker exec hermes hermes mcp test n8n-tools
# Test the endpoint directly (403 expected without a token)docker exec n8n sh -c 'curl -s -o /dev/null -w "%{http_code}\n" -X POST \ http://n8n:5678/mcp/hermes-tools'
# Check the endpoint stays closed from outside (404 expected)curl -so /dev/null -w '%{http_code}\n' https://n8n.guigpap.com/mcp/hermes-toolsRelated pages
Section titled “Related pages”Hermes
Section titled “Hermes”- Hermes Agent — The deployment and its security model
- Skills — The procedures that exercise these tools
- Mnemosyne memory — The memory tools, container side
Workflows
Section titled “Workflows”- Error Handler — Error workflow for the gateways
- Docker Updates —
Docker Actions, target of the Docker gateway - Content Pipeline — Target of the content gateway, and the
vps-vaultvault
Reference
Section titled “Reference”- Glossary — MCP, Autonomous agent