# Codex MCP server setup and continuity test

Connect Codex CLI, the Codex IDE extension, or the ChatGPT desktop app to
Handover's remote Streamable HTTP MCP server, verify the authenticated
boundary, and prove a fresh Codex agent can retrieve and continue exact source
context.

Canonical guide:
https://handover.sh/guides/codex-mcp-server-setup

Handover endpoint:
https://handover.sh/api/mcp?profile=core

Official Codex MCP documentation:
https://developers.openai.com/codex/mcp

## What a passing setup proves

1. Codex has a valid remote MCP configuration.
2. Codex completes Handover's browser OAuth flow or loads the intended service
   credential.
3. A protected call resolves the expected human or service identity.
4. Reads stay inside that identity's authorized boundary.
5. An approved private handoff can be created and read back exactly.
6. A separately authenticated successor can retrieve and continue it.
7. Missing, denied, read-only, stale, and revoked paths remain constrained.

`codex mcp add`, a server in `codex mcp list`, an OAuth label, or a visible
tool list proves only an earlier checkpoint.

## 1. Choose human OAuth or a service identity

Use browser OAuth when a person is present. Handover attributes the resulting
MCP work to the signed-in person and preserves their company, workspace, role,
and access boundary.

Use a named service agent for an unattended runner. Create it with the minimum
workspace grants and scopes required for the job. For a two-agent continuity
test, use two distinct people, two distinct service agents, or one of each:

```text
Publisher: human OAuth session or codex-publisher
Successor: separate human OAuth session or codex-successor
```

Never paste an OAuth access token or service credential into a prompt,
repository, handoff, screenshot, analytics event, install URL, or this file.

## 2. Choose global or project scope

Codex reads MCP configuration from:

```text
Global, private to this Codex host:
~/.codex/config.toml

Project, inherited after the repository is trusted:
.codex/config.toml
```

The ChatGPT desktop app, Codex CLI, and Codex IDE extension share the same MCP
configuration on one host.

Prefer the global file for a personal OAuth connection. A project file may
describe the server and, for unattended automation, an environment-variable
name, but it must not contain a populated credential. Review the repository and
its collaborators before trusting project configuration.

ChatGPT web does not read these local files. Hosted ChatGPT uses plugins.

## 3. Add the remote server

This lifecycle was validated with `codex-cli 0.146.0` against production on
2026-08-04:

```bash
codex mcp add handover \
  --url "https://handover.sh/api/mcp?profile=core"
```

Codex detects Handover's OAuth metadata and opens browser authorization. Sign
in to Handover, review the person, company, and requested scopes, then choose
**Connect agent**. If authorization does not start automatically:

```bash
codex mcp login handover
```

Codex writes:

```toml
[mcp_servers.handover]
url = "https://handover.sh/api/mcp?profile=core"
```

Codex stores the OAuth session separately from `config.toml`.

## 4. Inspect the saved state

```bash
codex mcp list
codex mcp get handover
```

Require:

```text
name: handover
enabled: true
transport.type: streamable_http
transport.url: https://handover.sh/api/mcp?profile=core
auth: OAuth
```

Important: `Auth: OAuth` describes the configured authentication method. It
does not prove the grant maps to the intended person, company, workspace, role,
or scopes. `handover.whoami` is the identity boundary.

Inside Codex, use `/mcp` to inspect the active server and tools.

## 5. Verify the live OAuth boundary

The production verification completed this sequence:

```text
1. Protected-resource discovery
2. Authorization-server discovery
3. Dynamic client registration
4. Browser consent
5. Authorization code + PKCE exchange
6. Authenticated handover.whoami call
7. OAuth logout and grant revocation
```

The clean Codex profile stored no static Handover bearer header. It resolved
the approving person and company through `handover.whoami`.

## 6. Configure an unattended service agent

For a runner where no person can complete browser consent:

```bash
read -s HANDOVER_TOKEN
export HANDOVER_TOKEN

codex mcp add handover-service \
  --url "https://handover.sh/api/mcp?profile=core" \
  --bearer-token-env-var HANDOVER_TOKEN
```

The service definition stores only the environment-variable name. Start Codex
from the environment that contains it. Rotate the service credential if it
appears in a transcript, issue, screenshot, analytics event, or handoff.

## 7. Verify identity before reading

Ask Codex:

```text
Call Handover's identity tool. Show the server-resolved principal, company,
workspace, role, and scopes. Stop if any value differs from the expected
codex-publisher identity.
```

Expected operation:

```text
handover.whoami
```

Never accept identity or workspace values supplied only in prompt text.

## 8. Verify protected reads

Expected operations:

```text
handover.search
handover.get
handover.read_artifact
```

Search for a known private record, open its canonical revision, and read one
exact source artifact. Pass only when the record is in the expected workspace,
the artifact matches the canonical source, and a denied record remains hidden.

## 9. Create and read back one private handover

Ask before the first write. Create a disposable private handoff with a unique
marker:

```text
CODEX-MCP-SETUP-2026-08-04-01
```

Attach:

```markdown
# Codex MCP verification

- Marker: CODEX-MCP-SETUP-2026-08-04-01
- Objective: prove authenticated publish and read-back
- Constraint: private to the test workspace
- Next action: retrieve from codex-successor
```

Expected operations:

```text
handover.create
handover.get
handover.read_artifact
```

Pass only when the server attributes the revision to `codex-publisher`,
visibility remains private, and the exact artifact is retrievable from the
canonical revision.

## 10. Prove successor continuity

Use an isolated Codex home or a second installation. Complete browser OAuth as
the successor, or configure the separate `codex-successor` service credential:

```bash
export CODEX_HOME="/path/to/isolated-codex-home"

codex mcp add handover \
  --url "https://handover.sh/api/mcp?profile=core"
```

Give the successor only the stable link or marker, not the publisher's
conversation.

Ask:

```text
Verify your identity, find this handoff, read the current source artifact,
state the exact marker, and continue the bounded next action using the current
expected revision. Read the result back.
```

Expected operations:

```text
handover.whoami
handover.search
handover.get
handover.read_artifact
handover.annotations
handover.continue
handover.get
```

Pass only when the server reports the successor identity, the exact artifact
is retrieved, the marker comes from that artifact, the write uses
`expectedRevisionId`, and the new revision records the successor as author.

## 11. Run negative tests

### Logged-out OAuth session

Log out in a disposable Codex profile:

```bash
codex mcp logout handover
```

A protected call must fail. Do not accept a configured server as proof that an
OAuth session is present.

### Rejected credential

Use a dedicated invalid test credential. A protected call must return 401.
The server must not guess or reuse another actor.

### Denied workspace

An identity without the test workspace grant must not discover titles,
summaries, artifacts, annotations, or counts.

### Read-only scope

A read-only identity may inspect granted context but must not create, continue,
annotate, assign, archive, or delete.

### Stale revision

Continue with an obsolete `expectedRevisionId`. The server must reject the
write until the agent reads and reconciles the current revision.

### Revoked credential

Log out an OAuth profile or revoke a dedicated test agent, then call
`handover.whoami` again. The old grant or credential must fail even if Codex
still has a local server entry.

### Untrusted project

Place only the non-secret server definition in `.codex/config.toml` inside a
disposable repository. Codex must not silently load project configuration
before the repository is trusted.

### Hosted ChatGPT boundary

Open ChatGPT web without the Handover plugin. The local Codex MCP entry must
not appear there. This is expected isolation, not a connection failure.

## 12. Diagnose explicit states

```text
Server listed, protected call fails
  Run codex mcp login handover and complete browser consent.

401 Unauthorized
  Reconnect OAuth or rotate the named service credential.

403 Forbidden
  Inspect whoami, workspace grants, role, and scopes.

Project server unavailable
  Review the repository before trusting project configuration.

ChatGPT web has no Handover tools
  Install the hosted plugin. Local Codex config is not shared with the web.

Tools visible, search returns nothing
  Verify whoami and search a known unique marker.

Write conflict
  Read the current revision, reconcile, and retry only with approval.
```

## 13. Remove local and remote access

For browser OAuth, revoke the grant and remove local configuration:

```bash
codex mcp logout handover
codex mcp remove handover
codex mcp list
```

For an unattended profile, revoke the named service agent in Handover, unset
`HANDOVER_TOKEN`, and remove the local server entry.

Local removal alone does not revoke a remote service credential. Complete
service-agent offboarding requires both, plus a protected call proving the old
credential now fails.

## 14. Record the result

```markdown
# Codex MCP setup result

- Codex CLI version:
- Configuration scope: global | project
- Authentication: human OAuth | named service agent
- Handover endpoint:
- Publisher identity:
- Successor identity:
- Workspace:
- Publisher revision:
- Successor revision:
- Exact artifact read-back passed:
- Logged-out or missing-credential path passed:
- Rejected credential passed:
- Denied workspace passed:
- Read-only scope passed:
- Stale revision passed:
- Revocation passed:
- Local removal passed:
- Hosted ChatGPT boundary recorded:
- Overall result: PASS | FAIL
- First failing checkpoint:
- Evidence:
```

Mark the workflow `PASS` only after the second authenticated identity retrieves
the exact source artifact and creates a verified successor revision.
