clermes-mcp

clermes-mcp

Exposes a Clermes worker fleet as typed tools over HTTP and stdio, enabling a coordinator to drive the fleet with structured tool calls.

Category
Visit Server

README

clermes-mcp

An MCP server that exposes a Clermes worker fleet as typed tools over HTTP and stdio.

Clermes is a file-based coordination harness for a fleet of long-lived coding-agent workers. The bash dispatcher at canopy-workshop/clermes is the source of truth for tmux and session state. clermes-mcp is a thin Python shell over that dispatcher, so a coordinator that speaks MCP (Hermes, Claude, an editor MCP client, anything) can drive the fleet with structured tool calls instead of scraping panes and writing poll loops.

clermes-mcp is an enhancement, not a requirement. The clermes CLI is fully usable on its own. This server is the integration layer that makes a Clermes fleet a first-class citizen in multiagent workflows.

The reference worker is Claude Code. The reference coordinator is Hermes. Any other coding agent (Codex, Aider, antigravity, opencode) and any other MCP-speaking coordinator fit the same harness. Nothing about the protocol or this server is agent-specific.

What you get

  • Typed read tools for fleet inventory, pane capture, lock and dispute inspection.
  • Typed action tools (operator role only) for dispatch, respawn, reply, halt, spawn, kill, fleet-wide heal.
  • Blocking or async per call. The client picks. Blocking returns the done file inline. Async returns a job id and the caller polls.
  • Auto-heal before send. If a worker pane is in bash, dead, or some other state, dispatch kills and respawns it before sending.
  • Anti-compact resend. After dispatch, the server watches for the conversation-compacted-then-idle pane state and re-sends the brief once if it sees the swallow signature.
  • Role gating. operator exposes the full surface. worker exposes read tools only. A worker-role MCP client cannot see dispatch or kill at all. The gate is structural: the action tools are never registered in that role.
  • No outbound to humans. The server never exposes a tool that contacts humans. I treat that as a fixed invariant of the project. Don't fork it back in.

Install

pip install clermes-mcp

You also need:

  • The clermes bash dispatcher on your PATH (or at $CLERMES_HOME/clermes).
  • tmux and jq on the host running the worker fleet.
  • A worker fleet (Claude Code, or any equivalent CLI agent with an interactive TUI).

Configure

Everything resolves from environment variables. Defaults work for a typical install at ~/.clermes.

Setting Env var Default
Clermes home CLERMES_HOME ~/.clermes
Dispatcher bin CLERMES_BIN $CLERMES_HOME/clermes, then $(which clermes)
Bind host CLERMES_MCP_HOST 127.0.0.1
Bind port CLERMES_MCP_PORT 9675
Bearer token CLERMES_MCP_TOKEN unset (server warns on HTTP transport)
Role CLERMES_MCP_ROLE operator
Default mode CLERMES_MCP_MODE blocking

If $CLERMES_HOME/voice-preamble.txt exists, its contents prepend to dispatches with public_artifact=true. Otherwise a neutral default applies. The preamble is the right place to put your repo's voice rules. Don't bake them into the server.

config.yaml under $CLERMES_HOME is read if present, for the paths.home override only. Every other field is informational.

Run the diagnostic check:

clermes-mcp doctor

It verifies paths, the dispatcher, the registry, and protocol directories.

Run

HTTP (recommended for multiagent integration):

clermes-mcp serve --transport http --host 127.0.0.1 --port 9675

stdio (for local subprocess clients):

clermes-mcp serve --transport stdio

To inspect the schema for every tool:

clermes-mcp tools

Run as a service

Drop the unit file at examples/clermes-mcp.service into ~/.config/systemd/user/ and enable it:

systemctl --user daemon-reload
systemctl --user enable --now clermes-mcp
journalctl --user -u clermes-mcp -f

On systems where user-systemd lingering is unreliable (WSL across wsl --shutdown, some headless setups), use whatever your platform's session-supervisor of choice is. A simple cron @reboot line works too. tmux is a last resort because the MCP server has no TTY needs.

Wire into a coordinator

The reference is Hermes:

mcp_servers:
  clermes:
    url: "http://127.0.0.1:9675/mcp"
    headers:
      Authorization: "Bearer ${CLERMES_MCP_TOKEN}"
    timeout: 1800
    connect_timeout: 30

A 30-minute timeout lines up with the blocking ceiling on long dispatches. For async use, the request returns immediately with a job id and the timeout can drop to anything.

Other MCP-speaking coordinators wire in the same way.

Tool surface

Read tools (every role):

  • list_workers(): flat list of {name, state, alive, locked, task_id?, workdir}.
  • fleet_snapshot(): full per-worker pane text and classification.
  • capture(worker, lines=80): pane tail with classification.
  • worker_health(worker): claude | bash | dead | other:<proc>.
  • list_open_tasks(): lock files joined with the assigned-task map.
  • read_dispute(task_id): raw markdown of a dispute file, or null.
  • read_result(task_id): parsed JSON of a done file, or null.
  • list_done(limit=50): recent completed task ids.
  • list_jobs() / job_status(job_id) / job_result(job_id): async job plumbing.

Action tools (operator role only):

  • dispatch(worker, brief, slug?, wait=true, mode=blocking, timeout=1800, public_artifact=false, auto_heal=true, anti_compact_resend=true): the headline tool.
  • respawn(worker): kill then spawn (the dispatcher's heal is fleet-wide; this is the single-worker equivalent).
  • spawn(worker) / kill(worker) / heal_fleet(): direct dispatcher wrappers.
  • reply(worker, message, wait_for_task_id?, mode=blocking, timeout=1800): send without a new TASK_ID footer. Use to answer a dispute or select an injection-dialog option.
  • halt(task_id): touch the halt file so an announced action does not proceed past its grace window.

Security model

  • Bind localhost by default. 127.0.0.1:9675. Don't bind 0.0.0.0 without a reverse proxy and a token in front of it.
  • Bearer token auth on HTTP. Set CLERMES_MCP_TOKEN and require it on every HTTP request. Without it the server logs a warning at startup and accepts anything.
  • Role gating. CLERMES_MCP_ROLE=worker strips every action tool from the registered surface. A worker-role MCP client cannot see, let alone call, dispatch or kill.
  • No outbound to humans. Nothing in the tool surface contacts email, SMS, agencies, webhooks, or chat. Adding one breaks the threat model of this project; don't do it.
  • No shell=True anywhere. All subprocess calls pass argv as a list. Briefs are arbitrary text and cannot escape the process boundary.
  • Token redaction in error strings surfaced to the client.

Layout

clermes-mcp/
├── README.md
├── LICENSE
├── pyproject.toml
├── .env.example
├── src/clermes_mcp/
│   ├── __init__.py
│   ├── __main__.py        CLI entry point
│   ├── server.py          FastMCP app, tool registration, transport wiring
│   ├── dispatcher.py      async subprocess wrapper around the bash CLI
│   ├── protocol.py        file I/O for done/dispute/announce/halt/locks/assigned
│   ├── pane.py            pane-text classification heuristics
│   ├── jobs.py            in-process async job registry
│   ├── config.py          env + optional config.yaml loader
│   ├── doctor.py          diagnose paths, dispatcher, deps
│   └── models.py          pydantic schemas
├── tests/                 pytest suite, all hermetic against the stub
├── examples/
│   ├── stub-clermes       fake dispatcher for CI and demo
│   ├── clermes-mcp.service systemd --user unit
│   └── hermes-config.snippet.yaml
└── docs/PROTOCOL.md       generic coordination contract

Testing

pip install -e ".[dev]"
pytest
ruff check src tests

Every test runs against examples/stub-clermes. No live fleet, no tmux. CI on its own can validate the full server surface.

Status

Pre-1.0. The tool surface is stable enough to ship, but expect minor breakage in tool names and arg shapes until the integration with at least two coordinators settles.

License

MIT.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured