Skip to main content
Glama

herdr-mcp

npm CI License: MIT

MCP server for herdr: one read-only tool per herdr method, over streamable HTTP with a bearer token.

Contents

Related MCP server: herdr-mcp

What it does

  • Serves one MCP tool per read-only herdr structure method. The tool name is herdr_ plus the method with dots turned into underscores (pane.list becomes herdr_pane_list). Every tool is annotated readOnlyHint: true, destructiveHint: false and idempotentHint: true.

  • Terminal content, long-poll methods, event subscriptions, writes, control and admin methods are never exposed. The tool set is computed from the herdr SDK's method table (ADR-0001).

  • Streamable HTTP transport with MCP protocol versions 2025-11-25, 2025-06-18 and 2025-03-26. Tools only: no resources, prompts or sampling.

  • Every request must carry Authorization: Bearer <token>. The server listens on loopback (127.0.0.1) by default.

Prerequisites

  • Bun 1.4.4 or later. The server uses Bun's HTTP server, so it does not run on Node. Check with bun --version.

  • A running herdr server with its unix socket. The socket is resolved in this order: HERDR_MCP_SOCKET, then the SDK's own resolution (HERDR_SOCKET, then ~/.config/herdr/herdr.sock). The SDK targets herdr 0.9.5 (socket protocol 22).

The server starts without a herdr socket. Tool calls then return an error result until herdr is reachable (see Exit codes and failure modes).

Install

bun add -g @stateforge-labs/herdr-mcp

The package provides the herdr-mcp command. Bun runs its TypeScript source directly, so there is no build step. Development checks are described in CONTRIBUTING.md.

Usage

Start the server:

herdr-mcp

It prints the listen address and nothing else:

herdr-mcp: listening on http://127.0.0.1:7423

On the first start the bearer token is created in the token file (see Configuration). The token is never printed. Read it with:

cat ~/.local/state/herdr-mcp/token

A minimal call: initialize a session, then call a tool. The session ID comes back in the Mcp-Session-Id response header.

TOKEN="$(cat ~/.local/state/herdr-mcp/token)"
H=(-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
   -H "Accept: application/json, text/event-stream" -H "MCP-Protocol-Version: 2025-11-25")

SID=$(curl -s -D - -o /dev/null http://127.0.0.1:7423/mcp "${H[@]}" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"example","version":"0.0.0"}}}' \
  | tr -d '\r' | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}')

curl -s http://127.0.0.1:7423/mcp "${H[@]}" -H "Mcp-Session-Id: $SID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"herdr_workspace_list","arguments":{}}}'

Sample output (abridged; the workspace names and IDs depend on your herdr):

{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\"type\":\"workspace_list\",\"workspaces\":[{\"workspace_id\":\"w1\",\"number\":1,\"label\":\"example\",\"focused\":true,\"pane_count\":1,\"tab_count\":1,\"active_tab_id\":\"w1:t1\",\"agent_status\":\"unknown\"}]}"}]}}

Tool arguments are checked against each tool's input schema before herdr is called. Unknown keys and missing required keys are rejected with isError: true and a text that starts with invalid params:.

Configure a client

The server speaks streamable HTTP only. Clients that support only stdio servers cannot connect to it directly. Keep the token in your environment, not in a file that is committed.

Claude Code

Put this in the project's .mcp.json:

{
  "mcpServers": {
    "herdr": {
      "type": "http",
      "url": "http://127.0.0.1:7423/mcp",
      "headers": { "Authorization": "Bearer ${HERDR_MCP_TOKEN}" }
    }
  }
}

Export the token in the shell that starts the client:

export HERDR_MCP_TOKEN="$(cat ~/.local/state/herdr-mcp/token)"

VS Code

Put this in .vscode/mcp.json, with HERDR_MCP_TOKEN exported in the environment VS Code starts from:

{
  "servers": {
    "herdr": {
      "type": "http",
      "url": "http://127.0.0.1:7423/mcp",
      "headers": { "Authorization": "Bearer ${env:HERDR_MCP_TOKEN}" }
    }
  }
}

Change the port in url if HERDR_MCP_PORT is set.

Tools

All tools take a JSON object and reject keys that are not listed (additionalProperties: false). string or null parameters accept null to mean "not given". Every tool has readOnlyHint: true, destructiveHint: false and idempotentHint: true. On success a tool returns herdr's result as structuredContent and as JSON text in content; a non-object result is wrapped as { "result": ... }. On failure it returns isError: true with a text.

Tool

herdr method

Inputs

herdr_ping

ping

none

herdr_server_agent_manifests

server.agent_manifests

none

herdr_session_snapshot

session.snapshot

none

herdr_workspace_list

workspace.list

none

herdr_workspace_get

workspace.get

workspace_id (required): string

herdr_worktree_list

worktree.list

cwd: string or nulltrust_repository: booleanworkspace_id: string or null

herdr_tab_list

tab.list

workspace_id: string or null

herdr_tab_get

tab.get

tab_id (required): string

herdr_agent_list

agent.list

none

herdr_agent_get

agent.get

target (required): string

herdr_agent_explain

agent.explain

target (required): string

herdr_pane_layout

pane.layout

pane_id: string or null

herdr_pane_process_info

pane.process_info

pane_id: string or null

herdr_layout_export

layout.export

pane_id: string or nulltab_id: string or null

herdr_pane_neighbor

pane.neighbor

direction (required): string, one of left, right, up, downpane_id: string or null

herdr_pane_edges

pane.edges

pane_id: string or null

herdr_pane_list

pane.list

workspace_id: string or null

herdr_pane_current

pane.current

caller_pane_id: string or null

herdr_pane_get

pane.get

pane_id (required): string

herdr_pane_link_resolve

pane.link.resolve

col (required): integerviewport_row (required): integerpane_id (required): stringcontent_revision: integer or nulloffset_from_bottom: integer or null

herdr_integration_list

integration.list

none

herdr_plugin_list

plugin.list

plugin_id: string or null

herdr_plugin_action_list

plugin.action.list

plugin_id: string or null

herdr_plugin_log_list

plugin.log.list

limit: integer or nullplugin_id: string or null

The table is generated from the method table of @stateforge-labs/herdr-sdk. A method is listed when its class is a structure read (R-meta), it is not a long poll, and it is not events.subscribe.

Configuration

The program reads only environment variables. A bad value stops the program with a message that names the setting, never its value.

Variable

Default

Meaning

HERDR_MCP_HOST

127.0.0.1

Interface to listen on. Keep it on loopback unless something else guards the port.

HERDR_MCP_PORT

7423

TCP port, 1 to 65535.

HERDR_MCP_TOKEN_FILE

$XDG_STATE_HOME/herdr-mcp/token, else $HOME/.local/state/herdr-mcp/token

The bearer token file. Created with mode 0600 in a 0700 directory when it is missing, empty or malformed.

HERDR_MCP_SOCKET

unset

The herdr socket path. When unset, the SDK uses HERDR_SOCKET, then ~/.config/herdr/herdr.sock.

A malformed token file is replaced at startup, so every client must read the token again after a restart.

Exit codes and failure modes

The program exits with status 1 on every startup failure. No other exit status is defined.

Situation

What you see

Exit

HERDR_MCP_PORT is not an integer from 1 to 65535

HERDR_MCP_PORT must be an integer from 1 to 65535

1

No token path can be derived (HERDR_MCP_TOKEN_FILE, XDG_STATE_HOME and HOME all unset)

set HERDR_MCP_TOKEN_FILE, XDG_STATE_HOME or HOME: there is nowhere to keep the token

1

The token file cannot be read or written

herdr-mcp: the token file could not be read or written

1

The port is already in use

Failed to start server. Is port 7423 in use?

1

The herdr socket is missing or unreachable

The server still starts. A tool call returns isError: true with herdr unreachable: the call got no usable answer or herdr call failed. The next call tries to connect again.

server keeps running

A tool call has invalid arguments

isError: true, text starts with invalid params:

server keeps running

The bearer token is missing or wrong

HTTP 401 with an empty body

server keeps running

Security scope

  • What an agent that holds the token can read: the structure reads in the Tools table. These cover workspaces, tabs, panes, agents, layouts, integrations and plugins, plus process information for panes (pane.process_info) and plugin logs (plugin.log.list). Those last two can contain data from your session, so check them before you expose the port.

  • What it cannot do: write, send input, run actions, read terminal content, open event subscriptions, or call admin methods. None of these methods is in the tool set.

  • Network: the server listens on 127.0.0.1 by default. Setting HERDR_MCP_HOST to another interface exposes it to that network. The server speaks plain HTTP with no TLS, so the bearer token is the only guard, and it crosses the network unencrypted.

  • Token: kept in a 0600 file inside a 0700 directory. Compared in constant time. Never logged or printed. The listen line and the request log are disabled. To rotate it, stop the server, delete the token file and start the server again.

To report a vulnerability, see SECURITY.md.

Run as a service

systemd/herdr-mcp.service is a user unit with the sandboxing and loopback defaults described above. It starts ~/.bun/bin/herdr-mcp, the command that bun add -g installs by default. Install the package, copy the unit from the installed package to ~/.config/systemd/user/, then run:

bun add -g @stateforge-labs/herdr-mcp
mkdir -p ~/.config/systemd/user
cp ~/.bun/install/global/node_modules/@stateforge-labs/herdr-mcp/systemd/herdr-mcp.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now herdr-mcp

If Bun is installed somewhere else, or BUN_INSTALL is set, change the ExecStart path in the copied unit to the herdr-mcp command that bun add -g installed.

Use as a library

The package exports the server, its HTTP layer and the auth helpers. Import them from @stateforge-labs/herdr-mcp:

Export

What it is

HerdrMcpLive(options)

A layer that serves the read-only herdr tools over authenticated MCP streamable HTTP.

READ_ONLY_METHOD_NAMES

The herdr method names exposed as tools.

McpHttpLive(options, registrations, handlers)

The generic MCP HTTP server with the bearer check.

tokenFile({ path })

Read-or-create the bearer token file. readOrCreate() returns the token.

bearerGuard(token)

A function that checks an Authorization header in constant time.

ensureOwnerDir(path)

Creates a directory with mode 0700.

toolNameOf(method)

The MCP tool name for a herdr method.

MCP_PATH, MCP_SERVER_NAME, MCP_SERVER_VERSION

The endpoint path (/mcp) and the server identity.

A runnable host program, the same as src/main.ts without the environment reading:

import { Effect, Layer } from "effect"
import { HerdrMcpLive, tokenFile } from "@stateforge-labs/herdr-mcp"

const token = await tokenFile({ path: "/absolute/path/to/token" }).readOrCreate()
const server = HerdrMcpLive({ host: "127.0.0.1", port: 7423, token })

await Effect.runPromise(Layer.launch(server) as Effect.Effect<never, unknown, never>)

Run it with bun run host.ts in a project that depends on the package, where host.ts is the file above. Pass socketPath to HerdrMcpLive to use a socket other than the default.

Support

Ask questions and report bugs in GitHub issues. For security problems, use SECURITY.md instead of a public issue.

License

MIT. See LICENSE.

Maintainers

Maintained by stateforge-labs.

Contributing

See CONTRIBUTING.md for how to report bugs, set up the project, and propose changes.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables controlling a Hermes Agent instance from any MCP client, exposing a broad set of Hermes CLI operations over MCP Streamable HTTP with bearer auth.
      MIT
    • A
      license
      B
      quality
      B
      maintenance
      Enables MCP clients to remotely control a running Herdr session: see agent status, arrange tabs and panes, start and prompt coding agents, and run worktree-isolated jobs over stdio or Streamable HTTP. Includes policy controls such as allowlists, read-only mode, disabled tools, and an audit log.
      32
      2
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Lets MCP clients such as Claude Code, Cursor, and Claude.ai inspect and drive herdr workspaces, panes, and coding agents over a local socket, running either as a local stdio process or as an OAuth-protected HTTP endpoint published through a Cloudflare Tunnel. It exposes tools to create workspaces and tabs, split panes, start and prompt agents, read their output, and wait for results.
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables clients to discover and read authorized vessel telemetry, state snapshots, and historical data, and to inspect and invoke approved read-only core or plugin operations over Streamable HTTP. It reuses the existing Signal K bearer tokens, permissions, and staleness/ACL checks, requiring no extra account, key, listener, or container.
      378 npm
      MIT