---
title: "Codex MCP setup: config.toml and a browser server"
description: "Add an MCP server to OpenAI Codex: the config.toml entry, codex mcp add, how to check it loaded, and the errors Codex prints when it does not."
canonical: "https://scalebrowser.net/docs/agents/mcp-clients/codex"
last_modified: "2026-09-22T18:16:38.000Z"
---

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

# Codex MCP setup: config.toml and a browser server

> Add an MCP server to OpenAI Codex: the config.toml entry, codex mcp add, how to check it loaded, and the errors Codex prints when it does not.

Codex keeps its MCP servers in TOML rather than JSON, one table per server. Which transport it uses follows from which keys are present: a `url` means HTTP, a `command` means stdio.

The worked example is Scalebrowser's own server, which gives the agent a real browser on your machine. Any other HTTP MCP server takes the same entry with its own address.

## Before you start

Everything below assumes a daemon that is already running and a token to reach it with.

<CardGroup columns={2}>
  <Card title="Windows desktop app">
    The app starts the daemon for you. The token is the contents of
    `%LOCALAPPDATA%\Scalebrowser\token`, and the address it is listening on is the
    `native_addr` field of `%LOCALAPPDATA%\Scalebrowser\runtime.json`. That is usually
    `127.0.0.1:8787`, but the app moves up a port when something else already holds it.
  </Card>
  <Card title="Self-hosted daemon">
    `scalebrowser-daemon --generate-token` prints a token and stores it under
    `<data_dir>/token`. The address is whatever `bind_addr` says, which is `127.0.0.1:8787`
    unless you changed it. See [Install & run](/docs/install#the-api-token).
  </Card>
</CardGroup>

<Warning>

**The token is a full-power credential.** It reaches every profile, every stored session
and the whole management API. Treat it like a password: keep it out of a repository, and
prefer your client's environment-variable syntax over a literal in a config file that
gets committed.

</Warning>

## Add the server

`~/.codex/config.toml` applies everywhere. A `.codex/config.toml` inside a project applies there, but only once you have marked the project as trusted, and it wins over the global file. The Codex CLI, the IDE extension and the ChatGPT desktop app all read the same file.

```toml ~/.codex/config.toml
[mcp_servers.scalebrowser]
url = "http://127.0.0.1:8787/v1/mcp"
bearer_token_env_var = "SCALEBROWSER_TOKEN"
startup_timeout_sec = 20
tool_timeout_sec = 120
```

`bearer_token_env_var` names an environment variable rather than carrying the token, and
Codex sends its value as `Authorization: Bearer …`. Export it before you start Codex. A literal
`bearer_token = "…"` in the file is refused, so there is no way to commit the token by accident.

The CLI writes the same entry for you, always into the global file:

```bash
codex mcp add scalebrowser --url http://127.0.0.1:8787/v1/mcp \
  --bearer-token-env-var SCALEBROWSER_TOKEN
```

It leaves the two timeouts at their defaults, 10 seconds to start and 60 seconds per tool call. Add
them to the file afterwards.

<Note>

**A tool call can take longer than a default timeout allows.** `wait_for` waits for a page
to settle and `press_and_hold` holds a key for about ten seconds, so a per-tool ceiling
below roughly 120 seconds will cut off calls that were going to succeed.

</Note>

## Check that it loaded

- **CLI:** `codex mcp list` shows every configured server, and `codex mcp get scalebrowser` shows one. Inside a session, `/mcp` lists the tools each server exposes, `/mcp verbose` with detail.
- **IDE extension:** the gear menu, then **MCP servers**. After editing the file by hand, restart the extension.
- **ChatGPT desktop app:** **Settings**, then **MCP servers**, then restart the app.

Codex speaks stdio and Streamable HTTP, and a plain `http://` address on loopback is fine.

## When it does not load

| Codex says | What to do |
| --- | --- |
| ``Environment variable SCALEBROWSER_TOKEN for MCP server 'scalebrowser' is not set`` | The process that started Codex never saw the variable. An IDE or the desktop app does not read your shell profile; set it where that process starts, or start it from a shell that has it. |
| ``MCP client for `scalebrowser` timed out after 10 seconds`` | The daemon did not answer in time. Check it is running and that the port in `url` matches `native_addr` in `runtime.json`, then raise `startup_timeout_sec`. |
| ``MCP client for `scalebrowser` failed to start`` | Usually a wrong address or a stopped daemon. `curl http://127.0.0.1:8787/health` answers without a token and tells you which. |
| `bearer_token is not supported` | The file carries the token itself. Replace the line with `bearer_token_env_var`. |

A `401` in the details means the token reached the daemon and was refused: copy it again from the app.

## What the agent can do now

Ask it to open a page and it will lease a profile, bind a tab and start reading. The tool
set, the page map and the failure shapes are on [MCP server](/docs/agents/mcp-server); what the
agent is **allowed** to do is decided by the daemon, not by the client, so see
[tool profiles](/docs/agents/mcp-server#the-tool-set).
