Extend Hermes MCP server (mcp_serve.py) to expose internal capabilities to external agents. Use when adding tools to Hermes's MCP interface so Codex, Windsurf, Claude Code, and other MCP clients can access skills, routing, or other Hermes features.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add Undermybelt/hermes-skills --skill hermes-mcp-server-extnsn --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Hermes Mcp Server Extnsn?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/undermybelt-hermes-mcp-server-extnsn)More formats (shields.io, HTML) on the badges page.
---
name: hermes-mcp-server-extnsn
description: >
Extend Hermes MCP server (mcp_serve.py) to expose internal capabilities to external agents.
Use when adding tools to Hermes's MCP interface so Codex, Windsurf, Claude Code, and other
MCP clients can access skills, routing, or other Hermes features.
version: 1.0.0
tags: [hermes, mcp, extension, skills, routing, codex, windsurf]
---
# Hermes MCP Server Extension
## When to Use
When you need external agents (Codex, Windsurf, Claude Code, Cursor) to access Hermes
capabilities via MCP. The MCP server (`mcp_serve.py`) is **separate** from the agent's
internal tool registry (`tools/`).
## Key File
`~/.hermes/hermes-agent/mcp_serve.py`
## Architecture
```
Hermes Internal Tools (tools/*.py)
└── Only available to Hermes's own agent loop
└── Registered via tools/registry.py
Hermes MCP Server (mcp_serve.py)
└── Available to any MCP client (Codex, Windsurf, CC)
└── Uses @mcp.tool() decorator inside create_mcp_server()
└── Separate from internal tools — must reimplement or import helpers
```
## Adding an MCP Tool
```python
# Inside create_mcp_server() in mcp_serve.py:
# 1. Define helpers (reuse internals or reimplement)
def _get_skills_dir() -> Path:
try:
from hermes_constants import get_hermes_home
return get_hermes_home() / "skills"
except ImportError:
return Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) / "skills"
# 2. Add tool with @mcp.tool() decorator
@mcp.tool()
def my_new_tool(param: str) -> str:
"""Description visible to MCP clients.
Args:
param: What this parameter does.
"""
return json.dumps({"result": "..."}, ensure_ascii=False)
```
## Current MCP Tools (15)
### Messaging (10)
- conversations_list, conversation_get, messages_read, attachments_fetch
- events_poll, events_wait, messages_send, channels_list
- permissions_list_open, permissions_respond
### Skills & Routing (5)
- **skill_list** — list all skills with metadata (name, desc, category, tags)
- **skill_view** — load full SKILL.md content + linked files
- **skill_route** — match task description against routing triggers (Chinese + English)
- **routing_rules** — return full skill-router.md content
- **skill_apply** — ONE-STEP: find + load skill by name or task description. USE THIS FIRST.
### Governance Feedback Loop (2)
- **governance_submit_candidate** — save external-agent findings as governance candidates
- **governance_list_candidates** — inspect recent saved candidates in the governance inbox
## Auto-Routing Architecture (Critical)
External agents (Codex, Windsurf, CC) don't know to call skill tools unless told.
Solution: embed the routing table in `FastMCP(instructions=...)` so it's always visible.
```python
# At startup, read skill-router.md and build instructions dynamically
_routing_text = ""
_router_path = Path(HERMES_HOME) / "routing" / "skill-router.md"
for line in _router_path.read_text().splitlines():
line = line.strip()
if line.startswith("-") and "→" in line:
_routing_text += " " + line.lstrip("- ") + "\n"
mcp = FastMCP("hermes", instructions=(
"ROUTING TABLE (keywords → skill):\n" + _routing_text +
"\nCall skill_apply(query) to load a skill. USE THIS FIRST.\n"
))
```
**Why this matters:**
- Without routing in instructions, agents only see tool names/descriptions
- With routing in instructions, agents see "古法编程 → old-code" and know to call skill_apply
- `skill_apply` description says "USE THIS FIRST for any task" — nudges agents to check skills
**skill_apply flow:**
1. Try direct name match → load SKILL.md
2. Route match against triggers → load top hit
3. Fuzzy fallback on descriptions → load top hit
4. Return full content + source + all_matches
## Pitfalls
- **yaml import**: Import once per function, not inside loops (895 skills = 895 imports)
- **Unicode**: Use `ensure_ascii=False` in all json.dumps calls
- **Missing deps**: Wrap imports in try/except ImportError
- **instructions**: Update `FastMCP(instructions=...)` when adding tools
- **Circular imports**: Can't always import from tools/ — may need to reimplement helpers
- **Security scan**: hermes-agent skill blocks edits due to env var refs; use this skill instead
- **Auto-routing gap**: If routing table is NOT in instructions, external agents won't know to call skill tools. Always embed routing triggers in instructions.
- **skill_apply > skill_route + skill_view**: Two-step flow requires agent to know both tools. `skill_apply` does it in one call — always prefer it in tool descriptions.
- **Routing table size**: 105 triggers ≈ 5.7KB in instructions. Acceptable for MCP context.
## Decision Guide
| Need | Where to add |
|------|-------------|
| Only Hermes agent loop needs it | `tools/your_tool.py` + registry |
| External agents need it too | `mcp_serve.py` with @mcp.tool() |
| Both | Add to both (separate implementations) |
## Files Modified
- `mcp_serve.py` — added skill_list, skill_view, skill_route, routing_rules, skill_apply tools
- FastMCP instructions updated: routing table from skill-router.md embedded at startup
- `_routing_text` built dynamically from `~/.hermes/routing/skill-router.md`
- `_scan_skills()` helper: walks skills dir, parses frontmatter, returns metadata
- `_route_skill()` helper: matches query against routing triggers + fuzzy fallback
- `_load_skill_content()` helper: finds and reads SKILL.md by name
## Standalone Package: mcp-skill-hub
The same architecture can be extracted as a standalone package for others to use.
Location: `/tmp/mcp-skill-hub/` (ready to push to GitHub).
```
mcp-skill-hub/
├── pyproject.toml # pip install mcp-skill-hub
├── src/mcp_skill_hub/
│ └── server.py # standalone: no Hermes deps
└── examples/skills/
├── router.md # keyword → skill routing
├── ddd-project/SKILL.md
├── code-review/SKILL.md
└── old-code/SKILL.md
```
### Architecture Insight (for README / talks)
The core idea is **portable agent knowledge**:
```
SKILL.md = reusable knowledge unit (markdown, human-editable, agent-executable)
router.md = keyword → skill mapping (Chinese + English triggers)
MCP = sharing protocol (one server, any client)
```
- Skills are just markdown — no code, no API, no cloud
- Anyone can contribute by PR-ing a SKILL.md
- Routing table in MCP instructions = agents auto-discover skills
- `skill_apply("古法编程")` one-step = zero-friction skill loading
- Tagline: "Share AI agent skills as markdown via MCP"
### Why This Matters
Without this pattern:
- Agent knowledge is locked in system prompts / config files
- Switching agents means losing all learned workflows
- No way to share proven workflows between agents
With this pattern:
- Skills are portable across any MCP-capable agent
- Community can contribute skills via git
- Routing is declarative (keywords in router.md)
- One `skill_apply()` call replaces hours of trial-and-error
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!