Documentation v0.3.2
Earshot / Extending

MCP servers

Connect stdio and HTTP tools without bypassing permissions.

Reviewed for 0.3.2 · Latest documentation

Five ways to add behaviour: MCP servers, in-process extensions, skills, slash commands and hooks. All five are content that ends up in front of a model or a shell, and all five are designed on the assumption that the other side is hostile or broken.

The rule they share: nothing here can grant a permission. A skill, a hook and an MCP server can each tell earshot to do something, and each of those things goes through the same gate a request typed by the user does. What they cannot do is approve it.

The ACP server is another consumer of these boundaries, not a bypass around them. An editor can display and answer a permission request, but cannot turn a deny into an allow. MCP servers configured for an ACP session are still loaded through earshot's trust and permission rules; client-provided MCP process definitions are currently rejected.

MCP servers#

Configured under mcpServers in settings, in the shape Claude Code uses:

{
  "mcpServers": {
    "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] },
    "linear": { "type": "http", "url": "https://mcp.linear.app/mcp", "headers": { "Authorization": "Bearer …" } }
  }
}

stdio and streamable HTTP. The pre-2025 sse transport is not supported and is reported rather than ignored.

Tools are namespaced server__tool, so two servers cannot collide, and a server name may not itself contain __ — one that could would be able to impersonate another server's tools.

Past 25 MCP tools, they are not listed in the prompt. Instead the model gets one tool_search tool and finds them by what it wants to do. A search surfaces at most ten at a time and they stay listed for the rest of the session. Nothing about the gate changes: a surfaced tool is permission-checked exactly as it would have been had it been listed all along, and tool_search itself grants nothing.

An MCP tool is never read-only. A server's readOnlyHint is an assertion by the same party that wrote the tool, so earshot displays it and does not believe it: every MCP call is serialised and gated. Rules name one tool, not one server:

{ "permissions": { "allow": ["Mcp(github__search_issues)"], "deny": ["Mcp(github__create_*)"] } }

A server the project checked in does not start on its own. A stdio server named in .earshot/settings.json is code the repository chose, and starting the process it names is running that code. It is listed with an explanation until you run earshot mcp trust <name>, which records approval in .earshot/settings.local.json — not committed, so a repository cannot trust itself in the next clone. Servers you define globally or locally start normally.

A server that fails to start, hangs, dies mid-session or floods its output is reported and skipped; the session runs with the tools it does have.

CommandEffect
earshot mcp listWhat is configured, and which servers are not started
earshot mcp trust <name>Allow a project-scope server to start
earshot mcp untrust <name>Withdraw that
Something unclear?Suggest a correction on GitHub ↗