# model-proxy-mcp

Claude-compatible model proxy MCP with ChatGPT Codex upstream support.

## What it does

This package provides:

- A Claude-compatible HTTP proxy server for `/v1/messages` and `/v1/models`
- An MCP server over stdio
- A `claude` wrapper command that launches Claude Code against a scoped proxy URL
- Scoped model/profile configuration and request history
- An admin HTTP UI and admin JSON endpoints

Key entrypoints:

- CLI entry: `packages/mcp/model-proxy-mcp/src/cli.ts:16`
- Claude wrapper: `packages/mcp/model-proxy-mcp/src/commands/claude.ts:233`
- HTTP server: `packages/mcp/model-proxy-mcp/src/server/http.ts:41`
- Gateway service: `packages/mcp/model-proxy-mcp/src/services/GatewayService.ts:118`

## Commands

### Start both HTTP and MCP services

```bash
pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts start
```

Options from `packages/mcp/model-proxy-mcp/src/commands/start.ts:7`:

- `--mcp-only`
- `--http-only`
- `-p, --port <port>`

### Start only the HTTP proxy

```bash
pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts http-serve
```

Default port is `43191` from `packages/mcp/model-proxy-mcp/src/constants/defaults.ts:11`.

### Start only the MCP server

```bash
pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts mcp-serve
```

Options from `packages/mcp/model-proxy-mcp/src/commands/mcp-serve.ts:10`:

- `--cleanup`
- `-p, --port <port>`

### Show status

```bash
pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts status
```

Optional scope:

```bash
pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts status --scope my-scope
```

### Stop the background HTTP server

```bash
pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts stop
```

## Launch Claude Code through the proxy

The `claude` command seeds scope config, ensures the HTTP proxy is running, sets Claude model env vars, and launches Claude Code against:

```text
http://127.0.0.1:<port>/scopes/<scope>
```

See `packages/mcp/model-proxy-mcp/src/commands/claude.ts:75` and `packages/mcp/model-proxy-mcp/src/commands/claude.ts:176`.

Example:

```bash
env -u CLAUDECODE pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts \
  claude --scope demo --clear-session -- \
  -p "hi, how are you doing?"
```

Why `env -u CLAUDECODE`? Claude Code blocks nested sessions when launched from inside another Claude Code session.

Supported wrapper options from `packages/mcp/model-proxy-mcp/src/commands/claude.ts:233`:

- `-s, --scope <scope>`
- `-p, --port <port>`
- `-c, --config-file <path>`
- `--config <path>`
- `--clear-session`

All remaining args are forwarded directly to the upstream `claude` CLI via `claudeArgs` in `packages/mcp/model-proxy-mcp/src/commands/claude.ts:196`.

## Headless and streaming usage

### One-shot headless response

```bash
env -u CLAUDECODE pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts \
  claude --scope test-headless --clear-session -- \
  -p "hi, how are you doing?"
```

### Stream JSON output

```bash
env -u CLAUDECODE pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts \
  claude --scope test-headless --clear-session -- \
  -p --output-format stream-json --include-partial-messages \
  "hi, how are you doing?"
```

### Stream JSON input and output

```bash
env -u CLAUDECODE pnpm exec tsx packages/mcp/model-proxy-mcp/src/cli.ts \
  claude --scope test-headless --clear-session -- \
  -p --input-format stream-json --output-format stream-json --include-partial-messages
```

## HTTP API

HTTP routes are defined in `packages/mcp/model-proxy-mcp/src/server/http.ts:45`.

Core routes:

- `GET /health`
- `GET /status`
- `GET /v1/models`
- `POST /v1/messages`
- `GET /scopes/:scope/status`
- `GET /scopes/:scope/v1/models`
- `POST /scopes/:scope/v1/messages`

Admin routes:

- `GET /admin`
- `GET /admin/scopes`
- `GET /admin/config?scope=<scope>`
- `GET /admin/profiles?scope=<scope>`
- `GET /admin/current-model?scope=<scope>&slot=<slot>`
- `GET /admin/history?scope=<scope>&limit=<n>&cursor=<cursor>`
- `GET /admin/history/stats?scope=<scope>`
- `PUT /admin/profiles/:id?scope=<scope>`
- `PUT /admin/active-profile?scope=<scope>`
- `PUT /admin/current-model?scope=<scope>`
- `PUT /admin/config?scope=<scope>`
- `DELETE /admin/history?scope=<scope>`

## Configuration

Default config locations come from `packages/mcp/model-proxy-mcp/src/constants/defaults.ts:5`:

- Settings dir: `~/.model-proxy`
- Provider config: `~/.model-proxy/model-provider.yaml`
- Model list: `~/.model-proxy/model-list.yaml`
- Scope settings dir: `~/.model-proxy/scopes`
- History DB: `~/.model-proxy/history.sqlite`
- Codex auth file: `~/.codex/auth.json`

Environment overrides used by `packages/mcp/model-proxy-mcp/src/services/ProfileStore.ts:107` and `packages/mcp/model-proxy-mcp/src/services/GatewayService.ts:47`:

- `MODEL_PROXY_MCP_PROVIDER_PATH`
- `MODEL_PROXY_MCP_MODEL_LIST_PATH`
- `MODEL_PROXY_MCP_SCOPE_DIR`
- `ANTHROPIC_AUTH_TOKEN`
- `MODEL_PROXY_MCP_UPSTREAM_AUTH_TOKEN`
- `MODEL_PROXY_MCP_UPSTREAM_AUTH_ENV`
- `MODEL_PROXY_MCP_UPSTREAM_TIMEOUT_MS`
- `API_TIMEOUT_MS`

The Claude wrapper also sets these model aliases in the child Claude process at `packages/mcp/model-proxy-mcp/src/commands/claude.ts:80`:

- `ANTHROPIC_DEFAULT_OPUS_MODEL=ccproxy-opus`
- `ANTHROPIC_DEFAULT_SONNET_MODEL=ccproxy-sonnet`
- `ANTHROPIC_DEFAULT_HAIKU_MODEL=ccproxy-haiku`
- `CLAUDE_CODE_SUBAGENT_MODEL=ccproxy-subagent`

## Upstream providers

The default provider registry includes:

- `chatgpt-codex`
- `zai-anthropic-compat`

See `packages/mcp/model-proxy-mcp/src/constants/defaults.ts:15`.

The gateway resolves Claude model aliases like `ccproxy-opus` and routes them to the configured scope slot in `packages/mcp/model-proxy-mcp/src/services/GatewayService.ts:31`.

## Authentication

ChatGPT Codex auth is loaded from `~/.codex/auth.json` by `packages/mcp/model-proxy-mcp/src/adapters/codex/CodexAuth.ts:25`.

Behavior:

- Reads `access_token`, `refresh_token`, and `account_id`
- Refreshes expired access tokens through OpenAI OAuth
- Persists refreshed tokens back to the auth file

## Development

Install dependencies from the monorepo root:

```bash
pnpm install
```

Build:

```bash
nx build model-proxy-mcp
```

Test:

```bash
nx test model-proxy-mcp
```

Typecheck:

```bash
nx typecheck model-proxy-mcp
```

Direct package scripts from `packages/mcp/model-proxy-mcp/package.json:22`:

```bash
pnpm --dir packages/mcp/model-proxy-mcp run build
pnpm --dir packages/mcp/model-proxy-mcp run test
pnpm --dir packages/mcp/model-proxy-mcp run typecheck
```

## Current test coverage in repo

Existing tests include:

- `packages/mcp/model-proxy-mcp/tests/commands/claude.test.ts:12`
- `packages/mcp/model-proxy-mcp/tests/server/http.test.ts:1`
- `packages/mcp/model-proxy-mcp/tests/services/GatewayService.test.ts:1`
- `packages/mcp/model-proxy-mcp/tests/services/ProfileStore.test.ts:1`
- `packages/mcp/model-proxy-mcp/tests/services/ConversationHistoryService.test.ts:1`
