Screen MCP tool calls in Cursor

Cursor starts each MCP server you configure as a local process and talks to it over stdio. agent-chaperone goes in front of that process. It reads each tool call before the server gets it and each result before the agent does, and nothing about the server changes.

This page covers MCP servers. Cursor's own terminal commands, file edits and web fetches do not go through MCP, so the proxy does not see them. From 0.4.0, hooks you register in Cursor reach them instead, with limits set by what Cursor lets a hook do: the configuration is in the hooks reference.

Install it #

npm install -g agent-chaperone

A global install means Cursor starts the proxy directly. Running it through npx works too, but adds a package lookup every time a server starts.

Put a server behind it #

Cursor reads servers from ~/.cursor/mcp.json for every project and from .cursor/mcp.json inside one project, under mcpServers. The editor and the Cursor CLI read the same files.

agent-chaperone wrap makes the edit. It prints what it would change and writes nothing until you add --write, and it keeps the original beside the file.

agent-chaperone wrap ~/.cursor/mcp.json
agent-chaperone wrap ~/.cursor/mcp.json --write

A server entry before and after:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/project"]
    }
  }
}
{
  "mcpServers": {
    "filesystem": {
      "command": "agent-chaperone",
      "args": ["--server", "filesystem", "--",
               "npx", "-y", "@modelcontextprotocol/server-filesystem", "/Users/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 Cursor. --unwrap takes it all back out.

Give it the API key #

The model screens need TYPESAFE_API_KEY. A server started by Cursor gets the environment Cursor itself was started with, so a key exported in your shell profile reaches the proxy once Cursor has been restarted. Cursor's help says the same of any variable a server needs.

To keep the key out of your shell profile, put it in a file of NAME=value lines and point the entry at it with envFile, which Cursor supports for local servers:

"filesystem": {
  "command": "agent-chaperone",
  "args": ["--server", "filesystem", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/Users/me/project"],
  "envFile": "/Users/me/.config/agent-chaperone/env"
}

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

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.

Check that it is working #

The server should show as connected under Customize, then MCPs. If it does not, the Output panel's MCP Logs has what the process printed. In the CLI, agent mcp list shows the same status.

Then use the server 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. agent-chaperone log --follow prints them as they happen. A line ending in [not screened] was decided without a model, which means the key did not arrive; the proxy also says so in MCP Logs when it starts.

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.