Model Gateway

mur-model-gateway is a companion service that gives your agents one local endpoint for Anthropic, OpenAI, and Gemini — and lets them reuse the credentials you already have (including your Claude Code subscription login) instead of a separate metered API key.

# install a released binary, then run it as a background service
mur-model-gateway install
mur-model-gateway status

It lives in its own repository: github.com/mur-run/mur-model-gateway.

How it works

The gateway listens on 127.0.0.1:8088 and routes by path:

PathUpstream
/v1/messages*api.anthropic.com
/v1/chat/completions*, /v1/embeddings*api.openai.com
/v1beta/models/*generativelanguage.googleapis.com

Requests that already carry auth are forwarded untouched. Requests without auth get credentials attached from the configured token source — by default the OS keychain entry Claude Code maintains, so agents ride the plan you already pay for.

Use it from MUR

Point a model registry entry's base_url at the gateway:

# ~/.mur/models.yaml
models:
  - alias: sonnet
    provider: anthropic
    model: claude-sonnet-5
    base_url: http://127.0.0.1:8088

Every agent using that alias now goes through the gateway. Nothing else in MUR changes — pricing, routing, and the Model Library all keep working.

ChatGPT Subscription (no API key)

MUR Hub can connect a ChatGPT Plus/Pro plan through Codex CLI, so agents run on the subscription instead of a usage-billed API key.

Model Library → Add Provider → ChatGPT Subscription
  1. Sign in with ChatGPT      (codex login — the browser flow Codex owns)
  2. Install gateway           (consent card, then install --token-source-codex codex)
  3. Pick the models on your plan

Who owns what:

ConcernOwner
Sign-in and the credential on diskCodex CLI
Account / plan / model statusMUR Hub, via a short-lived codex app-server session
Attaching and refreshing the token, Responses-API translationmur-model-gateway
Registry entries and agent assignmentMUR

MUR never reads or copies the Codex credential file; the Hub only sees "signed in as email on plan X" and model ids.

Each picked model becomes a registry entry with provider: codex, billing: subscription and no secret:

chatgpt_gpt_5_6_sol:
  provider: codex
  model: gpt-5.6-sol
  base_url: http://127.0.0.1:8088/codex/v1
  billing: subscription
  catalog_verified: true

The runtime sends authless requests only to that loopback /codex/v1 route — a remote host, https, or a secret on the entry is refused at startup, so a typo cannot land on OpenAI Platform billing. GET /__mur/health reports whether the gateway has the Codex hook and which kind of credential it sees (chatgpt, apikey, missing); the Hub treats only chatgpt as ready.

Billing safety. Pickers and fallback-chain rows show a billing label (Subscription, Usage billed, Local, or Billing unknown — unknown is never shown as free). A 429 from the subscription does not make MUR spend money: it never inserts a usage-billed OpenAI model behind a ChatGPT model on its own, and the chain editor warns if you add one yourself.

Disconnect vs sign out. Disconnect MUR removes the subscription entries from models.yaml and leaves the Codex login alone. Sign out of ChatGPT runs codex logout after a confirmation, because it signs out every Codex client on the machine — CLI and IDE extensions included.

If model/list cannot be read, the panel offers Advanced: add an unverified model ID; the entry is marked catalog_verified: false and badged Unverified.

Claude Subscription (no API key)

The same shape as ChatGPT Subscription, for a Claude Pro/Max plan through Claude Code. The CLI is Claude Code and the gateway route is /v1.

Model Library → Add Provider → Claude Subscription
  1. Sign in with Claude       (claude auth login --claudeai)
  2. Install gateway           (consent card)
  3. Pick models               (from the models.dev catalog)

Who owns what:

ConcernOwner
Sign-in and the credential on diskClaude Code
Account statusMUR Hub, via claude auth status --json
Attaching and refreshing the tokenmur-model-gateway
Registry entries and agent assignmentMUR

MUR never reads the Claude Code credential. The Hub keeps three fields from claude auth status — signed in or not, which login kind, and the email — and drops the rest. Only authMethod: "claude.ai" is a subscription: an Anthropic Console login is the API and reads as "signed in, but not this provider".

Each picked model becomes a registry entry with provider: claude, billing: subscription and no secret:

claude_opus_5:
  provider: claude
  model: claude-opus-5
  base_url: http://127.0.0.1:8088/v1
  billing: subscription
  catalog_verified: true

The runtime sends Anthropic Messages requests with no x-api-key header at all — absent, not empty, because the gateway decides what to do by whether an auth header is present. It accepts only that loopback /v1 shape: a remote host, an https URL, or a secret on the entry is refused at startup. GET /__mur/health reports claudeCredential (oauth or missing — a kind, never a token); the Hub treats only oauth as ready.

Already using provider: anthropic with the gateway? It keeps working. The difference is what the entry guarantees: provider: anthropic is the same route with no protection, so one base_url edit to api.anthropic.com turns it into a metered API entry and nothing objects. mur model doctor points at the entries that could carry the explicit label; it stays quiet about one that has a secret, because what that entry does depends on the token inside and doctor does not read secrets.

Disconnect vs sign out. Disconnect MUR removes the subscription entries from the registry and leaves the Claude Code login alone. Sign out of Claude runs claude auth logout after a confirmation, because it signs Claude Code out everywhere on this machine — terminal sessions and IDE extensions included.

Configuration

Env varDefaultMeaning
MUR_MODEL_GATEWAY_BIND127.0.0.1:8088Listen address
MUR_MODEL_GATEWAY_TOKEN_SOURCEkeychainkeychain, off, env:<VAR>, file, or file:<path>
MUR_MODEL_GATEWAY_COMPRESSoff1 enables tool_result wire compression

Upstreams are overridable per provider (MUR_MODEL_GATEWAY_UPSTREAM_ANTHROPIC / _OPENAI / _GEMINI).

Notes

  • Loopback-only by default — it is a local outlet, not a shared server.
  • macOS release binaries are Developer-ID signed and notarized, so the keychain "Always Allow" you grant once survives every update.
  • Formerly known as cc-proxy; renamed when it grew beyond Claude Code to cover OpenAI and Gemini.