Table of Contents

OpenAI Codex (CLI, Desktop App, IDE Extension)

Warning

Under construction: The time cockpit MCP server and this documentation are under active development, and breaking changes are possible. Tools may be renamed, changed or removed, and dialog labels and configuration steps may change without notice. Check back for updates before rolling the setup out to your users, and expect to adapt your configuration, skills and prompts after an update.

Codex reads MCP servers from %USERPROFILE%\.codex\config.toml (global; CODEX_HOME) or from .codex\config.toml in the project. CLI, desktop app and IDE extension share this file — a server registered once is visible everywhere. The configuration below is in production use and works.

Note

Terminal output shown on this page is illustrative. Version numbers, callback IDs and tool counts vary.

Install and Sign In to Codex

npm install -g @openai/codex
codex --version
codex login

Alternatively install the Codex desktop app, which includes the CLI. codex login signs in to your ChatGPT account — not to be confused with the MCP sign-in below.

No file has to be edited. codex mcp add writes the server to the global config.toml, accepts your client ID directly and — as soon as it finds OAuth metadata on the server — starts the sign-in flow immediately. One command, one browser sign-in, done:

codex mcp add timecockpit --url https://mcp.timecockpit.com --oauth-client-id <client-id>
codex mcp list
Added global MCP server 'timecockpit'.
OAuth callback URL: http://127.0.0.1/callback/XuuuHAzzHOni
Detected OAuth support. Starting OAuth flow…
Opening browser to authenticate with timecockpit...
✔ Successfully logged in to MCP server timecockpit

Name          Url                          Bearer Token Env Var  Status   Auth
timecockpit   https://mcp.timecockpit.com  -                     enabled  OAuth

Tenant, sandbox and modes are passed as URL segments rather than headers, so no TOML editing is required. To change the URL of an existing entry, remove it and add it again. Note that the callback ID in the redirect URI is derived from the complete server URL, so a changed URL (additional segments, or the preview environment) results in a new "OAuth callback URL" that has to be registered on your app registration before the sign-in succeeds — see Callback URL Specifics. You also have to sign in again, because tokens are stored per server URL:

codex mcp remove timecockpit
codex mcp add timecockpit --url https://mcp.timecockpit.com/tcTenantId/<tenant-id>/access/readonly/scope/owndata --oauth-client-id <client-id>

Lifecycle commands:

Command Purpose
codex mcp add <name> --url <url> --oauth-client-id <id> Create the server; prints the "OAuth callback URL" and starts sign-in. Further flags: --oauth-client-registration AUTO\|CIMD\|DCR, --oauth-resource, --bearer-token-env-var
codex mcp login <name> Start sign-in (again), e.g. after expiry or logout; --no-browser for servers/WSL, --scopes only if the server does not advertise the scope
codex mcp list [--json] Status and auth (OAuth, Not logged in, Bearer token, Unsupported)
codex mcp get <name> Show a server's configuration
codex mcp logout <name> Delete stored OAuth credentials
codex mcp remove <name> Remove the server
Note

Limits of the CLI route: codex mcp add has no flags for static HTTP headers or a fixed callback port (it writes http_headers = None, callback_port = None). Headers are unnecessary thanks to URL segments. The callback port is ephemeral on this route, so the Entra registration must accept http://127.0.0.1/callback/<id> with any port (loopback rule per RFC 8252 §7.3). If sign-in fails because of the redirect URI, or if you need a real header, use Option B.

Option B: config.toml (Headers, Fixed Port)

You can also maintain the file directly. This is useful for a fixed callback port (64485, as with Claude Code), a real header, or a project-level .codex/config.toml (e.g. created by apm install).

Section in %USERPROFILE%\.codex\config.toml:

[mcp_servers.timecockpit]
url = "https://mcp.timecockpit.com"
http_headers = { "X-tc-tenant-id" = "<tenant-id>" }   # optional, see connection settings
enabled = true

[mcp_servers.timecockpit.oauth]
client_id = "<client-id>"
callback_port = 64485

Then run codex mcp login timecockpit. Keys at a glance:

Key Meaning
url Streamable HTTP endpoint (required)
http_headers Static headers; also sent during OAuth discovery
env_http_headers Headers whose value comes from an environment variable, e.g. { "X-tc-tenant-id" = "TC_TENANT_ID" }
bearer_token_env_var Alternative to OAuth: static token from an environment variable
enabled, required, startup_timeout_sec, tool_timeout_sec Activation, required server for codex exec, timeouts (defaults 10 s / 60 s)
scopes, oauth_resource Optional: explicit scopes or RFC 8707 resource — with Entra only when needed (see troubleshooting)
oauth.client_id Client ID of your app registration ("always takes precedence and skips client registration")
oauth.callback_port Fixed loopback port; takes precedence over the global mcp_oauth_callback_port
oauth.callback_url Written by codex mcp add; the registered callback URL (see below)
mcp_oauth_callback_port, mcp_oauth_callback_url (top level) Global fixed port or alternative redirect URI for all servers
mcp_oauth_credentials_store (top level) auto (default: keyring, otherwise file), keyring, file (CODEX_HOME/.credentials.json)

The former experimental flag experimental_use_rmcp_client is no longer needed. Codex has no client_secret — it is always a public client with PKCE.

Authentication: CLI, TUI, App

CLI (standard route): With Option A the sign-in happens during add; afterwards you can repeat it at any time:

codex mcp login timecockpit
codex mcp login timecockpit --no-browser    # prints the URL; paste the redirect URL back
codex mcp login timecockpit --scopes https://mcp.timecockpit.com/mcp.access    # only if the server does not advertise the scope
Starting local callback server on http://127.0.0.1:64485 ...
Opening browser to authenticate with timecockpit...
If the browser does not open, visit:
https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?client_id=<client-id>&redirect_uri=http%3A%2F%2F127.0.0.1%3A64485%2Fcallback%2FXuuuHAzzHOni&response_type=code&code_challenge_method=S256...
✔ Successfully logged in to MCP server timecockpit

With --no-browser, Codex prints the URL and asks you to paste the final redirect URL (http://127.0.0.1:64485/callback/<id>?code=…&state=…) back into the terminal.

In the TUI: /mcp shows the servers with auth status (Not logged in / OAuth) and their tool list, but does not start the sign-in itself — run codex mcp login in a second shell.

MCP servers

• timecockpit  https://mcp.timecockpit.com
  Auth: OAuth (logged in)
  Tools: ping, get_current_user, get_entities, describe_entity, execute_tcql_query, get_timesheets, create_timesheet, … (16)

Use /mcp verbose for details. To (re)authenticate run: codex mcp login timecockpit

Desktop app: Settings → Integrations and MCP (depending on version: Plugins → MCPs). If a server requires OAuth, the app offers an Authenticate button. After a CLI sign-in, an already open thread has to be restarted.

Tokens are stored in the Windows Credential Manager (keyring), with ~/.codex/.credentials.json as fallback. codex mcp logout timecockpit deletes them.

Verify

codex mcp list
codex mcp get timecockpit
Name          Url                          Bearer Token Env Var  Status   Auth
timecockpit   https://mcp.timecockpit.com  -                     enabled  OAuth

timecockpit
  url: https://mcp.timecockpit.com
  http_headers: { X-tc-tenant-id = <tenant-id> }
  oauth.client_id: <client-id>
  oauth.callback_port: 64485
  enabled: true

Then follow Verify the Connection.

Callback URL Specifics

Codex always binds the callback listener to 127.0.0.1 (not localhost). If the authorization server metadata does not report authorization_response_iss_parameter_supported — which is the case with Entra ID — Codex appends a 12-character ID derived from the complete server URL (host and all path segments) to the path: http://127.0.0.1:<port>/callback/<id>. Consequently https://mcp.timecockpit.com, https://mcp.timecockpit.com/access/readonly and https://mcp-preview.timecockpit.com each have a different callback ID and each need their own redirect URI on the app registration. The exact value is printed by codex mcp add … --oauth-client-id ("OAuth callback URL") and stored in oauth.callback_url. Exactly this value must be registered on your app registration; 127.0.0.1 URIs can only be added in the Entra portal via the app manifest (replyUrlsWithType, type InstalledClient) — see Entra ID Setup. With Option A the port is ephemeral, so register the URI without a port; with Option B and a fixed callback_port, register it with the port.

Troubleshooting

Message / symptom Cause / solution
Dynamic client registration not supported oauth.client_id is missing. Use --oauth-client-id.
Entra: redirect URI does not match The callback URL (see above) is not registered on your app registration, or is registered as Web instead of Mobile and desktop / InstalledClient.
AADSTS9010010 / invalid_target Entra rejects the resource parameter because it does not match the scope. Do not set oauth_resource; if needed set scopes = ["https://mcp.timecockpit.com/mcp.access"] explicitly.
Port 127.0.0.1:64485 is already in use Another process holds the port (e.g. a simultaneous Claude Code sign-in). Wait, or choose a different port for Codex.
Desktop app shows OAuth authorization required despite CLI sign-in Restart the thread or the app.
Browser does not open (server, WSL) codex mcp login timecockpit --no-browser