Local, read-only stdio bridge for using the COROS MCP gateway from Codex.
The bridge works around a protocol mismatch between the current COROS MCP gateway and the Codex MCP client:
- The COROS gateway currently answers
initializeas a stateless JSON-RPC request. In the verified integration, the response does not includeMcp-Session-Id. - Codex's remote Streamable HTTP MCP lifecycle expects a session-aware initialization flow. Directly pointing Codex at the COROS endpoint can therefore fail during MCP startup before any sport query is available.
- This project gives Codex a normal local stdio MCP server. The bridge translates Codex's stdio lifecycle into stateless, authenticated JSON-RPC calls to COROS.
The bridge does not replace the COROS service or implement a second data store. It is a small local protocol and credential boundary.
- Local stdio only. The bridge does not listen on a network port.
- Read-only allowlist only. Tools must be in the verified COROS query allowlist and advertise
readOnlyHint: true. - FIT download, FIT URL, route URL, export, and other sensitive file-oriented tools are excluded.
- No write, delete, upload, or training-plan mutation tools are exposed.
- The bridge reads the token cache created by the official
@coros_open/coros-mcp-loginCLI. - Access tokens are refreshed when needed and persisted atomically with file mode
0600. - Access and refresh tokens are never printed, logged, or committed.
- Upstream and OAuth requests, including response-body reads, time out after 30 seconds by default.
- There is no telemetry or background daemon.
The allowlist is intentionally conservative. If COROS adds a new read-only tool, it must be reviewed and added explicitly before this bridge exposes it.
- macOS or another system that can run the official COROS MCP login flow
- Node.js 22 or newer
- A Codex client with MCP configuration support
- A COROS account authorized through the official login CLI
git clone https://github.com/lagrangee/coros-codex-mcp-bridge.git
cd coros-codex-mcp-bridge
npm test
npm run checkThere are no runtime npm dependencies. Use a Node executable that is visible to the Codex process; for desktop applications, an absolute Node path is often more reliable than relying on GUI PATH inheritance.
Run the official login command in a terminal:
npx --yes @coros_open/coros-mcp-login loginComplete authentication in the browser. Do not paste a password, authorization code, access token, or refresh token into Codex or an issue.
The bridge discovers the first existing cache at:
~/.coros-mcp-skill-gateway-ts/{cn,eu,us}/token.json
If the cache is missing or the refresh token has been revoked, run the official login command again.
Add or replace the coros entry in ~/.codex/config.toml:
[mcp_servers.coros]
command = "/absolute/path/to/node"
args = ["/absolute/path/to/coros-codex-mcp-bridge/src/cli.mjs"]
startup_timeout_sec = 30For a shell-installed Node, command = "node" may be sufficient. For Codex Desktop, use the absolute path to the Node runtime that the desktop process can execute.
After changing MCP configuration, start a fresh Codex process or task so it reloads the configuration. Verify the entry with:
codex mcp get corosThe bridge is started and stopped by Codex as a stdio child process. You do not need to keep a terminal running or supervise a daemon.
All overrides are optional:
| Variable | Purpose | Default |
|---|---|---|
COROS_TOKEN_PATH |
Explicit token cache path | Regional cache discovery |
COROS_REGION |
Regional endpoint selector: cn, eu, or us |
Inferred from cache path, then cn |
COROS_OAUTH_ISSUER |
Override the OAuth issuer | Regional COROS issuer |
COROS_MCP_URL |
Override the upstream MCP URL | ${issuer}/mcp |
COROS_REQUEST_TIMEOUT_MS |
Request and response-body timeout | 30000 |
Example:
COROS_REGION=eu COROS_REQUEST_TIMEOUT_MS=60000 node src/cli.mjsCodex
| JSON-RPC over stdin/stdout
v
coros-codex-mcp-bridge
| token cache discovery and refresh
| read-only tool allowlist
| stateless JSON-RPC translation
v
COROS MCP gateway
The bridge keeps the upstream implementation details local to the adapter:
src/cli.mjsowns JSONL stdio and environment-based configuration.src/bridge.mjsowns the Codex-facing MCP surface and read-only policy.src/coros-client.mjsowns upstream initialization, pagination, session recovery, SSE parsing, and tool calls.src/token-store.mjsowns token-cache discovery input, refresh, atomic persistence, and file permissions.
npm test
npm run checkTests use fake HTTP responses and temporary token files. They do not require a COROS account and must not contain real credentials.
Run the stdio server directly when debugging protocol integration:
node src/cli.mjsThe process reads newline-delimited JSON-RPC from stdin and writes responses to stdout. Diagnostic messages must stay off stdout because stdout is the MCP protocol channel.
Run:
npx --yes @coros_open/coros-mcp-login loginThen restart the Codex process so the bridge reloads the cache.
Check the command and absolute paths in ~/.codex/config.toml, run codex mcp get coros, and start a fresh Codex process. A configuration edit is not necessarily hot-loaded into an already running process.
That is intentional. Review its semantics and add it to the allowlist in src/bridge.mjs with a regression test before exposing it.
See CONTRIBUTING.md. In particular, do not add credentials, live personal sport data, or unreviewed write-capable tools to tests or fixtures.
See SECURITY.md. Do not report token values or other private sport data in public issues.
MIT. See LICENSE.