2026-03-05 05:24:55 -08:00
---
sidebar_position: 4
title: "MCP (Model Context Protocol)"
2026-03-14 06:36:01 -07:00
description: "Connect Hermes Agent to external tool servers via MCP — and control exactly which MCP tools Hermes loads"
2026-03-05 05:24:55 -08:00
---
# MCP (Model Context Protocol)
2026-03-14 06:36:01 -07:00
MCP lets Hermes Agent connect to external tool servers so the agent can use tools that live outside Hermes itself — GitHub, databases, file systems, browser stacks, internal APIs, and more.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
If you have ever wanted Hermes to use a tool that already exists somewhere else, MCP is usually the cleanest way to do it.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
## What MCP gives you
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
- Access to external tool ecosystems without writing a native Hermes tool first
- Local stdio servers and remote HTTP MCP servers in the same config
- Automatic tool discovery and registration at startup
- Utility wrappers for MCP resources and prompts when supported by the server
- Per-server filtering so you can expose only the MCP tools you actually want Hermes to see
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
## Quick start
2026-03-05 05:24:55 -08:00
2026-03-18 03:14:58 -07:00
1. Install MCP support (already included if you used the standard install script):
2026-03-05 05:24:55 -08:00
```bash
2026-03-18 03:14:58 -07:00
cd ~/.hermes/hermes-agent
uv pip install -e ".[mcp]"
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
2. Add an MCP server to `~/.hermes/config.yaml` :
2026-03-05 05:24:55 -08:00
```yaml
mcp_servers:
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server -filesystem", "/home/user/projects"]
```
2026-03-14 06:36:01 -07:00
3. Start Hermes:
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
```bash
hermes chat
```
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
4. Ask Hermes to use the MCP-backed capability.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
For example:
```text
List the files in /home/user/projects and summarize the repo structure.
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
Hermes will discover the MCP server's tools and use them like any other tool.
## Two kinds of MCP servers
### Stdio servers
Stdio servers run as local subprocesses and talk over stdin/stdout.
2026-03-05 05:24:55 -08:00
```yaml
mcp_servers:
2026-03-14 06:36:01 -07:00
github:
2026-03-05 05:24:55 -08:00
command: "npx"
2026-03-14 06:36:01 -07:00
args: ["-y", "@modelcontextprotocol/server -github"]
2026-03-05 05:24:55 -08:00
env:
2026-03-14 06:36:01 -07:00
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
Use stdio servers when:
- the server is installed locally
- you want low-latency access to local resources
- you are following MCP server docs that show `command` , `args` , and `env`
### HTTP servers
HTTP MCP servers are remote endpoints Hermes connects to directly.
2026-03-05 05:24:55 -08:00
```yaml
mcp_servers:
2026-03-14 06:36:01 -07:00
remote_api:
url: "https://mcp.example.com/mcp"
headers:
Authorization: "Bearer * * *"
```
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
Use HTTP servers when:
- the MCP server is hosted elsewhere
- your organization exposes internal MCP endpoints
- you do not want Hermes spawning a local subprocess for that integration
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
## Basic configuration reference
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
Hermes reads MCP config from `~/.hermes/config.yaml` under `mcp_servers` .
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Common keys
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
| Key | Type | Meaning |
|---|---|---|
| `command` | string | Executable for a stdio MCP server |
| `args` | list | Arguments for the stdio server |
| `env` | mapping | Environment variables passed to the stdio server |
| `url` | string | HTTP MCP endpoint |
| `headers` | mapping | HTTP headers for remote servers |
| `timeout` | number | Tool call timeout |
| `connect_timeout` | number | Initial connection timeout |
| `enabled` | bool | If `false` , Hermes skips the server entirely |
| `tools` | mapping | Per-server tool filtering and utility policy |
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Minimal stdio example
2026-03-05 05:24:55 -08:00
```yaml
2026-03-14 06:36:01 -07:00
mcp_servers:
2026-03-05 05:24:55 -08:00
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server -filesystem", "/tmp"]
```
2026-03-14 06:36:01 -07:00
### Minimal HTTP example
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
```yaml
mcp_servers:
company_api:
url: "https://mcp.internal.example.com"
headers:
Authorization: "Bearer * * *"
```
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
## How Hermes registers MCP tools
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
Hermes prefixes MCP tools so they do not collide with built-in names:
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
```text
mcp_<server_name>_<tool_name>
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
Examples:
| Server | MCP tool | Registered name |
|---|---|---|
2026-03-05 05:24:55 -08:00
| `filesystem` | `read_file` | `mcp_filesystem_read_file` |
| `github` | `create-issue` | `mcp_github_create_issue` |
| `my-api` | `query.data` | `mcp_my_api_query_data` |
2026-03-14 06:36:01 -07:00
In practice, you usually do not need to call the prefixed name manually — Hermes sees the tool and chooses it during normal reasoning.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
## MCP utility tools
docs: expand Docusaurus coverage across CLI, tools, skills, and skins (#1232)
- add code-derived reference pages for slash commands, tools, toolsets,
bundled skills, and official optional skills
- document the skin system and link visual theming separately from
conversational personality
- refresh quickstart, configuration, environment variable, and messaging
docs to match current provider, gateway, and browser behavior
- fix stale command, session, and Home Assistant configuration guidance
2026-03-13 21:34:41 -07:00
2026-03-14 06:36:01 -07:00
When supported, Hermes also registers utility tools around MCP resources and prompts:
docs: fix all remaining minor accuracy issues
- updating.md: Note that 'hermes update' auto-handles config migration
- cli.md: Add summary_model to compression config, fix display config
(add personality/compact), remove unverified pastes/ claim
- configuration.md: Add 5 missing config sections (stt, human_delay,
code_execution, delegation, clarify), fix display defaults,
fix reasoning_effort default to empty/unset
- messaging/index.md: Add GATEWAY_ALLOWED_USERS to security section
- skills.md: Add category field to skills_list return value
- mcp.md: Document auto-registered utility tools (resources/prompts)
- architecture.md: Fix file_tools.py reference, base_url default to None,
synchronous agent loop pseudocode
- cli-commands.md: Fix hermes logout description
- environment-variables.md: Add HERMES_QUIET, HERMES_EXEC_ASK,
BROWSER_INACTIVITY_TIMEOUT, GATEWAY_ALLOWED_USERS
Verification scan: 27/27 checks passed, zero issues remaining.
2026-03-05 07:00:51 -08:00
2026-03-14 06:36:01 -07:00
- `list_resources`
- `read_resource`
- `list_prompts`
- `get_prompt`
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
These are registered per server with the same prefix pattern, for example:
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
- `mcp_github_list_resources`
- `mcp_github_get_prompt`
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Important
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
These utility tools are now capability-aware:
- Hermes only registers resource utilities if the MCP session actually supports resource operations
- Hermes only registers prompt utilities if the MCP session actually supports prompt operations
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
So a server that exposes callable tools but no resources/prompts will not get those extra wrappers.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
## Per-server filtering
This is the main feature added by the PR work.
You can now control which tools each MCP server contributes to Hermes.
### Disable a server entirely
2026-03-05 05:24:55 -08:00
```yaml
mcp_servers:
2026-03-14 06:36:01 -07:00
legacy:
url: "https://mcp.legacy.internal"
enabled: false
```
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
If `enabled: false` , Hermes skips the server completely and does not even attempt a connection.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Whitelist server tools
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
```yaml
mcp_servers:
2026-03-05 05:24:55 -08:00
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server -github"]
env:
2026-03-14 06:36:01 -07:00
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
tools:
include: [create_issue, list_issues]
```
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
Only those MCP server tools are registered.
### Blacklist server tools
```yaml
mcp_servers:
stripe:
url: "https://mcp.stripe.com"
tools:
exclude: [delete_customer]
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
All server tools are registered except the excluded ones.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Precedence rule
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
If both are present:
```yaml
tools:
include: [create_issue]
exclude: [create_issue, delete_issue]
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
`include` wins.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Filter utility tools too
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
You can also separately disable Hermes-added utility wrappers:
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
```yaml
mcp_servers:
docs:
url: "https://mcp.docs.example.com"
tools:
prompts: false
resources: false
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
That means:
- `tools.resources: false` disables `list_resources` and `read_resource`
- `tools.prompts: false` disables `list_prompts` and `get_prompt`
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Full example
2026-03-05 05:24:55 -08:00
```yaml
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server -github"]
env:
2026-03-14 06:36:01 -07:00
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
tools:
include: [create_issue, list_issues, search_code]
prompts: false
stripe:
url: "https://mcp.stripe.com"
headers:
Authorization: "Bearer * * *"
tools:
exclude: [delete_customer]
resources: false
legacy:
url: "https://mcp.legacy.internal"
enabled: false
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
## What happens if everything is filtered out?
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
If your config filters out all callable tools and disables or omits all supported utilities, Hermes does not create an empty runtime MCP toolset for that server.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
That keeps the tool list clean.
## Runtime behavior
### Discovery time
Hermes discovers MCP servers at startup and registers their tools into the normal tool registry.
### Reloading
If you change MCP config, use:
```text
/reload-mcp
2026-03-05 05:24:55 -08:00
```
2026-03-14 06:36:01 -07:00
This reloads MCP servers from config and refreshes the available tool list.
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
### Toolsets
2026-03-05 05:24:55 -08:00
2026-03-14 06:36:01 -07:00
Each configured MCP server also creates a runtime toolset when it contributes at least one registered tool:
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
```text
mcp-<server>
```
That makes MCP servers easier to reason about at the toolset level.
## Security model
### Stdio env filtering
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
For stdio servers, Hermes does not blindly pass your full shell environment.
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
Only explicitly configured `env` plus a safe baseline are passed through. This reduces accidental secret leakage.
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
### Config-level exposure control
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
The new filtering support is also a security control:
- disable dangerous tools you do not want the model to see
- expose only a minimal whitelist for a sensitive server
- disable resource/prompt wrappers when you do not want that surface exposed
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
## Example use cases
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
### GitHub server with a minimal issue-management surface
2026-03-09 03:37:38 -07:00
```yaml
mcp_servers:
2026-03-14 06:36:01 -07:00
github:
2026-03-09 03:37:38 -07:00
command: "npx"
2026-03-14 06:36:01 -07:00
args: ["-y", "@modelcontextprotocol/server -github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
tools:
include: [list_issues, create_issue, update_issue]
prompts: false
resources: false
2026-03-09 03:37:38 -07:00
```
2026-03-14 06:36:01 -07:00
Use it like:
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
```text
Show me open issues labeled bug, then draft a new issue for the flaky MCP reconnection behavior.
```
### Stripe server with dangerous actions removed
```yaml
mcp_servers:
stripe:
url: "https://mcp.stripe.com"
headers:
Authorization: "Bearer * * *"
tools:
exclude: [delete_customer, refund_payment]
```
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
Use it like:
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
```text
Look up the last 10 failed payments and summarize common failure reasons.
```
2026-03-09 03:37:38 -07:00
2026-03-14 06:36:01 -07:00
### Filesystem server for a single project root
2026-03-09 03:37:38 -07:00
```yaml
mcp_servers:
2026-03-14 06:36:01 -07:00
project_fs:
2026-03-09 03:37:38 -07:00
command: "npx"
2026-03-14 06:36:01 -07:00
args: ["-y", "@modelcontextprotocol/server -filesystem", "/home/user/my-project"]
```
Use it like:
```text
Inspect the project root and explain the directory layout.
```
## Troubleshooting
### MCP server not connecting
Check:
```bash
2026-03-18 03:14:58 -07:00
# Verify MCP deps are installed (already included in standard install)
cd ~/.hermes/hermes-agent && uv pip install -e ".[mcp]"
2026-03-14 06:36:01 -07:00
node --version
npx --version
2026-03-09 03:37:38 -07:00
```
2026-03-14 06:36:01 -07:00
Then verify your config and restart Hermes.
### Tools not appearing
Possible causes:
- the server failed to connect
- discovery failed
- your filter config excluded the tools
- the utility capability does not exist on that server
- the server is disabled with `enabled: false`
If you are intentionally filtering, this is expected.
### Why didn't resource or prompt utilities appear?
Because Hermes now only registers those wrappers when both are true:
1. your config allows them
2. the server session actually supports the capability
This is intentional and keeps the tool list honest.
2026-03-29 15:47:19 -07:00
## Running Hermes as an MCP server
In addition to connecting **to ** MCP servers, Hermes can also **be ** an MCP server. This lets other MCP-capable agents (Claude Code, Cursor, Codex, or any MCP client) use Hermes's messaging capabilities — list conversations, read message history, and send messages across all your connected platforms.
### When to use this
- You want Claude Code, Cursor, or another coding agent to send and read Telegram/Discord/Slack messages through Hermes
- You want a single MCP server that bridges to all of Hermes's connected messaging platforms at once
- You already have a running Hermes gateway with connected platforms
### Quick start
```bash
hermes mcp serve
```
This starts a stdio MCP server. The MCP client (not you) manages the process lifecycle.
### MCP client configuration
Add Hermes to your MCP client config. For example, in Claude Code's `~/.claude/claude_desktop_config.json` :
```json
{
"mcpServers": {
"hermes": {
"command": "hermes",
"args": ["mcp", "serve"]
}
}
}
```
Or if you installed Hermes in a specific location:
```json
{
"mcpServers": {
"hermes": {
"command": "/home/user/.hermes/hermes-agent/venv/bin/hermes",
"args": ["mcp", "serve"]
}
}
}
```
### Available tools
The MCP server exposes 10 tools, matching OpenClaw's channel bridge surface plus a Hermes-specific channel browser:
| Tool | Description |
|------|-------------|
| `conversations_list` | List active messaging conversations. Filter by platform or search by name. |
| `conversation_get` | Get detailed info about one conversation by session key. |
| `messages_read` | Read recent message history for a conversation. |
| `attachments_fetch` | Extract non-text attachments (images, media) from a specific message. |
| `events_poll` | Poll for new conversation events since a cursor position. |
| `events_wait` | Long-poll / block until the next event arrives (near-real-time). |
| `messages_send` | Send a message through a platform (e.g. `telegram:123456` , `discord:#general` ). |
| `channels_list` | List available messaging targets across all platforms. |
| `permissions_list_open` | List pending approval requests observed during this bridge session. |
| `permissions_respond` | Allow or deny a pending approval request. |
### Event system
The MCP server includes a live event bridge that polls Hermes's session database for new messages. This gives MCP clients near-real-time awareness of incoming conversations:
```
# Poll for new events (non-blocking)
events_poll(after_cursor=0)
# Wait for next event (blocks up to timeout)
events_wait(after_cursor=42, timeout_ms=30000)
```
Event types: `message` , `approval_requested` , `approval_resolved`
The event queue is in-memory and starts when the bridge connects. Older messages are available through `messages_read` .
### Options
```bash
hermes mcp serve # Normal mode
hermes mcp serve --verbose # Debug logging on stderr
```
### How it works
The MCP server reads conversation data directly from Hermes's session store (`~/.hermes/sessions/sessions.json` and the SQLite database). A background thread polls the database for new messages and maintains an in-memory event queue. For sending messages, it uses the same `send_message` infrastructure as the Hermes agent itself.
The gateway does NOT need to be running for read operations (listing conversations, reading history, polling events). It DOES need to be running for send operations, since the platform adapters need active connections.
### Current limits
- Stdio transport only (no HTTP MCP transport yet)
- Event polling at ~200ms intervals via mtime-optimized DB polling (skips work when files are unchanged)
- No `claude/channel` push notification protocol yet
- Text-only sends (no media/attachment sending through `messages_send` )
2026-03-14 06:36:01 -07:00
## Related docs
- [Use MCP with Hermes ](/docs/guides/use-mcp-with-hermes )
- [CLI Commands ](/docs/reference/cli-commands )
- [Slash Commands ](/docs/reference/slash-commands )
- [FAQ ](/docs/reference/faq )