Screen tool calls in Hermes Agent

Hermes Agent starts each MCP server in its configuration as a local process and talks to it over stdio. agent-chaperone goes in front of that process, and a plugin puts the same screens in front of the tools Hermes runs itself: its terminal, its file edits and its web fetches.

This page covers both. The plugin needs 0.4.0 or later, and so does wrap for Hermes's YAML configuration.

Install it #

npm install -g agent-chaperone

A global install means Hermes starts the proxy directly, and it is where the plugin below finds the command and its own files.

Put a server behind it #

Hermes reads servers from ~/.hermes/config.yaml, under mcp_servers. agent-chaperone wrap makes the edit. It prints what it would change and writes nothing until you add --write, keeps the original beside the file, and writes back only the entries it changed, so the comments in the file stay.

agent-chaperone wrap ~/.hermes/config.yaml
agent-chaperone wrap ~/.hermes/config.yaml --write

A server entry before and after:

mcp_servers:
  filesystem:
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/me/project"]
mcp_servers:
  filesystem:
    command: agent-chaperone
    args:
      - --server
      - filesystem
      - --
      - npx
      - -y
      - "@modelcontextprotocol/server-filesystem"
      - /home/me/project

Everything after -- is the server that would have run anyway. --server names the section of the policy file that applies, after the name you gave the server in Hermes. Keys such as env, timeout and enabled are kept as they were. --unwrap takes it all back out.

Give it the API key #

The model screens need TYPESAFE_API_KEY. Hermes does not hand a server its own environment: a stdio server gets a short list of safe variables, such as PATH and HOME, plus whatever the entry's env names. A key exported in your shell does not reach the proxy on its own.

Put the key in ~/.hermes/.env and name it in the entry. Hermes fills in ${...} from that file when it starts the server, so the key itself stays out of config.yaml:

mcp_servers:
  filesystem:
    command: agent-chaperone
    args: ["--server", "filesystem", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/home/me/project"]
    env:
      TYPESAFE_API_KEY: "${TYPESAFE_API_KEY}"

The proxy removes its own keys before it starts the server behind it, so the server never receives TYPESAFE_API_KEY.

Without a key the proxy still starts, the deterministic rules still run, and every judgment records that no model was asked. It never refuses to start because a key is missing.

Screen Hermes's own tools #

The terminal, file edits and web fetches Hermes runs itself never cross an MCP connection. A plugin reaches them. Hermes ignores what a shell hook prints after a tool has run, so only a plugin can change what the model reads, and this one hands each call and each result to agent-chaperone hook pre and hook post. It ships in the npm package:

cp -R "$(npm root -g)/agent-chaperone/integrations/hermes" ~/.hermes/plugins/agent-chaperone
hermes plugins enable agent-chaperone

Hermes loads no plugin until it is enabled, which is what the second line does. It adds the name to plugins.enabled in config.yaml, and you can write that by hand instead.

A held call goes to Hermes's own approval prompt. Its "always" answer is remembered for that exact call, so it never allows every later use of the tool. Hermes approves the prompt by itself when approvals.mode is off or YOLO mode is on, and refuses the call when nobody is there to answer.

A result judged unsafe is withheld: the plugin hands Hermes a notice in place of the tool's result. The tools it screens, and what each command answers, are in the hooks reference. MCP tools are left to the proxy, so a wrapped server is not screened twice.

The plugin starts the command with Hermes's own environment, which includes ~/.hermes/.env, so the key from the step above reaches it too.

Check that it is working #

hermes mcp test filesystem
hermes plugins list

The first connects to the wrapped server, which starts the proxy in front of it. If it fails, hermes logs mcp shows what the process printed. The second should show agent-chaperone as enabled.

Then use the server and the terminal once from the agent, and read what was decided:

agent-chaperone log

Each line is one call or result, with the decision and, in shadow mode, what enforcing would have done instead. Calls from the plugin are recorded under the server name built-in. A line ending in [not screened] was decided without a model, which means the key did not arrive.

What this does not cover #

Next #

It starts in shadow mode, which blocks nothing. The MCP guide covers what each screen asks, how to read a shadow-mode log, and when to switch to enforce. The exact wording of every question is in the design document.