> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runaether.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Repository MCP Config

> MCP servers committed in .mcp.json and .codex/config.toml work in Aether tasks as they do locally

Commit your team's MCP servers in the repository the way Claude Code and Codex read them, and Aether tasks get them too: Claude Code's `.mcp.json` and the `[mcp_servers]` tables of Codex's `.codex/config.toml`, on either harness. Aether reads both files through GitHub at the commit the task's base branch names when the task is created, and keeps that commit for the whole task. Values come from the project's [environment variables](/guides/environment-variables). The servers are the task's own: nothing is added to the organization's catalog.

An entry Aether cannot use never blocks a task: it is skipped, and the task is created and runs without it. Every skip is shown with its file, its server and why: in the composer before you send, on the task page, in the CLI's `aether task create` output, and as a line in the Slack and Linear replies that start the task. Only a `config.toml` server with `required = true` refuses the task instead.

## Remote servers

A server with a `url` (`"type": "http"` in `.mcp.json`) is reached over Streamable HTTP through Aether's MCP gateway, so its URL and headers never enter the workspace. `${VAR}` and `${VAR:-default}` in `.mcp.json`, and `bearer_token_env_var` and `env_http_headers` in `config.toml`, resolve from the project's environment variables. A server that sets no `Authorization` header and has the URL of a catalog server the project enables uses that server's connection, under the project's credential policy. A server that sets no `Authorization` and has no catalog server's URL is asked whether it needs a credential; if it does, it needs an org admin to add a catalog server with its URL. An optional server whose connection the task cannot use is skipped, saying whose connection is missing.

## Local (stdio) servers

A server with a `command` runs inside the task's workspace as a catalog local server does: Aether's workspace service starts the process and both harnesses reach it as one more MCP server. The harness never starts it.

### Supported commands

The command is a package runner with a package pinned to one release:

| Runs | `.mcp.json` | `.codex/config.toml` |
| - | - | - |
| An npm package | `"command": "npx", "args": ["-y", "@modelcontextprotocol/server-everything@2026.8.31"]` | `command = "npx"`<br />`args = ["-y", "@modelcontextprotocol/server-everything@2026.8.31"]` |
| A PyPI package | `"command": "uvx", "args": ["mcp-server-fetch@2025.4.7"]` | `command = "uvx"`<br />`args = ["mcp-server-fetch@2025.4.7"]` |
| `python -m` from a PyPI package | `"command": "uvx", "args": ["--from", "py-docs-mcp==0.3.1", "python", "-m", "py_docs_mcp"]` | `command = "uvx"`<br />`args = ["--from", "py-docs-mcp==0.3.1", "python", "-m", "py_docs_mcp"]` |

`-y` (or `--yes`) is optional for `npx`; `uvx --from <package>==<version> <package>` is the same as `uvx <package>@<version>`. Arguments after the package go to the server unchanged.

* **The version is pinned.** An npm package takes a full semver version (`1.2.3`), a PyPI package an exact PEP 440 version. A package with no version, `latest`, a tag, a range or a wildcard is skipped: the task would run whichever release is newest when it starts.
* **Other commands are skipped.** `node server.js`, `python -m …` without `uvx`, `docker`, `uv run`, a binary or script in the repository, a path to `npx`, and package-runner options other than the ones above.

### Environment

The process gets `PATH`, `HOME`, the npm and uv package caches, and the variables its file declares — nothing of the agent's environment, and none of the project's other environment variables.

* **`.mcp.json`:** each `env` value expands `${VAR}` and `${VAR:-default}` from the project's environment variables.
* **`.codex/config.toml`:** `env` values are used as written (Codex expands nothing in them). Each name in `env_vars` is set from the project's environment variable of that name, as Codex forwards it from the environment it runs in. A name may be in `env` or `env_vars`, not both.

A server referencing a variable the project does not set, with no default in the file, is skipped. A value that references a variable holds the project's environment variables, so it is a secret: it is masked wherever the server's output is logged. Literal values are not.

`command` and `args` never reference a variable — a project's environment variables reach a local server only through its `env`. A server with `cwd` in `config.toml` is skipped: a local server runs in the task's repository checkout.

<Warning>
  The process runs as the agent's user in the workspace. It cannot inherit the agent's environment, but it can read whatever the agent can read.
</Warning>

### Required and disabled servers

A `.mcp.json` server is optional; one with `"disabled": true` is left out. A `config.toml` server is optional unless it sets `required = true`, as Codex reads it; one with `enabled = false` is left out. An optional server Aether cannot use is skipped, and one that does not start within 90 seconds is left out of the turn, which runs without it. A required server Aether cannot use refuses the task at creation with the code `mcp_repo_config_invalid`, naming the file and the server, and fails a later turn the same way; one that does not start within 90 seconds fails the turn, naming it.

## When both files, or the organization, declare a server

* **The same name in both files** is one server when both declare the same URL and headers, or the same command, arguments and environment (`env_vars = ["TOKEN"]` in `config.toml` is the same as `"TOKEN": "${TOKEN}"` in `.mcp.json`). Two different declarations under one name are not one server: the task is given `.mcp.json`'s, and `config.toml`'s is skipped. Names become server keys as the harnesses write them into tool names, lowercased.
* **A name the organization's catalog already uses** is the organization's server: the task uses it instead, and its server list says why the repository's copy was not given.

## Skipped, and why

Each skip names its file and its server, or only the file when the file does not parse, and one of these reasons. The task runs without the server; fix the file or the project and the next task, or the task's next turn for a variable, gets it.

| Reason contains | Fix |
| - | - |
| `is not set in the project's environment variables, and the file gives no default` | Set the variable in the project, or give a default in `.mcp.json` |
| `its package "…" pins no version` / `must be a full semver version` / `must be an exact PEP 440 version` | Pin one release, as in `<package>@1.2.3` or `<package>==1.2.3` |
| `its command "…" is not one Aether runs` | Run the server through `npx` or `uvx` with its package |
| `references a variable` | Move the value into `env` |
| `its cwd "…" is a directory on the machine Codex runs on` | Remove `cwd` |
| `declares "…" under the same key "…"` | Declare the server alike in both files, or under different names |
| `it is not valid JSON` / `it is not valid TOML for Codex` (with its line) | Fix the file: nothing in it is read until it parses |
| `the "sse" transport cannot reach a task` | Declare the server's Streamable HTTP endpoint with `"type": "http"` |
| `it is a directory, not a file` / `it is larger than 1 MiB` | Commit the file as a file of at most 1 MiB |
| `it takes the connection of …, which the task's creator has not connected` (or `needs to reconnect`, or the organization) | Connect the catalog server in Settings → Integrations |
| `it needs a connection, and no catalog server this project enables has its URL` | An org admin adds a catalog server with its URL and enables it on the project |
| `Aether could not ask it whether it needs a connection` | The server did not answer; the next turn asks again |

A variable removed from the project after a task was created, or a connection that went away, leaves its server out of the task's next turn, and the task page names it as skipped; a connection made since gives the next turn the server again. A required server fails the turn instead, with `mcp_repo_config_invalid` and the same message.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.