Use
MCP servers
List your MCP servers once in fenzi.yaml and every agent gets them: Claude Code, Codex, OpenCode, and Grok, each in its own config format. Inside the sandbox, every call to a remote server is checked against the tools you listed for it, and a server's token stays outside the sandbox, the way a model key does.
Add a server
fenzi mcp add deepwiki https://mcp.deepwiki.com/mcp --tool read_wiki_structure --tool read_wiki_contentsName the server, give its URL, and list the tools agents may call, one --tool each. --all-tools allows every tool the server has, and --deny refuses one even then. The entry goes into the mcp section of ./fenzi.yaml:
version: 1
mcp:
deepwiki:
url: https://mcp.deepwiki.com/mcp
tools:
allow: [read_wiki_structure, read_wiki_contents]
linear:
url: https://mcp.linear.app/mcp
token: true
tools:
allow: [list_issues, get_issue, create_comment]
deny: [delete_issue]
files:
command: [npx, -y, "@modelcontextprotocol/server-filesystem", /sandbox]The next fenzi run gives the servers to the agent. Agents read their MCP servers when they start, so a change applies to a new sandbox, not to one already running.
A server that needs a token
fenzi mcp token linearPaste the token at the prompt; it is not shown. Fenzi stores it in the sandbox runtime on this machine, never in a file. The server's entry says token: true; fenzi mcp add --token writes that. Inside the sandbox the agent holds a placeholder, and the runtime puts the real token only on requests to that server. Sent anywhere else, it stays a placeholder.
Servers that sign you in with OAuth, such as Linear, GitHub, or Notion, can also take a personal API token this way. If the agent runs the server's OAuth sign-in itself, that token is kept in the agent's own files inside the sandbox, where the agent can read it.
What the sandbox checks
Each remote server gets a rule the sandbox enforces on every request: the methods a client sends to connect and list what the server offers, the tools you allowed, and the tools you denied. Anything else is refused with HTTP 403 policy_denied. Only the agent's own program reaches the server.
13:33:38 allowed POST mcp.deepwiki.com/mcp tools/list
13:33:48 allowed POST mcp.deepwiki.com/mcp tools/call read_wiki_structure
13:33:50 denied POST mcp.deepwiki.com/mcp tools/call read_wiki_contentsThe log names the tool of every call. The agent's error does not: it says POST /mcp not permitted by policy. Some requests are refused on every connection and are routine: Claude Code and Grok first try server/discover, then connect the usual way, and clients close a session with a DELETE the rule does not allow.
The policy check before start does not cover MCP rules: the policy prover cannot read them. Fenzi checks them itself, and fenzi run says so on its mcp line.
Local servers
fenzi mcp add files -- npx -y @modelcontextprotocol/server-filesystem /sandboxA server with a command runs inside the sandbox as a child of the agent, with the agent's limits on files, processes, and network. Its traffic with the agent is a pipe, so it is not checked per tool. Hosts it calls need to be in the policy's hosts. A server that has to run on your machine, outside the sandbox, is not supported.
For every project, or one
fenzi mcp add --machine writes to ~/.config/fenzi/mcp.yaml, for the servers you use in every project. A project's fenzi.yaml adds its own and can narrow one the machine file has: fewer tools, more denied. It cannot widen it. On a machine signed in to a team, the servers come from the team's policy.
fenzi mcp listLists the servers agents get in this folder, where each one comes from, and whether its token is stored.
Import from .mcp.json
fenzi mcp importCopies the servers in .mcp.json or .cursor/mcp.json into fenzi.yaml. Remote servers come in with every tool allowed, so narrow each one afterwards. A token in a header is not copied; store it with fenzi mcp token. Inside the sandbox the agent uses Fenzi's list and ignores its own files, so what it can call is what the policy says.
fenzi mcp import --dry-runShows the servers an import would add, the ones it would leave because fenzi.yaml already has them, and the tokens it would not copy. It writes nothing. With --json it prints the same as one document.
When the agent asks for a tool
An agent may file a request for an MCP server through the sandbox. Fenzi does not approve it: in OpenShell 0.1.2 an approved MCP request allows every tool on that server, not the one it named (NVIDIA/OpenShell#4679). fenzi approve says so, and a Team approval in the console is turned into a rejection with that reason. Add the tool to the server's entry instead and start a new run.
Limits
- An allowed tool gets any arguments the server accepts.
- What a server sends back is not checked. A tool result can carry instructions to the agent; the sandbox limits what the agent can then do, not what it reads.
- Only servers over Streamable HTTP get per-tool rules.
- One server per host and port, and an MCP server cannot share its host and port with a host in
hosts. - Tested end to end with Claude Code: an allowed tool call went through and a tool not listed was refused. Codex connected and listed the server's tools in a sandbox; a tool call from Codex has not been run yet. OpenCode and Grok get the same servers in their own config formats; their runs in a sandbox are next.