# Connect coding clients to the MCP lab The optional `mcp` profile serves the gateway at `https://mcp.localtest.me/mcp`, with its OAuth broker at `https://mcp.localtest.me/`. Sign in through the local Pharos AAI using an account that has already completed normal Pharos login and accepted the AUP. These are public OAuth clients using PKCE. Each has an enrolled callback and requires no client secret. Dynamic client registration stays disabled. | Client | Client ID | Exact callback | | --- | --- | --- | | Codex 0.148.0 | `pharos-codex` | `http://127.0.0.1:18744/callback/zxqdECo_DvVZ` | | Claude Code | `pharos-claude-code` | `http://localhost:18745/callback` | | OpenCode | `pharos-opencode` | `http://127.0.0.1:18746/mcp/oauth/callback` | The examples request Party, Project and Support reads. The [MCP contract](../../../contracts/mcp/README.md) describes the other owner scopes and command inputs. Add the required owner scopes and authenticate again when testing writes. Existing platform permissions still apply. ## Reach the lab Use the configured dev-box connection: ```sh make urls ``` If the short HTTPS addresses or certificate trust need preparing, follow [browser setup](../../../docs/development.md#open-the-application). The browser and each client's HTTPS runtime must trust the lab's public CA. Use the authenticated public certificate copied by that setup; retain TLS verification. Apply the fragments below to your own client configuration, preserving any existing entries. They do not contain account credentials. Complete the browser sign-in and consent from the machine running the client's callback listener. ## Codex Merge this fragment into the Codex configuration: ```toml [mcp_servers.pharos-lab] url = "https://mcp.localtest.me/mcp" scopes = ["party-governance:read", "project:read", "support:read"] [mcp_servers.pharos-lab.oauth] client_id = "pharos-codex" callback_port = 18744 ``` Then authenticate and inspect the entry: ```sh codex mcp login pharos-lab codex mcp get pharos-lab ``` Codex 0.148.0 appends a callback ID derived from the complete MCP URL. For `https://mcp.localtest.me/mcp` this is `zxqdECo_DvVZ`, giving the registered callback above. This version accepts `client_id` and `callback_port` in the per-server OAuth table; it ignores `callback_url` there. Leave the global `mcp_oauth_callback_url` unset for this setup. Newer Codex documentation describes an exact per-server `callback_url` when the broker advertises issuer support. The lab also retains the exact `http://127.0.0.1:18744/callback` registration for that flow. Check the installed version before using it. The broker advertises `authorization_response_iss_parameter_supported` and returns its exact issuer in the authorisation response for both callbacks. ## Claude Code Add the HTTP server with its enrolled client and callback: ```sh claude mcp add-json --scope user pharos-lab \ '{"type":"http","url":"https://mcp.localtest.me/mcp","oauth":{"clientId":"pharos-claude-code","callbackPort":18745,"scopes":"party-governance:read project:read support:read"}}' ``` If an entry with that name already exists, update its fields in the existing configuration. Then authenticate: ```sh claude mcp login pharos-lab claude mcp get pharos-lab ``` The same sign-in is available through `/mcp` in an interactive Claude Code session. This callback uses `localhost`, as Claude Code 2.1.310 does. ## OpenCode 1.x Merge this fragment into the OpenCode configuration: ```json { "mcp": { "pharos-lab": { "type": "remote", "url": "https://mcp.localtest.me/mcp", "enabled": true, "oauth": { "clientId": "pharos-opencode", "callbackPort": 18746, "redirectUri": "http://127.0.0.1:18746/mcp/oauth/callback", "scope": "party-governance:read project:read support:read" } } } } ``` Then authenticate and inspect the connection: ```sh opencode mcp auth pharos-lab opencode mcp list ``` These fields match installed OpenCode 1.18.19. OpenCode V2 documentation uses snake_case fields such as `client_id`, `callback_port` and `redirect_uri`; use the configuration format for the installed client version. The explicit redirect above retains the registered path and port. ## First check Ask the client to list the Projects accessible to the signed-in member. The gateway should expose the permitted read tools and return the same canonical Projects as the ordinary platform. A successful OAuth callback alone does not establish a successful tool call. The independent lab smoke client is `pharos-mcp-lab-smoke`, with callback `http://127.0.0.1:18743/callback` and `project:read`. Its results are recorded separately from proof using any of the three coding clients. ## Configuration references Checked on 8 November 2026 against installed Codex 0.148.0, Claude Code 2.1.310 and OpenCode 1.18.19. Version checks and configuration inspection establish syntax; the live report records which clients actually authenticated and called tools. - [Codex 0.148.0 OAuth configuration](https://github.com/openai/codex/blob/rust-v0.148.0/codex-rs/config/src/mcp_types.rs) - [Codex 0.148.0 callback construction](https://github.com/openai/codex/blob/rust-v0.148.0/codex-rs/rmcp-client/src/perform_oauth_login.rs) - [Current Codex OAuth clients and callbacks](https://learn.chatgpt.com/docs/extend/mcp#oauth-client-registration-and-callbacks) - [Claude Code MCP authentication](https://code.claude.com/docs/en/mcp#authenticate-with-remote-mcp-servers) - [OpenCode 1.18.19 OAuth provider and configuration fields](https://github.com/anomalyco/opencode/blob/v1.18.19/packages/opencode/src/mcp/oauth-provider.ts) - [OpenCode current MCP documentation](https://opencode.ai/docs/mcp-servers/)