{
  "markdown": "# Nexus MCP\n<!-- mcp-name: io.github.j7an/nexus-mcp -->\n\n[![PyPI](https://img.shields.io/pypi/v/nexus-mcp)](https://pypi.org/project/nexus-mcp/)\n[![Python 3.13+](https://img.shields.io/pypi/pyversions/nexus-mcp)](https://www.python.org)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![type-checked: mypy](https://img.shields.io/badge/type--checked-mypy-blue.svg)](https://mypy-lang.org/)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://pre-commit.com/)\n[![MCP](https://img.shields.io/badge/MCP-compatible-purple)](https://modelcontextprotocol.io/)\n\nAn MCP server that enables AI models to invoke AI CLI agents (Codex, Claude Code, OpenCode) as\ntools. Provides durable workspace-scoped jobs, parallel execution, automatic retries with\nexponential backoff, JSON-first response parsing, discoverable prompt templates, model tier\nclassification, and persistent preferences through MCP tools, resources, and prompts.\n\n## Use Cases\n\nNexus MCP is useful whenever a task benefits from querying multiple AI agents in\nparallel rather than sequentially:\n\n- **Research & summarization** — fan out a topic to multiple agents, then\n  synthesize their responses into a single summary with diverse perspectives\n- **Code review** — send different files or review angles (security, correctness,\n  style) to separate agents simultaneously\n- **Multi-model comparison** — prompt the same question to different models and\n  compare outputs side-by-side for quality or consistency\n- **Bulk content generation** — generate multiple test cases, translations, or\n  documentation pages concurrently instead of one at a time\n- **Second-opinion workflows** — get independent answers from separate agents\n  before making a decision, reducing single-model bias\n\n## Features\n\n- **Parallel execution** — `batch_prompt` fans out tasks with `asyncio.gather` and a configurable\n  semaphore (default concurrency: 3)\n- **Durable jobs** — start, observe, cancel, and resume normalized agent work through stable job and\n  session identities backed by a private per-user SQLite database\n- **Automatic retries** — exponential backoff with full jitter for transient errors (HTTP 429/503)\n- **Output handling** — JSON-first parsing, brace-depth fallback for noisy stdout, temp-file\n  spillover for outputs exceeding 50 KB\n- **Execution modes** — `default` (safe, no auto-approve), `yolo` (full auto-approve)\n- **CLI detection** — auto-detects binary path, version, and JSON output capability at startup\n- **Persistent preferences** — set defaults for execution mode, model, retries, output limit, and timeout; preferences persist across MCP sessions via the backing store (MemoryStore default, FileTreeStore/RedisStore for restart persistence)\n- **Prompt templates** — 10 discoverable workflow scaffolds (code review, debug, research, implement feature, etc.) via `list_prompts`/`get_prompt`; each returns structured messages with expert framing the client can use or ignore\n- **Model tier classification** — heuristic-based model classification into quick/standard/thorough tiers; clients can override with sampling or live benchmarks. The `nexus://runners` resource includes tier data per model\n- **Tool timeouts** — configurable safety timeout (default 15 min) cancels long-running tool calls to prevent the server from blocking indefinitely\n- **Client-visible logging** — runner events (retries, output truncation, error recovery) are sent to MCP clients via protocol notifications, not just server stderr\n- **Elicitation** — interactive parameter resolution via MCP elicitation; disambiguates missing CLI, offers model selection, confirms YOLO mode, and prompts for elaboration on vague prompts. Auto-detects client support and skips gracefully when unavailable. Suppression flags prevent repeat prompts within a session\n- **Benchmark data sources** — server instructions include URLs for Artificial Analysis, OpenRouter, Chatbot Arena, and LLM Stats so clients can fetch live model benchmarks without API keys\n- **Extensible** — implement `build_command` + `parse_output`, register in `RunnerFactory`\n\n| Agent | Status |\n|-------|--------|\n| Codex | Supported |\n| Claude Code | Supported |\n| OpenCode | Supported |\n\n## Installation\n\n### Run with uvx (recommended)\n\n```bash\nuvx nexus-mcp\n```\n\n`uvx` installs the package in an ephemeral virtual environment and runs it — no cloning required.\n\nTo check the installed version:\n\n```bash\nuvx nexus-mcp --version\n```\n\nTo update to the latest version:\n\n```bash\nuvx --reinstall nexus-mcp\n```\n\n<details>\n<summary><h3>MCP Client Configuration</h3></summary>\n\n**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):\n\n```json\n{\n  \"mcpServers\": {\n    \"nexus-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"nexus-mcp\"],\n      \"env\": {\n        \"NEXUS_CODEX_MODEL\": \"gpt-5.2\",\n        \"NEXUS_CODEX_MODELS\": \"gpt-5.4,gpt-5.4-mini,gpt-5.3-codex,gpt-5.2-codex,gpt-5.2,gpt-5.1-codex-max,gpt-5.1-codex-mini\",\n        \"NEXUS_CLAUDE_MODEL\": \"claude-sonnet-4-6\",\n        \"NEXUS_CLAUDE_MODELS\": \"claude-sonnet-4-6,claude-haiku-4-5-20251001\",\n        \"NEXUS_OPENCODE_MODEL\": \"ollama-cloud/kimi-k2.5\",\n        \"NEXUS_OPENCODE_MODELS\": \"ollama-cloud/glm-5,ollama-cloud/kimi-k2.5,ollama-cloud/qwen3-coder-next,ollama-cloud/minimax-m2.5,ollama/gemini-3-flash-preview\"\n      }\n    }\n  }\n}\n```\n\n**Cursor** (`.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally):\n\n```json\n{\n  \"mcpServers\": {\n    \"nexus-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"nexus-mcp\"],\n      \"env\": {\n        \"NEXUS_CODEX_MODEL\": \"gpt-5.2\",\n        \"NEXUS_CODEX_MODELS\": \"gpt-5.4,gpt-5.4-mini,gpt-5.3-codex,gpt-5.2-codex,gpt-5.2,gpt-5.1-codex-max,gpt-5.1-codex-mini\",\n        \"NEXUS_CLAUDE_MODEL\": \"claude-sonnet-4-6\",\n        \"NEXUS_CLAUDE_MODELS\": \"claude-sonnet-4-6,claude-haiku-4-5-20251001\",\n        \"NEXUS_OPENCODE_MODEL\": \"ollama-cloud/kimi-k2.5\",\n        \"NEXUS_OPENCODE_MODELS\": \"ollama-cloud/glm-5,ollama-cloud/kimi-k2.5,ollama-cloud/qwen3-coder-next,ollama-cloud/minimax-m2.5,ollama/gemini-3-flash-preview\"\n      }\n    }\n  }\n}\n```\n\n**Claude Code** (CLI):\n\n```bash\nclaude mcp add nexus-mcp \\\n  -e NEXUS_CODEX_MODEL=gpt-5.2 \\\n  -e NEXUS_CODEX_MODELS=gpt-5.4,gpt-5.4-mini,gpt-5.3-codex,gpt-5.2-codex,gpt-5.2,gpt-5.1-codex-max,gpt-5.1-codex-mini \\\n  -e NEXUS_CLAUDE_MODEL=claude-sonnet-4-6 \\\n  -e NEXUS_CLAUDE_MODELS=claude-sonnet-4-6,claude-haiku-4-5-20251001 \\\n  -e NEXUS_OPENCODE_MODEL=ollama-cloud/kimi-k2.5 \\\n  -e NEXUS_OPENCODE_MODELS=ollama-cloud/glm-5,ollama-cloud/kimi-k2.5,ollama-cloud/qwen3-coder-next,ollama-cloud/minimax-m2.5,ollama/gemini-3-flash-preview \\\n  -- uvx nexus-mcp\n```\n\n**Generic stdio config** (any MCP-compatible client):\n\n```json\n{\n  \"command\": \"uvx\",\n  \"args\": [\"nexus-mcp\"],\n  \"transport\": \"stdio\",\n  \"env\": {\n    \"NEXUS_CODEX_MODEL\": \"gpt-5.2\",\n    \"NEXUS_CLAUDE_MODEL\": \"claude-sonnet-4-6\",\n    \"NEXUS_OPENCODE_MODEL\": \"ollama-cloud/kimi-k2.5\"\n  }\n}\n```\n\nAll `env` keys are optional — see [Configuration](#configuration) for the full list.\n\n</details>\n\n<details>\n<summary><h3>Setup for Development</h3></summary>\n\n**Prerequisites:**\n- **Python 3.13+** ([download](https://www.python.org/downloads/))\n- **uv** dependency manager ([install guide](https://github.com/astral-sh/uv))\n  ```bash\n  curl -LsSf https://astral.sh/uv/install.sh | sh\n  ```\n\n**Optional (for integration tests):**\n- **Codex** — check with `codex --version`\n- **Claude Code** — check with `claude --version`\n- **OpenCode** — check with `opencode --version`\n\n> **Claude Code note:** Nexus invokes Claude Code non-interactively via `claude -p`.\n> Anthropic says `claude -p` and Agent SDK usage draw from separate monthly Agent SDK\n> credits starting 2026-06-15, while interactive Claude Code usage remains on plan usage\n> limits:\n> https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan\n\n> **Note:** Integration tests are optional. Unit tests run without CLI dependencies via subprocess mocking.\n\n```bash\n# 1. Clone the repository\ngit clone <repository-url>\ncd nexus-mcp\n\n# 2. Install dependencies\nuv sync\n\n# 3. Install pre-commit hooks (runs linting/formatting on commit)\nuv run pre-commit install\n\n# 4. Verify installation\nuv run pytest                    # Run tests\nuv run mypy src/nexus_mcp        # Type checking\nuv run ruff check .              # Linting\n\n# 5. Run the MCP server\nuv run python -m nexus_mcp\n```\n\n</details>\n\n<details>\n<summary><h3>OpenCode Server (Docker) — experimental</h3></summary>\n\n> ⚠️ **Experimental** — This integration has not been validated end-to-end by the maintainer. Expect rough edges in setup, auth, and tool exposure. The MCP tools surfaced from upstream OpenCode track the upstream project and may change without notice. Feedback and bug reports are welcome.\n\nRun an isolated [OpenCode](https://opencode.ai) server for HTTP-based agent execution alongside the CLI runner. Provides session management, file search, permissions, and 38 additional MCP tools when the server is healthy.\n\n**Quick start:**\n\n1. Copy `.env.example` to `.env` and set `PROJECT_DIR` to your project path:\n   ```bash\n   cp .env.example .env\n   # Edit .env: set PROJECT_DIR=/path/to/your/project\n   ```\n2. Start the server:\n   ```bash\n   docker compose up -d\n   ```\n3. Authenticate with your provider:\n   ```bash\n   docker exec -it opencode-server opencode auth login\n   ```\n4. Verify the server is healthy:\n   ```bash\n   curl -u opencode:nexus http://localhost:4096/global/health\n   ```\n\nThe server binds to `127.0.0.1` (localhost only) by default for security. See [docs/opencode-server-setup.md](docs/opencode-server-setup.md) for the full guide including remote access, multi-project setup, and network security.\n\n</details>\n\n## Usage\n\nOnce nexus-mcp is configured in your MCP client, your AI assistant automatically sees its tools.\nThe reliable trigger is **explicitly asking for output from an external AI agent** (e.g. Codex, Claude Code, OpenCode).\nGeneric \"do this in parallel\" prompts may be handled by the host AI's own capabilities instead.\nThe `cli` parameter is optional — if omitted and the client supports MCP elicitation, the server will\nask which runner to use. The server provides runner metadata (names, models, availability,\nexecution modes) in its connection instructions — no discovery call needed. The `cli` parameter\nincludes a JSON schema enum listing valid runner names.\n\n<details>\n<summary><h3>Usage Examples</h3></summary>\n\n#### Fan out a research question (batch_prompt)\n\n**You say:** \"Get perspectives from Codex, Claude Code, and OpenCode on transformer architectures.\"\n\n```json\n{\n  \"tasks\": [\n    { \"cli\": \"codex\", \"prompt\": \"Summarize the key findings of the Attention Is All You Need paper\", \"label\": \"codex-summary\" },\n    { \"cli\": \"claude\", \"prompt\": \"What are the main limitations of transformer architectures?\", \"label\": \"claude-limitations\" },\n    { \"cli\": \"opencode\", \"prompt\": \"List 3 real-world applications of transformers beyond NLP\", \"label\": \"opencode-applications\" }\n  ]\n}\n```\n\n#### Code review from multiple angles (batch_prompt)\n\n**You say:** \"Have Codex, Claude Code, and OpenCode each review this diff in parallel.\"\n\n```json\n{\n  \"tasks\": [\n    { \"cli\": \"codex\", \"prompt\": \"Review this diff for security vulnerabilities:\\n\\n<paste diff>\", \"label\": \"codex-security-review\" },\n    { \"cli\": \"claude\", \"prompt\": \"Review this diff for correctness and edge cases:\\n\\n<paste diff>\", \"label\": \"claude-correctness-review\" },\n    { \"cli\": \"opencode\", \"prompt\": \"Review this diff for style and maintainability:\\n\\n<paste diff>\", \"label\": \"opencode-review\" }\n  ]\n}\n```\n\n#### Single-agent prompt\n\n**You say:** \"Ask Codex to explain the difference between TCP and UDP.\"\n\n```json\n{ \"cli\": \"codex\", \"prompt\": \"Explain the difference between TCP and UDP in simple terms\", \"model\": \"gpt-5.2\" }\n```\n\n#### Elicitation (server picks the runner)\n\n**You say:** \"Explain the CAP theorem using one of the available agents.\"\n\n```json\n{ \"prompt\": \"Explain the CAP theorem in simple terms\" }\n```\n\nIf the client supports MCP elicitation, the server asks which runner to use. Pass `\"elicit\": false` to skip.\n\n#### Persistent preferences\n\n**You say:** \"Use YOLO mode with Codex from now on.\"\n\n```json\n{ \"execution_mode\": \"yolo\", \"model\": \"gpt-5.2\", \"max_retries\": 5 }\n```\n\nSubsequent calls inherit these settings. Preferences persist across MCP sessions until explicitly cleared.\n\nFallback chain: **explicit parameter → saved preference → per-runner env → global env → hardcoded default**.\n\n</details>\n\n## MCP Tools\n\nNexus exposes a durable `agent_*` surface and the original compatibility prompt surface. Every\ndurable tool requires an explicit `workspace` selector containing exactly one of an existing\n`workspace_id` or a filesystem `path`; Nexus never infers a durable workspace from the server's\ncurrent directory. A path is resolved to one canonical workspace identity before admission.\n\nExecution-starting durable tools return a `JobHandle` immediately. Clients use the observation and\ncontrol tools to follow the normalized job independently of an MCP request lifetime.\n\n| Tool | Description |\n|------|-------------|\n| `agent_start` | Create a durable session and queue its first turn |\n| `agent_continue` | Queue another turn on an existing session |\n| `agent_fork` | Create a child session when the backend supports forking |\n| `agent_review` | Queue a typed review operation on an existing session |\n| `agent_diagnose` | Queue a sessionless backend diagnostic job |\n| `agent_status` | Read the current normalized status of one job |\n| `agent_result` | Read the pending or terminal typed result of one job |\n| `agent_list` | Page through authorized jobs in one workspace |\n| `agent_backends` | List backend capabilities and current availability for one workspace |\n| `agent_cancel` | Request idempotent cancellation of a queued or active job |\n| `agent_respond` | Resolve a pending approval, permission, question, or form input |\n\nThe compatibility `prompt` and `batch_prompt` tools retain their background-task behavior. They\nreturn FastMCP task IDs so clients can poll without holding a long-running MCP request open.\nPer-call concurrency defaults to 3. The shared process runtime starts with 3 workers and grows to\na high-water maximum of 8; one call whose effective demand exceeds 8 is rejected explicitly,\nwhile concurrent calls share the process ceiling and may queue.\n\n| Tool | Task? | Description |\n|------|-------|-------------|\n| `batch_prompt` | Yes | Fan out prompts to multiple runners in parallel; returns `MultiPromptResponse` |\n| `prompt` | Yes | Single-runner convenience wrapper; routes to `batch_prompt` |\n| `set_preferences` | No | Set or selectively clear persistent defaults for execution mode, model, retries, timeouts, elicitation, and trigger suppression |\n| `get_preferences` | No | Retrieve current preferences |\n| `clear_preferences` | No | Reset all preferences |\n| `set_model_tiers` | No | Save model tier classifications (client sends sampling/benchmark results; server persists) |\n| `get_model_tiers` | No | Retrieve saved model tier classifications |\n\n<details>\n<summary><h3>Tool API Reference</h3></summary>\n\n#### `batch_prompt`\n\n| Parameter | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `tasks` | Yes | — | List of task objects (see below) |\n| `max_concurrency` | No | `3` | Max parallel agent invocations for this call; effective demand above the process worker maximum of 8 is rejected |\n| `elicit` | No | pref or `true` | Enable/disable interactive elicitation for this call |\n\n**Task object fields:**\n\n| Field | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `cli` | No | — | Runner name (e.g. `\"codex\"`); if omitted, elicitation asks which runner to use |\n| `prompt` | Yes | — | Prompt text |\n| `label` | No | auto | Display label for results |\n| `context` | No | `{}` | Optional context metadata dict |\n| `execution_mode` | No | pref or `\"default\"` | `\"default\"` or `\"yolo\"` |\n| `model` | No | pref or CLI default | Model name override |\n| `max_retries` | No | pref or env default | Max retry attempts for transient errors |\n| `output_limit` | No | pref or env default | Max output bytes |\n| `timeout` | No | pref or env default | Subprocess timeout in seconds |\n| `retry_base_delay` | No | pref or env default | Base delay for exponential backoff |\n| `retry_max_delay` | No | pref or env default | Max delay cap for backoff |\n\n> **Note:** `elicit` is a batch-level parameter. When enabled, the server runs a single upfront elicitation pass across all tasks rather than prompting per-task.\n\n#### `prompt`\n\nSame parameters as a single task object in `batch_prompt`, plus `elicit` (batch-level in `batch_prompt`, per-call here).\n\n#### `set_preferences`\n\n| Parameter | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `execution_mode` | No | — | `\"default\"` or `\"yolo\"` |\n| `model` | No | — | Model name (e.g. `\"gpt-5.2\"`) |\n| `max_retries` | No | — | Max total attempts (≥1; 1 = no retries) |\n| `output_limit` | No | — | Max output bytes (≥1) |\n| `timeout` | No | — | Subprocess timeout seconds (≥1) |\n| `retry_base_delay` | No | — | Backoff base delay seconds (≥0) |\n| `retry_max_delay` | No | — | Backoff max delay seconds (≥0) |\n| `elicit` | No | `true` | Enable/disable elicitation |\n| `confirm_yolo` | No | `true` | Prompt before YOLO mode (auto-suppressed after first accept) |\n| `confirm_vague_prompt` | No | `true` | Prompt on very short prompts |\n| `confirm_high_retries` | No | `true` | Prompt when max_retries > 5 |\n| `confirm_large_batch` | No | `true` | Prompt when batch > 5 tasks |\n| `clear_*` | No | `false` | Clear any field individually (e.g. `clear_model: true`) |\n\n#### `get_preferences` / `clear_preferences`\n\n`get_preferences` — no parameters, returns all fields (`null` when unset).\n`clear_preferences` — no parameters, resets all to `null`. Does **not** clear model tiers.\n\n#### `set_model_tiers`\n\n| Parameter | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `tiers` | Yes | — | Dict mapping model names to tiers (`\"quick\"`, `\"standard\"`, `\"thorough\"`) |\n\nPersists tier classifications. Clients typically call once via sampling or benchmark fetch.\n\n#### `get_model_tiers`\n\nNo parameters. Returns saved tiers as `dict[str, str]`, or `{}` if none saved.\n\n</details>\n\n### Managing Preferences\n\n| Operation | Tool | Notes |\n|-----------|------|-------|\n| Set fields | `set_preferences` | Persists across sessions |\n| Read values | `get_preferences` | `null` for unset fields |\n| Clear all | `clear_preferences` | Does not clear model tiers |\n| Clear one field | `set_preferences` with `clear_*: true` | Others preserved |\n| Suppress elicitation | `set_preferences` with `confirm_*: false` | YOLO/batch/retry auto-suppress after accept |\n| Re-enable prompt | `set_preferences` with `clear_confirm_*: true` | Resets to default |\n| Save/read tiers | `set_model_tiers` / `get_model_tiers` | Persists across sessions |\n\n## Durable Job Architecture\n\nThe framework-independent core separates normalized domain contracts from concrete backends,\nstorage, and the MCP transport. A **job** is one admitted operation and owns its retry attempts,\nevents, controls, and terminal result. A **session** is a durable conversation identity bound to one\nworkspace and backend; `agent_start` creates it, `agent_continue` reuses it, and `agent_fork`\ncreates a child when supported. Diagnostic jobs may be sessionless. A session and a job are not MCP\nclient sessions or FastMCP background-task IDs.\n\nJobs and sessions use `private | workspace` access policies:\n\n- `private` (the default) is visible only to the owning principal.\n- `workspace` is visible to the owner and to callers explicitly authorized for that same workspace.\n  It never grants cross-workspace access. For the local MCP adapter, the operating-system user is\n  the principal and the private database permissions form the trust boundary.\n\nThe SQLite database contains sensitive prompts, normalized events, provider references, and\nresults. Set `NEXUS_DB_PATH` to override its location. Otherwise Nexus uses these per-user paths:\n\n- macOS: `~/Library/Application Support/nexus-mcp/nexus.sqlite3`\n- Windows: `%LOCALAPPDATA%\\nexus-mcp\\nexus.sqlite3` (falling back to\n  `~/AppData/Local/nexus-mcp/nexus.sqlite3`)\n- Linux and other Unix platforms:\n  `${XDG_DATA_HOME:-~/.local/share}/nexus-mcp/nexus.sqlite3`\n\nOn POSIX systems Nexus removes group and other access from the database directory and SQLite files.\nNormalized job, session, event, and result records are retained indefinitely by default; Nexus does\nnot schedule automatic pruning. Applying retention cutoffs is an explicit store operation, and no\npublic MCP pruning tool is currently exposed.\n\nCodex, Claude Code, and OpenCode execution currently passes through the temporary\n`LegacyRunnerBackend` bridge while native backends are developed. The bridge supports normalized\nturns only: it does not provide backend cancellation, graceful interruption, session forking, or\nsafe reconciliation after an interrupted attempt. These are legacy-backend limitations, not core\njob-model promises; clients should inspect `agent_backends` capabilities before selecting an\noperation.\n\n## MCP Prompts\n\nNexus MCP provides 10 discoverable prompt templates that clients can browse via `list_prompts()` and render via `get_prompt(name, args)`. Each prompt returns structured messages with expert framing — the client decides how (or whether) to use them.\n\n**Design principle:** Server informs, client decides. Prompts provide the scaffold (role, structure, methodology); the client decides runner, model, depth, and orchestration. Prompts are completely optional — existing `prompt`/`batch_prompt` tools work exactly as before.\n\n| Prompt | Tags | Parameters | Purpose |\n|--------|------|------------|---------|\n| `code_review` | analysis | `file`, `instructions` | Structured code review with findings by severity |\n| `debug` | analysis | `error`, `context`, `file` | Systematic diagnosis: reproduce, isolate, root cause, fix |\n| `quick_triage` | analysis | `description`, `file` | Fast assessment: what's wrong, severity, next step |\n| `research` | analysis | `topic`, `scope` | Structured research with source citations |\n| `second_opinion` | analysis | `original_output`, `question` | Independent review of another AI's output |\n| `implement_feature` | generation | `description`, `language`, `constraints` | Feature implementation with quality checklist |\n| `refactor` | generation | `file`, `goal`, `constraints` | Behavior-preserving restructuring |\n| `bulk_generate` | generation | `template`, `variables` | Expand template across variable sets |\n| `write_tests` | testing | `file`, `framework`, `coverage_goal` | Test generation with configurable coverage approach |\n| `compare_models` | comparison | `prompt`, `criteria` | Multi-runner comparison framework |\n\n<details>\n<summary><strong>Example — using a prompt template</strong></summary>\n\n```\n# 1. Client discovers available prompts\nlist_prompts() → sees \"code_review\", \"debug\", \"compare_models\", etc.\n\n# 2. Client renders a prompt with arguments\nget_prompt(\"code_review\", {file: \"src/auth.py\", instructions: \"security vulnerabilities\"})\n\n# 3. Server returns structured messages\n→ PromptResult(\n    messages=[\n      Message(\"You are a senior code reviewer...\", role=\"assistant\"),\n      Message(\"Review the file `src/auth.py`...\\nFocus: security vulnerabilities\\n...\", role=\"user\"),\n    ],\n    description=\"Code review of src/auth.py\"\n  )\n\n# 4. Client feeds messages into prompt/batch_prompt with chosen runner+model\nprompt(cli=\"claude\", prompt=<rendered messages>)\n```\n\n</details>\n\n## MCP Resources\n\nRead-only data endpoints that clients query for runner metadata, configuration, and preferences.\n\n| Resource URI | Description |\n|---|---|\n| `nexus://runners` | All registered CLI runners with models (enriched with tier data), modes, availability |\n| `nexus://runners/{cli}` | Single runner details by name (URI template) |\n| `nexus://config` | Resolved operational config defaults (timeouts, retries, output limits) |\n| `nexus://preferences` | Current preferences with config fallback |\n\nModels in `nexus://runners` include tier data: `{\"name\": \"gpt-5.4-mini\", \"tier\": \"quick\"}`. Tiers are `quick` (fast/cheap), `standard` (balanced), or `thorough` (max quality). Models with only heuristic tiers appear in `unclassified_models` — calling `set_model_tiers` moves them out.\n\n<details>\n<summary><strong>Model tier enrichment examples</strong></summary>\n\n**Before `set_model_tiers`** — all tiers are heuristic guesses, all models are unclassified:\n\n```json\n{\n  \"models\": [\n    {\"name\": \"gpt-5.1-codex-max\", \"tier\": \"thorough\"},\n    {\"name\": \"gpt-5.4-mini\", \"tier\": \"quick\"},\n    {\"name\": \"claude-sonnet-4-6\", \"tier\": \"standard\"}\n  ],\n  \"unclassified_models\": [\"gpt-5.1-codex-max\", \"gpt-5.4-mini\", \"claude-sonnet-4-6\"]\n}\n```\n\n**After `set_model_tiers`** — saved tiers replace heuristics, classified models leave the list:\n\n```json\n{\n  \"models\": [\n    {\"name\": \"gpt-5.1-codex-max\", \"tier\": \"thorough\"},\n    {\"name\": \"gpt-5.4-mini\", \"tier\": \"quick\"},\n    {\"name\": \"claude-sonnet-4-6\", \"tier\": \"standard\"}\n  ],\n  \"unclassified_models\": []\n}\n```\n\n</details>\n\n<details>\n<summary><h2>Configuration</h2></summary>\n\n### Global Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `NEXUS_DB_PATH` | Platform per-user data directory | Durable SQLite job database; contains sensitive prompts and results |\n| `NEXUS_OUTPUT_LIMIT_BYTES` | `50000` | Max output size in bytes before temp-file spillover |\n| `NEXUS_TIMEOUT_SECONDS` | `600` | Subprocess timeout in seconds (10 minutes) |\n| `NEXUS_TOOL_TIMEOUT_SECONDS` | `900` | Tool-level timeout in seconds (15 minutes); set to `0` to disable |\n| `NEXUS_RETRY_MAX_ATTEMPTS` | `3` | Max attempts including the first (set to 1 to disable retries) |\n| `NEXUS_RETRY_BASE_DELAY` | `2.0` | Base seconds for exponential backoff |\n| `NEXUS_RETRY_MAX_DELAY` | `60.0` | Maximum seconds to wait between retries |\n| `NEXUS_CLI_DETECTION_TIMEOUT` | `30` | Timeout in seconds for CLI binary version detection at startup |\n| `NEXUS_EXECUTION_MODE` | `default` | Global execution mode (`default` or `yolo`) |\n\n### Per-Runner Environment Variables\n\nPattern: `NEXUS_{AGENT}_{KEY}` (agent name uppercased). Per-runner values override global values.\n\nValid `{AGENT}` values: `CLAUDE`, `CODEX`, `OPENCODE`, `OPENCODE_SERVER`\n\n| Variable pattern | Example | Description |\n|----------|---------|-------------|\n| `NEXUS_{AGENT}_MODEL` | `NEXUS_CODEX_MODEL=gpt-5.2` | Default model for this runner |\n| `NEXUS_{AGENT}_MODELS` | `NEXUS_CODEX_MODELS=gpt-5.2,gpt-5.4-mini` | Comma-separated model list (surfaced in server instructions) |\n| `NEXUS_{AGENT}_TIMEOUT` | `NEXUS_CODEX_TIMEOUT=900` | Subprocess timeout override |\n| `NEXUS_{AGENT}_OUTPUT_LIMIT` | `NEXUS_CODEX_OUTPUT_LIMIT=100000` | Output limit override |\n| `NEXUS_{AGENT}_MAX_RETRIES` | `NEXUS_CLAUDE_MAX_RETRIES=5` | Max retry attempts override |\n| `NEXUS_{AGENT}_RETRY_BASE_DELAY` | `NEXUS_CLAUDE_RETRY_BASE_DELAY=1.0` | Backoff base delay override |\n| `NEXUS_{AGENT}_RETRY_MAX_DELAY` | `NEXUS_OPENCODE_RETRY_MAX_DELAY=30.0` | Backoff max delay override |\n| `NEXUS_{AGENT}_EXECUTION_MODE` | `NEXUS_CODEX_EXECUTION_MODE=yolo` | Execution mode override |\n\nInvalid per-runner values are silently ignored (the global or hardcoded default is used instead).\n\n</details>\n\n<details>\n<summary><h2>Development</h2></summary>\n\n### Testing\n\nThis project follows **Test-Driven Development (TDD)** with strict Red→Green→Refactor cycles.\n\n```bash\n# Run all tests\nuv run pytest\n\n# Run with coverage report\nuv run pytest --cov=nexus_mcp --cov-report=term-missing\n\n# Run specific test types\nuv run pytest -m integration           # Integration tests (requires CLIs)\nuv run pytest -m \"not integration\"     # Unit tests only\nuv run pytest -m \"not slow\"            # Skip slow tests\n\n# Run specific test file\nuv run pytest tests/unit/runners/test_codex.py\n```\n\n**Test markers:**\n- `@pytest.mark.integration` — requires real CLI installations\n- `@pytest.mark.slow` — tests taking >1 second\n\n### Code Quality\n\nAll quality checks run automatically via pre-commit hooks. Run manually:\n\n```bash\n# Lint and format\nuv run ruff check .              # Check for issues\nuv run ruff check --fix .        # Auto-fix issues\nuv run ruff format .             # Format code\n\n# Type checking (strict mode)\nuv run mypy src/nexus_mcp\n\n# Run all pre-commit hooks manually\nuv run pre-commit run --all-files\n```\n\n### Adding Dependencies\n\n```bash\nuv add <package>              # Production dependency\nuv add --dev <package>        # Development dependency\nuv sync                       # Sync environment after changes\n```\n\n### Tool Configuration\n\n- **Ruff:** line length 100, 17 rule sets (E/F/I/W + UP/FA/B/C4/SIM/RET/ICN/TID/TC/ISC/PTH/TD/NPY) — `pyproject.toml → [tool.ruff]`\n- **Mypy:** strict mode, all type annotations required — `pyproject.toml → [tool.mypy]`\n- **Pytest:** `asyncio_mode = \"auto\"`, no `@pytest.mark.asyncio` needed — `pyproject.toml → [tool.pytest.ini_options]`\n- **Pre-commit:** ruff-check, ruff-format, mypy, trailing-whitespace, end-of-file-fixer — `.pre-commit-config.yaml`\n\n### Python 3.13+ Syntax\n\n- `type` keyword for type aliases: `type AgentName = str`\n- Union syntax: `str | None` (not `Optional[str]`)\n- `match` statements for complex conditionals\n- **NO** `from __future__ import annotations`\n\n### Project Structure\n\n```\nnexus-mcp/\n├── src/nexus_mcp/\n│   ├── __main__.py          # Entry point\n│   ├── core/                # Framework- and provider-independent domain contracts\n│   ├── backends/            # Typed backend protocols and runtime registry\n│   ├── jobs/                # Job service, worker, SQLite store, and migrations\n│   ├── legacy/              # Temporary adapter over existing CLI runners\n│   ├── mcp/                 # FastMCP transport adapter\n│   │   ├── server.py        # Server, compatibility tools, and registration\n│   │   ├── job_tools.py     # Typed durable agent_* tools\n│   │   ├── runtime.py       # MCP lifespan ownership for job runtime services\n│   │   └── prompts/         # Discoverable prompt templates\n│   ├── server.py            # Compatibility re-export for the MCP server\n│   ├── types.py             # Compatibility request and response models\n│   ├── exceptions.py        # Exception hierarchy\n│   ├── config.py            # Legacy environment configuration\n│   ├── process.py           # Legacy subprocess wrapper\n│   ├── parser.py            # Legacy JSON-to-text output parsing\n│   ├── cli_detector.py      # CLI binary detection and version checks\n│   └── runners/\n│       ├── base.py          # Legacy runner protocol and template method\n│       ├── factory.py       # RunnerFactory\n│       ├── claude.py        # ClaudeRunner\n│       ├── codex.py         # CodexRunner\n│       ├── opencode.py      # OpenCodeRunner\n│       └── opencode_server.py # OpenCode server runner\n├── tests/\n│   ├── unit/               # Fast, mocked tests\n│   │   └── prompts/        # Prompt template tests\n│   ├── e2e/                # End-to-end MCP protocol tests\n│   ├── integration/        # Real CLI tests\n│   └── fixtures.py         # Shared test utilities\n├── .github/\n│   └── workflows/          # CI, security, dependabot\n├── pyproject.toml          # Dependencies + tool config\n└── .pre-commit-config.yaml # Git hooks configuration\n```\n\n</details>\n\n## Releases\n\nStable releases are cut by running the **Tag Release** workflow from the Actions\ntab and choosing a bump (`auto` infers it from Conventional Commits since the\nlast tag). Pre-releases are tagged manually. See [RELEASE.md](RELEASE.md) for\nthe full maintainer workflow, recovery steps, and notes on `server.json`\nplaceholder fields.\n\n## License\n\nMIT\n",
  "bytes": 32186,
  "sha": "04be6864a9f9d8596200ebf88f99faff88a989d4edafe20b41b55c8debeaeb9d",
  "repo_slug": "j7an/nexus-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_j7an_nexus_mcp_c7a033b7/readme"
}