# MCP servers Codey is an MCP client over stdio. Servers go in the config by hand, in the same shape Claude Code and Codex use, so an entry can be carried across from either unchanged: ```json { "mcp_servers": { "fs": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] }, "db": { "command": "my-db-mcp", "env": { "DB_URL": "postgres://localhost/dev" } } } } ``` Each server is started once, when the session opens, in the working root, and every tool it lists is offered as `mcp____` — the name being the key you gave it, not whatever the server calls itself. Subagents get the same tools from the same processes. Every call prompts like `bash` does, with "always this tool" to stop asking. A server that is not installed, does not answer within thirty seconds or speaks a protocol version Codey does not is reported at startup and left out; the session goes on without it. A server that dies later is not restarted, and its tools say so when called. Only tools are used: not resources, prompts or sampling, and no HTTP transport. Pictures a tool returns are described to the model rather than shown. A server's directory is fixed when it starts, so after `/worktree` it is still serving the root the session began in. `-no-mcp` starts none of them for one run — Codey's own and Claude Code's alike. ## Claude Code's servers The servers Claude Code already knows about are started as well, read from where Claude Code keeps them rather than copied into Codey's config: | Where | Whose | Started | | --- | --- | --- | | `~/.claude.json`, under `projects[""].mcpServers` | yours, for this project — what `claude mcp add` writes | always | | `.mcp.json` at the working root | the repository's, committed | once you [trust it](#trusting-a-project) | | `~/.claude.json`, top-level `mcpServers` | yours, for every project — `claude mcp add -s user` | always | The shape is the one already shown above, `{"mcpServers": {name: {command, args, env}}}`, with `"type": "stdio"` accepted and meaning the same thing. A server with `"type": "http"` or `"sse"`, or with a `url`, is a remote server; Codey's client speaks only stdio, so it is reported at startup and skipped. `${VAR}` and `${VAR:-default}` are expanded in the command, the arguments and the env values, as Claude Code expands them — so a `.mcp.json` can say `"${DB_URL}"` and leave the secret in your environment. A variable that is unset and has no default skips that server with a notice naming it, rather than starting it with a hole in its command line. When two places define a server of the same name, Codey's own `mcp_servers` win, and after that the table is read top to bottom: your per-project servers, then the repository's, then your global ones. That is Claude Code's own order, so a name means the same program in both. Each clash is reported once, naming the one that won, because a server that quietly turned out to be a different program is not something anyone thinks to debug. ### Trusting a project A `.mcp.json` comes from the repository. Starting a server listed there means running a command — with your environment, your credentials, your network — that whoever wrote the repository chose, before the agent has done anything and outside every approval prompt. So, like Claude Code, Codey asks first. The first interactive start in a checkout whose `.mcp.json` or shared `.claude/settings.json` [allow rules](claude-code-settings.md) would grant something prints, before the TUI opens: ``` Claude Code's configuration for /home/you/src/thing would: start these MCP servers, from .mcp.json: db: npx -y @acme/db-mcp --url ${DB_URL} (env: DB_TOKEN) run these without asking, from .claude/settings.json: Bash(make:*) These files come from the repository, not from you: trusting them lets it choose commands this machine runs. Your answer is remembered until they change. Trust them for this checkout? [y/N] ``` One question covers both files, because it is one question: do you trust what this repository says about itself. The full command line is shown because that is the thing being agreed to. The answer — yes or no — is remembered for this checkout against a fingerprint of exactly those definitions, as written, before any `${VAR}` is expanded. A new server, a changed argument or one more allow rule is a different fingerprint, and the question comes back; nothing else does. A refusal is remembered too, so saying no once is not a question at every start. The record is kept in `~/.config/codey/trust.json`, not in the project's `.codey/` directory with the rest of the per-repository state. That is the point of it: anything inside the working tree can arrive with a clone, and a repository that shipped its own record of being trusted would be approving its own servers. The fingerprint would be no defence there — whoever wrote the `.mcp.json` can compute it. Only a file the repository cannot reach can say what you decided. Where nobody can be asked — `-p`, `codey agent stdio`, a piped stdin — an undecided project's servers are not started and its allow rules are ignored, with a line on stderr saying so. A checkout you have already trusted needs nothing more. `-trust-project` says yes for one run without asking and without recording anything, which is what a CI job against a repository you control wants. Servers in `~/.claude.json` never ask: you put them there, as you put Codey's own in its config. Once started, every server's tool calls go through the approval prompts like any other, unless an allow rule such as `mcp__db` says otherwise.