multi-model-companion
# multi-model-companion
[](https://github.com/Reederey87/multi-model-companion/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/downloads/)
Local MCP server that lets **Claude Code** delegate bounded, read-only tasks to
external models through [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI):
- **OpenAI Codex** (ChatGPT / Codex subscription via OAuth)
- **xAI Grok** (Grok subscription via OAuth)
- **Local OpenAI-compatible models** (vLLM, Ollama, LM Studio, llama.cpp, …)
- Optionally any other backend CLIProxyAPI exposes (Kimi, OpenRouter, API keys, …)
Claude stays the coordinator: it decomposes work, selects models and context,
verifies output, edits files, and runs tests. Companion models receive **only
the context you send** and return text — they cannot run shell, read your disk,
modify the repo, or use your credentials.
```text
Native Claude Code
│ MCP (stdio)
▼
multi-model-companion
│ OpenAI-compatible HTTP
▼
CLIProxyAPI (127.0.0.1:8317)
├── Codex OAuth → GPT / Codex models
├── xAI OAuth → Grok models
├── Kimi OAuth → Kimi models (optional)
└── openai-compatibility → local vLLM / Ollama / …
```
## Why MCP instead of the official Codex Claude Code plugin?
Short version: **one uniform multi-provider bridge beats one CLI wrapper per
vendor** for everyday review, analysis, local-model routing, and multi-model
compare. Keep a CLI plugin (or bare Codex CLI) only for rare write-mode
“go implement this yourself” rescue tasks.
Full write-up (rephrased from a real migration off a Codex/Grok plugin stack):
- **[docs/06-mcp-vs-plugin.md](docs/06-mcp-vs-plugin.md)** — architecture
contrast, trust surface, data governance, and the recommended split.
Upstream plugin reference:
[openai/codex-plugin-cc](https://github.com/openai/codex-plugin-cc).
## Requirements
- Python ≥ 3.12
- [uv](https://docs.astral.sh/uv/)
- [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) running locally
- At least one configured backend (OAuth login and/or local OpenAI-compatible server)
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI
## Quickstart
```bash
git clone https://github.com/<you>/multi-model-companion.git
cd multi-model-companion
cp .env.example .env # set CLIPROXY_API_KEY and model IDs
uv sync --extra dev
```
1. Install and start CLIProxyAPI — [docs/01-cliproxyapi-setup.md](docs/01-cliproxyapi-setup.md)
2. Log in to subscriptions you want — [docs/02-subscription-logins.md](docs/02-subscription-logins.md)
3. Optionally wire a local model — [docs/03-local-models.md](docs/03-local-models.md)
4. Register the MCP server with Claude Code — [docs/04-claude-code-mcp.md](docs/04-claude-code-mcp.md)
Confirm models from the proxy:
```bash
curl -s \
-H "Authorization: Bearer $CLIPROXY_API_KEY" \
"${CLIPROXY_BASE_URL:-http://127.0.0.1:8317/v1}/models" \
| jq -r '.data[].id' | sort
```
Set `CODEX_MODEL`, `GROK_MODEL`, and `DEEPSEEK_MODEL` in `.env` to IDs that
actually appear in that list.
## MCP tools
| Tool | Purpose |
|---|---|
| `delegate_analysis` | Debugging hypotheses, architecture, research synthesis |
| `delegate_review` | Read-only code review of a supplied diff/excerpt |
| `delegate_patch` | Propose a minimal unified diff (never applies it) |
| `compare_models` | Same question to 2–3 providers in parallel |
| `list_companion_models` | Configured IDs vs what CLIProxyAPI currently exposes |
| `health_check` | Connectivity check (no inference) |
Providers in this package: `codex`, `grok`, `deepseek` (the third slot is
intended for your **local** OpenAI-compatible model; rename via env).
## Model routing (house defaults)
- Drop-in agent guidance: [CLAUDE.md](CLAUDE.md)
- Longer rationale: [MODEL_ROUTING.md](MODEL_ROUTING.md)
Core policy:
1. Prefer a **local / cheap** model (`deepseek` slot) for anything that fits
supplied context.
2. Escalate to Codex / Grok only on evidence (thin output, fuzzy spec, high
blast radius).
3. Claude verifies every material claim and applies every change itself.
4. Never put secrets, `.env`, or key material in delegated context.
## Configuration
See [`.env.example`](.env.example). Required:
```bash
CLIPROXY_API_KEY=replace-with-a-long-random-client-key
```
Optional model overrides (examples — use IDs from your `/v1/models` list):
```bash
CLIPROXY_BASE_URL=http://127.0.0.1:8317/v1
CODEX_MODEL=gpt-5.6-codex
GROK_MODEL=grok-4
DEEPSEEK_MODEL=local/my-local-model
```
Example CLIProxyAPI + MCP snippets:
- [examples/cliproxyapi.config.example.yaml](examples/cliproxyapi.config.example.yaml)
- [examples/mcp.json.example](examples/mcp.json.example)
## Security model
- **Read-only delegation** — no tool runs shell or writes files.
- Outbound context is redacted for common secret patterns and truncated.
- Repository content is wrapped as untrusted data in the prompt.
- Logs are metadata-only (provider, model, mode, sizes, status) — never full
prompts, keys, or responses.
- Keep CLIProxyAPI bound to `127.0.0.1`.
Details: [docs/05-security.md](docs/05-security.md).
## Validation
```bash
uv sync --extra dev
uv run pytest -v
uv run ruff check src tests scripts
uv run python scripts/smoke_stdio.py # no live models required
```
Live path (CLIProxyAPI + backends up):
```bash
export CLIPROXY_API_KEY=...
uv run python scripts/e2e_live.py
```
Optional independent audit prompt: [docs/validation-prompt.md](docs/validation-prompt.md).
## Project layout
```text
src/multi_model_companion/ # MCP server + CLIProxy client
tests/ # unit tests (httpx mocked)
scripts/ # smoke + optional live e2e
docs/ # setup guides + MCP vs plugin rationale
examples/ # sample CLIProxyAPI + MCP configs
CLAUDE.md # drop into a project for routing defaults
MODEL_ROUTING.md # longer routing rationale
```
## Docs index
| Doc | Topic |
|---|---|
| [docs/01-cliproxyapi-setup.md](docs/01-cliproxyapi-setup.md) | Install / run the proxy |
| [docs/02-subscription-logins.md](docs/02-subscription-logins.md) | Codex, Grok, Kimi OAuth |
| [docs/03-local-models.md](docs/03-local-models.md) | vLLM, Ollama, tunnels |
| [docs/04-claude-code-mcp.md](docs/04-claude-code-mcp.md) | Wire MCP into Claude Code |
| [docs/05-security.md](docs/05-security.md) | Threat model and controls |
| [docs/06-mcp-vs-plugin.md](docs/06-mcp-vs-plugin.md) | Why MCP over CLI plugins |
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). Please read [SECURITY.md](SECURITY.md)
before reporting vulnerabilities, and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
for community expectations.
Release notes: [CHANGELOG.md](CHANGELOG.md).
## Related projects
- [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)
- [CLIProxyAPI docs](https://help.router-for.me/)
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
- [Model Context Protocol](https://modelcontextprotocol.io/)
- [openai/codex-plugin-cc](https://github.com/openai/codex-plugin-cc) (plugin alternative)
## License
MIT — see [LICENSE](LICENSE).
TDQS
Scored across 6 tools
Each tool has a distinct primary purpose: analysis, review, patch, comparison, listing, and health checking. The slight overlap between delegate_analysis and delegate_review is mitigated by clear use-case descriptions, and list_companion_models/health_check serve different aspects of availability.
Most names follow a verb_noun pattern (delegate_*, compare_models, list_companion_models), but health_check deviates from the verb-first convention and could be check_health. Overall the pattern is consistent enough to be predictable.
Six tools is a well-scoped set for a multi-model companion server. Each tool covers a distinct capability without redundancy or bloat.
The server covers the primary workflows: delegating analysis, review, patch generation, multi-model comparison, and status checks. Minor gaps exist, such as no explicit tool for configuring models or retrieving detailed model metadata, but the core functionality is complete.