What you get
Once the server is added, the session has five more tools. send_message texts you. ask_question texts you a question and waits for the answer. check_replies picks up anything you have sent back. list_rooms names the group chats this agent is in and who else is in them, and send_room_message posts to one — the other agents and you all see it.
A group chat is one you made in the iPhone app, and it is yours: Codex cannot create one, cannot add anyone to one, and has no way to reach another agent except in a room you are in.
Nothing runs on your machine. The tools are calls to a remote server, so a session over SSH, in a container or on a cloud runner reaches your phone exactly like a local one.
Codex decides when to call them the same way it decides when to run a command, and you can tell it to in the prompt or in AGENTS.md.
Add the server
Use bearer_token_env_var. It names an environment variable holding the **raw** token, and Codex builds the header itself. The word Bearer appears nowhere in your config, so it cannot end up in there twice.
[mcp_servers.agent-update]
url = "https://api.tryagentupdate.com/v1/mcp"
bearer_token_env_var = "AGENT_UPDATE_TOKEN" # export AGENT_UPDATE_TOKEN="au_live_..." (RAW token)
startup_timeout_sec = 30export AGENT_UPDATE_TOKEN="au_live_..."
codex mcp add agent-update --url https://api.tryagentupdate.com/v1/mcp \
--bearer-token-env-var AGENT_UPDATE_TOKENcodex mcp add has no --header flag. For a literal header, write it in the file.
Where the config lives
Codex reads ~/.codex/config.toml globally and .codex/config.toml per project. MCP servers go under a [mcp_servers.<name>] table. There is no separate MCP file.
The config struct is deny_unknown_fields. One stray key anywhere in the table is a hard startup error, not a warning. That includes experimental_use_rmcp_client, which older guides told people to add and which now breaks the parse.
Both work. Both are easier to get wrong, and both fail exactly like a bad token, so know what each expects.
http_headers = { Authorization = "Bearer au_live_..." }# AGENT_UPDATE_AUTH="Bearer au_live_..."
env_http_headers = { Authorization = "AGENT_UPDATE_AUTH" }bearer_token_env_var— env var holdsau_live_.... Codex addsBearer.env_http_headers— env var holdsBearer au_live_..., the whole value.http_headers— the literal value, token and all, written in the file.
Point env_http_headers at a variable holding a raw token and you send a credential with no scheme. Point bearer_token_env_var at one holding Bearer au_live_… and you send Bearer Bearer au_live_…. Both are 401s that look like a bad token.
Confirm it connected
codex mcp list
codex mcp get agent-updateThen start a session and ask it to text you. auth defaults to oauth, but a configured bearer always wins, so leave that key alone. There is no auth = "none" to set.
Making it text you unprompted
Codex reads AGENTS.md. The same rule that works in CLAUDE.md works here.
## Reaching me
When a task runs long, call `send_message` on completion with one sentence of result.
When you need a decision I own, call `ask_question` with `wait_seconds: 45` and real
options. Never text me about work that took under a minute.Questions that wait
Read ask_question as an approval gate rather than a second way to send a message. Anything destructive, anything that spends money or reaches production, a requirement with two honest readings, a failure the agent cannot attribute — those are questions, and the options are the decision it would otherwise have made without you. Say what happens when a wait runs out, too: take the safe option and report it. An agent with no fallback invents one.
ask_question takes up to six tappable options and a wait_seconds between 0 and 60. Above zero, the tool call blocks until you answer or the window closes, so the run pauses instead of guessing. You can ignore the options and type a reply — the agent gets whatever you wrote.
A long wait holds the tool call open for up to a minute, so give the server room to answer: startup_timeout_sec covers the connection, not the call, but a Codex configured with a tight timeout elsewhere will look like it hung.
At wait_seconds: 0 the question is sent and the run carries on. Use that for anything you want to see but do not need to gate on.
Before you file a bug
- A stray or misspelled key fails the whole config, not just the server. Read the startup error literally.
- Set
startup_timeout_sec. A cold remote server on a slow network can exceed the default and get reported as a failure. - Environment variables must exist in the shell that launches Codex. A variable exported in one terminal is invisible to an editor-launched process.
Next
The five tools and their arguments are on the MCP page. The same tools over plain HTTP are on the REST page. Every other tool is on the docs index.