herdr-mcp
# herdr-mcp
An [MCP](https://modelcontextprotocol.io) server that exposes a running
[Herdr](https://herdr.dev) session to MCP clients such as Grok Bot, Claude
Desktop, or any other app that speaks the protocol.
Herdr is a terminal workspace manager for coding agents. It organizes
terminals into workspaces, tabs and panes, recognizes the agent running in
each pane, and tracks whether it is idle, working, blocked on a dialog, or
done. This server lets a desktop assistant see all of that and act on it:
read what Claude Code or Codex is doing in your terminal, hand them a prompt,
wait for them to finish, run commands in new panes, and react to lifecycle
events as they happen.
## How it works
- Every control tool is a typed wrapper over the `herdr` CLI, so name
resolution, `--wait` semantics and protocol compatibility stay Herdr's job.
- A background **event tap** holds one `events.subscribe` connection open on
Herdr's Unix socket. It buffers every event with a monotonic sequence number
and subscribes to `pane.agent_status_changed` for each pane, resubscribing
when new panes appear. Clients poll with `events_recent` or block with
`events_wait`.
- Mutating tools carry MCP annotations (`readOnlyHint`, `destructiveHint`) so
clients can gate them with per-tool permissions.
## Requirements
- Herdr 0.9 or newer, with a server running for the session you want to
expose (start it with `herdr` or `herdr server`).
- Python 3.12 or newer and [uv](https://docs.astral.sh/uv/).
## Install
```sh
git clone https://github.com/frysquint/herdr-mcp.git ~/git/herdr-mcp
cd ~/git/herdr-mcp
uv sync
uv run herdr-mcp --help
```
`uv sync` creates `.venv/bin/herdr-mcp`, an absolute entry point that needs
no shell setup. That is the path to hand to desktop clients, which often run
with a minimal `PATH`.
## Grok Bot
Open Grok Bot settings, go to **MCP servers**, add a server, and paste:
```json
{
"mcpServers": {
"herdr": {
"command": "/home/USER/git/herdr-mcp/.venv/bin/herdr-mcp",
"args": []
}
}
}
```
Replace `USER` with your login. Grok Bot accepts one server per paste.
If you prefer to run through uv instead of the venv entry point:
```json
{
"mcpServers": {
"herdr": {
"command": "/absolute/path/to/uv",
"args": ["run", "--project", "/home/USER/git/herdr-mcp", "herdr-mcp"]
}
}
}
```
## Other MCP clients
Claude Desktop, Claude Code, Codex and most others take the same
`command`/`args` shape. For Claude Code:
```sh
claude mcp add herdr -- /home/USER/git/herdr-mcp/.venv/bin/herdr-mcp
```
To serve over HTTP instead of stdio (for remote clients or several clients
sharing one tap):
```sh
uv run herdr-mcp --transport streamable-http --host 127.0.0.1 --port 8765
```
The endpoint is `http://127.0.0.1:8765/mcp`. There is no authentication; keep
it on loopback or put it behind something that authenticates.
## Configuration
All configuration is through the environment of the server process.
| Variable | Effect |
| -------------------- | ------------------------------------------------------------------- |
| `HERDR_BIN_PATH` | Path to the `herdr` binary. Default: first `herdr` on `PATH`. |
| `HERDR_SESSION` | Target a named Herdr session instead of the default one. |
| `HERDR_SOCKET_PATH` | Low-level override of the socket path (CLI and event tap). |
| `HERDR_MCP_MACHINE` | Run every command against a saved SSH machine profile (`herdr --machine`). Live events are disabled in this mode because there is no local socket for that machine. |
| `HERDR_MCP_LOG_LEVEL`| Log level written to stderr. Default `INFO`. |
## Tools
Read-only: `herdr_status`, `session_snapshot`, `workspace_list`,
`workspace_get`, `tab_list`, `pane_list`, `pane_get`, `pane_layout`,
`pane_process_info`, `pane_read`, `pane_wait_output`, `agent_list`,
`agent_get`, `agent_explain`, `agent_read`, `agent_wait`, `worktree_list`,
`events_status`, `events_recent`, `events_wait`.
Mutating: `workspace_create`, `workspace_focus`, `workspace_rename`,
`tab_create`, `tab_focus`, `tab_rename`, `pane_split`, `pane_run`,
`pane_send_text`, `pane_send_keys`, `pane_rename`, `agent_prompt`,
`agent_send_keys`, `agent_start`, `agent_rename`, `agent_focus`,
`worktree_create`, `notification_show`.
Destructive: `workspace_close`, `tab_close`, `pane_close`.
### Event kinds
Broadcast events from Herdr, in underscore form: `workspace_created`,
`workspace_updated`, `workspace_metadata_updated`, `workspace_renamed`,
`workspace_moved`, `workspace_reordered`, `workspace_closed`,
`workspace_focused`, `worktree_created`, `worktree_opened`,
`worktree_removed`, `tab_created`, `tab_closed`, `tab_focused`,
`tab_renamed`, `tab_moved`, `pane_created`, `pane_closed`, `pane_updated`,
`pane_focused`, `pane_moved`, `pane_exited`, `pane_agent_detected`,
`layout_updated`.
Per-pane subscription events: `pane_agent_status_changed` with
`agent_status` one of `idle`, `working`, `blocked`, `done`, `unknown`.
Synthetic events from the tap itself: `tap_connected`, `tap_disconnected`,
`tap_events_lost`. If you see `tap_events_lost`, re-read state with
`session_snapshot`; Herdr does not replay missed events.
### A typical delegation loop
1. `agent_list` to find a ready agent (status `idle` or `done`).
2. `events_recent` with `limit: 0` to learn `latest_seq`.
3. `agent_prompt` with `wait: true`, or send it with `wait: false` and then
`events_wait` with `since_seq`, `kinds: ["pane_agent_status_changed"]`,
`pane_id`, and `agent_status: ["done", "blocked", "idle"]`.
4. `agent_read` to collect the response. If the status was `blocked`, show the
user the dialog text before answering it with `agent_send_keys`.
## Development
```sh
uv run pytest
uv run herdr-mcp --log-level DEBUG # speaks MCP on stdin/stdout
```
The unit tests fake the `herdr` binary and do not need a running server.
## License
MIT. See `LICENSE`.
TDQS
Scored across 41 tools
The set is strongly segmented by resource prefix (workspace_, tab_, pane_, agent_, events_, worktree_), and repeated actions such as list/get/create/close target explicit resources. The closest overlaps are pane_read vs agent_read and pane_send_keys vs agent_send_keys, plus the several input tools, but descriptions make the intended conditions clear.
All names use snake_case with a resource/domain prefix, and nearly all are resource_action forms like workspace_list, pane_read, and agent_prompt. Exceptions such as herdr_status, session_snapshot, and events_status are readable status/snapshot nouns and do not break the overall convention.
41 tools is heavy for any single MCP server; even though the terminal/workspace/agent domain is broad, many fine-grained pane/agent input, read, and wait variants could be consolidated or parameterized. The count exceeds the reasonable 3-15 range and sits in the 'too many' band.
Core lifecycle is covered: workspaces, tabs, and panes can be created, listed, renamed, focused, and closed; agents can be started, prompted, waited on, and read; events and worktrees have support. Gaps remain for pane_focus/resize, agent_stop, tab_get, and worktree_remove, though terminal access and close operations provide workarounds.