Hermes Kernel MCP Server
Enables AI agents to discover and invoke kernel tools and capabilities via the Model Context Protocol (MCP), supporting stdio, SSE, and Streamable HTTP transports for bidirectional communication.
README
Hermes Kernel v2
An async-first, event-driven AI Operating System kernel — Clean Architecture, plugin-extensible, MCP-native.
Status: v2.15.0 · 685 passed, 3 skipped, 92% coverage (Python 3.11+). All phases P0–P5 + extensions A/A2/B/C/D/E/F + ADR-007..029 + CI axis-gate delivered.
What is this?
Hermes Kernel v2 is the core runtime of an AI Operating System. It provides the minimal, well-factored primitives that higher layers (knowledge pipeline, agents, integrations) build on:
- Domain — pure Pydantic entities (documents, chunks, tools, tasks, events, capabilities, agents), JSON/MCP-serialisable, zero framework coupling.
- Event bus — async, fire-and-forget
publish+wait_forsync barrier, fault-contained per handler. - Registries — plugins, tools, capabilities, agents (async lock + sync fast-path for construction).
- Executor — capability-driven
Taskstate machine over the bus. - Workspace — multi-workspace registry (single-tenant today).
- Plugins — fault-tolerant loader + a declarative SDK (
@agent,@tool,@on_event,@capability). - MCP — bidirectional Model Context Protocol (client consumes external servers; server exposes kernel tools), stdio JSON-RPC 2.0, no external MCP lib.
Architecture follows Clean Architecture with a CI-enforced inward dependency
axis (import-linter). See docs/adr/.
Knowledge Pipeline (P2)
Raw files become a queryable knowledge graph through five independent, event-driven, workspace-scoped stages — each subscribes to the previous stage's event and publishes its own (no direct coupling). See ADR-004.
┌───────────────┐ document.scanned ┌────────────────┐ document.parsed
│ FileScanner │ ──────────────────▶ │ DocumentParser │ ─────────────────┐
└───────────────┘ └────────────────┘ │
▼
┌────────────────┐ chunk.embedded ┌───────────────┐ chunk.created ┌──────────────────┐
│ KnowledgeGraph │ ◀──────────────── │ ChunkEmbedder │ ◀────────────── │ DocumentChunker │
└───────┬────────┘ └───────────────┘ └──────────────────┘
│ graph.updated
▼
(node_id, edges, workspace_id)
| Stage | Does | Optional dep |
|---|---|---|
FileScanner |
polling watch, emits scanned files | — (no watchdog) |
DocumentParser |
extract text by MIME type | pdfminer.six (PDF) |
DocumentChunker |
sliding-window chunks w/ overlap | — |
ChunkEmbedder |
vector embeddings | sentence-transformers |
KnowledgeGraph |
cosine-similarity linking, workspace-isolated | — |
Heavy deps are lazily imported and optional; the default path (hash embeddings,
text parsing) is stdlib-only. End-to-end verified in
tests/test_integration_p2.py (real .md → 10 nodes, 8 edges).
Persistence & Multi-tenancy (P5)
The kernel is multi-tenant: users authenticate, operations are gated by RBAC,
and state survives restart in a workspace-isolated store. All stdlib
(hashlib, sqlite3) — no heavy deps. See
ADR-005.
| Layer | Module | Responsibility |
|---|---|---|
| Auth | kernel/auth.py |
User, AuthRegistry, pbkdf2-hash passwords (no plaintext) |
| RBAC | kernel/rbac.py |
Permission, Role, require_permission guard |
| Persistence | kernel/persistence.py |
SQLite async CRUD, workspace-isolated JSON store |
RBAC is a guard (require_permission before a registry call), not a
wrapper — see tests/test_rbac.py. Persistence composes with WorkspaceRegistry
(save/load), KnowledgeGraph (persist/load) and FileScanner (DB-backed
de-duplication) without rewriting them.
Extensions: SSE, Streamable HTTP, Retrieval, CLI (post-v0.7.0)
A — SSE transport for MCP (mcp/server_sse.py)
MCPServerSSE bridges the stdio MCPServer JSON-RPC core to the SSE transport:
GET /sse opens a text/event-stream and emits an endpoint event;
POST /messages/?sessionId=... carries JSON-RPC, responses stream back. Pure
stdlib (http.server + a dedicated asyncio loop) — no FastAPI/uvicorn.
srv = MCPServerSSE(tool_registry, event_bus)
srv.set_handler("echo", lambda a: f"got:{a.get('v')}")
srv.start(host="127.0.0.1", port=8080) # GET /sse + POST /messages/
A2 — Streamable HTTP transport for MCP (mcp/server_streamable.py)
The modern MCP HTTP shape (see ADR-008):
POST /mcp/v1/messages carries JSON-RPC and returns the response in the POST
body (HTTP 200); GET /mcp/v1/events is a server→client SSE stream for
notifications. Sessions use the Mcp-Session-Id header (not a query param),
and JSON-RPC batches (requests: [...]) are aggregated. Pure stdlib.
Durable sessions (resumable): pass a PersistenceRegistry to the
constructor. Every server→client SSE frame is persisted (per-session workspace
mcp:<session_id>) and replayed on reconnect when the client sends a
Last-Event-ID header — surviving disconnects and (with a file-backed store) a
full server restart.
from kernel.persistence import PersistenceRegistry
srv = MCPServerStreamable(tool_registry, event_bus,
persistence=PersistenceRegistry(db_path="mcp.db"))
srv.set_handler("echo", lambda a: f"got:{a.get('v')}")
srv.start(host="127.0.0.1", port=8080) # POST /mcp/v1/messages + GET /mcp/v1/events
B — KnowledgeRetrievalService (kernel/retrieval.py)
Durable, workspace-scoped vector search with pluggable backends (ADR-009).
from kernel.retrieval import KnowledgeRetrievalService
from kernel.retrieval_backends import FaissBackend
svc = KnowledgeRetrievalService(
persistence, bus,
backend=FaissBackend(persist_dir=".hermes/faiss", embedding_dim=384)
)
await svc.index_and_persist(node)
top = await svc.query(embedding, workspace_id="ws1", top_k=5)
| Backend | Class | Use case | Install |
|---|---|---|---|
| Memory (default) | MemoryBackend |
Small corpora, zero-dep | — |
| Faiss | FaissBackend |
Large corpora, fast ANN | pip install faiss-cpu |
| SQLite-VSS | SQLiteVSSBackend |
Medium corpora, SQLite-native | pip install sqlite-vss |
Backends are swappable at construction time; the public API
(query(embedding, workspace_id, top_k)) never changes.
C — Plugin SDK CLI (plugins/sdk/cli.py)
A hermes console script (installed via [project.scripts]):
hermes plugin init myplugin # scaffold myplugin.py + plugin.yaml
hermes plugin watch ./plugins # hot-reload changed modules (polling, no watchdog)
hermes plugin list # list loaded plugins (name, version, caps, status)
hermes plugin validate ./myplugin # static check: manifest + compile + (--strict) deps
hermes plugin disable myplugin # unload from sys.modules + emit plugin.disabled event
The list / disable commands drive the kernel's own PluginRegistry
(kernel/registry.py) — there is exactly one registry. validate runs the
PluginValidator (manifest schema → py_compile → dependency resolution) with
no plugin execution. See ADR-010.
D — Desktop Control builtin plugin (plugins/builtin/desktop_control/)
Exposes host mouse / keyboard / screenshot control as kernel Tools under the
hermes.desktop capability (see ADR-011). Optional deps are installed via
the desktop extra:
pip install 'hermes-kernel-v2[desktop]'
| Tool | Params | Returns |
|---|---|---|
mouse_move |
x: int, y: int |
{"ok": bool} |
mouse_click |
button: str="left", clicks: int=1 |
{"ok": bool} |
key_press |
key: str |
{"ok": bool} |
type_text |
text: str, interval: float=0.01 |
{"ok": bool} |
screenshot |
`region: list[int] | None = None` |
Design: DesktopControlPlugin(BasePlugin); every tool is async and offloads
the blocking pyautogui call via asyncio.to_thread (event loop never blocked).
load() raises RuntimeError on unsupported platforms or missing deps. Tools
are registered into ToolRegistry via register_tools(tr) after load()
(import-side-effect free — no global SDK state needed).
E — MCP Streamable HTTP hardening (mcp/server_streamable.py)
Two durability / interoperability hardenings on top of ADR-008 (see ADR-012):
- Session TTL / eviction.
MCPServerStreamable(..., session_ttl=86400, evict_interval=3600)starts a background task that deletes persistedMcpSessionEventrows older thansession_ttlfrom eachmcp:<session_id>workspace (file-backed logs no longer grow unbounded).session_ttl=0disables eviction. Mcp-Protocol-Versionnegotiation. BothPOST /mcp/v1/messagesandGET /mcp/v1/eventsread the client'sMcp-Protocol-Versionheader. A match (or its absence — legacy client) is accepted and the server echoes its version on every response; a mismatch yields426 Upgrade Requiredadvertising the supported version. Default server version:2024-11-05.
F — Human Emulation Layer (plugins/builtin/human_emulation/, ADR-013)
Autonomous, human-like automation (browse sites, click, type) when the user is
away. Builtin plugin exposing 8 Tools under hermes.human.browser /
hermes.human.input:
BrowserAgent— async Playwright wrapper (visible browser):browser_start/navigate/click/type(human WPM + rare typos) /screenshot/close.InputSimulator— pyautogui with human-like micro-delays + occasional typos;FAILSAFE=True(cursor-to-corner aborts).HumanProfiledomain entity — the "digital twin" (typing speed, delays, screen resolution, user agent).BrowserSession+ActionLogentities give a full audit trail (workspace-isolated, ADR-007).
Optional deps behind the [human] extra (playwright, pyautogui); the kernel
imports cleanly without them (lazy import + clear RuntimeError).
Quick start
# 1. create / activate a Python 3.11+ virtualenv, then install
python -m pip install -e .
# 2. run the test suite
python -m pytest tests/ -v
# 3. run with coverage
python -m pytest tests/ --cov=kernel --cov=plugins --cov=mcp --cov-report=term-missing
Expected: 209 passed, 3 skipped (sqlite-vss has no Windows wheels → 3 retrieval-backend tests skip; they pass on Linux).
Note: always invoke pytest as
python -m pytestso it resolves against the active venv interpreter (a barepip/pytestmay bind to a different Python).
Repository layout
hermes-kernel-v2/
├── kernel/ # core (domain, bus, registry, capability, executor, workspace, retrieval)
├── plugins/
│ ├── base.py # BasePlugin ABC
│ ├── loader.py # fault-tolerant plugin loader
│ ├── sdk/ # declarative authoring SDK (@agent/@tool/@on_event/@capability)
│ └── builtin/ # example plugins (filesystem)
├── mcp/ # client.py, server.py, server_sse.py, server_streamable.py, tools.py
├── tests/ # 174 tests across 17 suites
├── docs/
│ ├── adr/ # architectural decision records
│ └── roadmap.md # phase status + coverage
└── pyproject.toml
Architecture
Decisions are recorded as ADRs:
- ADR-001 — Kernel Architecture — layers, Clean Architecture, async/lock, event-driven.
- ADR-002 — Plugin System —
BasePlugin, loader,plugin.yamlmanifest, Plugin SDK. - ADR-003 — MCP Integration —
MCP client/server,
MCPToolAdapter. - ADR-004 — Knowledge Pipeline — 5 event-driven stages, workspace isolation, similarity linking.
- ADR-005 — Multi-tenancy — Auth (P5.1), RBAC (P5.2), Persistent Storage (P5.3).
- ADR-007 — Workspace Isolation — formal data-isolation contract (persistence, graph, retrieval, scanner, RBAC).
- ADR-008 — Streamable HTTP Transport —
POST /mcp/v1/messages + GET /mcp/v1/events,
Mcp-Session-Idheader, batches. - ADR-009 — Retrieval Backends — Memory / Faiss / SQLite-VSS pluggable backends behind a stable API.
- ADR-010 — Plugin CLI UX —
list/validate/disabledriving the singlePluginRegistry. - ADR-011 — Desktop Control —
builtin
DesktopControlPluginexposing mouse/keyboard/screenshot ashermes.desktopTools (lazypyautogui/Pillow, async, platform-guarded). - ADR-012 — MCP Streamable HTTP hardening —
McpSessionEventTTL eviction (background task) +Mcp-Protocol-Versionnegotiation (426 on mismatch). - ADR-013 — Human Emulation Layer —
plugins.builtin.human_emulation: PlaywrightBrowserAgent+ pyautoguiInputSimulator+HumanProfile/BrowserSession/ActionLogentities. - ADR-016 — Agent/Plugin Unification —
BaseAgentasync lifecycle +AgentRuntime, unifiedArtifact(format/provenance/content: Any),CapabilityExecutor(namespaced dispatch →Artifact). - ADR-017 — Event Platform + Desktop Agent Vision —
kernel/events.py(DomainEvent extends Event + EventStore append-only + CQRS Command/Query Bus),DesktopAgent(BaseAgent)event-driven,DesktopVision(OCR + element detection),CapabilityExecutor.register_agent. - ADR-018 — Capability Handler Auto-Discovery —
kernel/discovery.py+CapabilityExecutor.autodiscover(instances): reflects over loaded plugin/agent instances and wires their capabilities (no plugin import, axis clean). Replaces manual bootstrap wiring. - ADR-019 — Workflow Runtime Foundation —
kernel/workflow.py(WorkflowEnginestate machine: retry/backoff, reverse-order compensation, human-approval PAUSE, input-mapping from prior steps),kernel/planner.py(goal→Workflow),Workflowdomain model replaces the stub + activates deadTask.workflow_id. 23 tests. - ADR-020 — Execution Sandbox —
kernel/sandbox.py(Sandbox.runsoft timeout/resource enforcement,TimeoutGuard,ResourceMonitorvia optionalpsutil); optional integration intoAgentRuntime/WorkflowEngine. 17 tests. - ADR-021 — Health & Recovery —
kernel/health.py(HealthMonitorliveness probes,DeadLetterQueuefor failed work,CircuitBreakerper-capability state machine,RecoveryEngineauto-restart/escalation); optional integration intoAgentRuntime/WorkflowEngine/CapabilityExecutor(backward-compatible). 40 tests. - ADR-022 — Behavior Engine —
plugins/builtin/desktop_control/behavior.py(BehaviorEngine: Bezier mouse curves + overshoot, scroll momentum, WPM typing rhythm with typos, gaze fixation + reading saccades/regressions) +human_profile.py(HumanProfileStoreCRUD + SQLite); optional integration intoDesktopAgent(desktop.click/type/scroll/read),UIElement.center*for targeting. 35 tests. - ADR-023 — Swarm / Teams — multi-agent
orchestration + distributed health:
kernel/swarm.py(SwarmCoordinator: create/join/leave, Bully leader election, heartbeat + suspicion/failure, capability-aware least-load delegation),kernel/distributed_health.py(DistributedHealthMonitor),kernel/team_manager.py(TeamManager),kernel/swarm_store.py(SwarmStorein-memory + SQLite); 8 swarm events; optional backward-compatible integration intoAgentRuntime/WorkflowEngine/CapabilityExecutor. 49 tests. - ADR-024 — Dynamic Planner — adaptive
replanning + risk-aware execution:
kernel/dynamic_planner.py(DynamicPlanner: DAG toposort, retry w/ exponential backoff, rule-based replan for 5 triggers + optional LLM shim,risk_assess),kernel/plan_store.py(PlanStorein-memory + SQLite), 6 planner events,WorkflowEngine.execute_adaptiveSwarmCoordinator.rebalance_load. 39 tests.
- ADR-025 — Knowledge Graph & Semantic Memory
— semantic memory:
kernel/semantic_graph.py(Entity/Relation/KnowledgeGraph models),kernel/knowledge_graph.py(KnowledgeGraphEngine: entities, relations, neighbor/path queries,similarvia injected embedding or Jaccard, rule-basedrun_inference),kernel/graph_store.py(SQLite), 6 KG events,AgentRuntime.remember/recall+WorkflowEngine.execute_with_context. 46 tests. - ADR-026 — Plugin Marketplace & Multi-node
—
kernel/marketplace_domain.py(PluginPackage/CatalogEntry/NodeInfo models),kernel/marketplace.py(PluginMarketplace: discover via injected http_client, install/uninstall, checksum+dependency validation,register_local),kernel/cluster.py(ClusterManager: join/leave, leader election, broadcast),kernel/marketplace_store.py(SQLite), 5 events,AgentRuntime.install_capability+WorkflowEngine.discover_plugins. 38 tests.
Roadmap
See docs/roadmap.md for full phase status.
| Phase | Name | Status |
|---|---|---|
| P0 | Kernel Core | ✅ |
| P1 | Runtime + Capability | ✅ |
| P2 | Knowledge Pipeline | ✅ |
| P3 | MCP + SDK | ✅ |
| P4 | MCP Server | ✅ |
| P5 | Multi-tenancy | ✅ |
| A | SSE transport | ✅ |
| B | KnowledgeRetrievalService | ✅ |
| C | Plugin SDK CLI | ✅ |
| D | ADR-007 Workspace Isolation | ✅ |
Authoring a plugin
from plugins.sdk import sdk, configure_sdk
from kernel.bus import EventBus
from kernel.registry import AgentRegistry, ToolRegistry
from kernel.capability import CapabilityRegistry
tr = ToolRegistry()
configure_sdk(
agent_registry=AgentRegistry(),
tool_registry=tr,
capability_registry=CapabilityRegistry(tr),
bus=EventBus(),
)
@sdk.agent(name="researcher", capabilities=["hermes.search"])
class Researcher:
@sdk.tool(name="web_search", capability="hermes.search",
schema={"type": "object", "properties": {"q": {"type": "string"}}})
async def search(self, q: str) -> list:
...
Researcher() # registration happens on construction
CI / Dependency axis gate
GitHub Actions (.github/workflows/ci.yml) runs on every push/PR to main,
matrix Python 3.11 + 3.12. Three gates, in order:
| Gate | Command | Threshold |
|---|---|---|
| Axis (Clean Architecture) | python -m tach check |
zero violations |
| Tests | python -m pytest tests/ |
228 passed, 0 failed |
| Coverage | pytest --cov --cov-fail-under=85 |
≥ 85% |
The axis contract (in [tool.tach] in pyproject.toml):
kernel.domain → [] (shared pydantic contract, leaf)
kernel → [kernel.domain]
plugins → [kernel, kernel.domain]
plugins.builtin.desktop_control → [kernel, kernel.domain, plugins] # explicit submodule
mcp → [kernel, kernel.domain]
tests / docs → excluded
kernel never imports plugins (the load_paths loader is injected, not
imported). kernel.domain is the common contract everyone may depend on.
Explicit submodules (e.g. plugins.builtin.desktop_control) are declared so
tach enforces the boundary transitively (submodules are not auto-inherited).
See CHANGELOG.md for the full release history.
Local run:
python -m pip install -e ".[dev]"
python -m tach check # dependency axis
python -m pytest tests/ # full suite
License
Internal / unreleased.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。