Metadata-Version: 2.5
Name: zeus-dev-helper-mcp
Version: 0.7.9
Summary: Developer Helper MCP — first Zeus-powered app onboarding coach (ZDH)
Project-URL: Homepage, https://docs.koten.ai/zeus-client/dev-helper-mcp
Project-URL: Documentation, https://docs.koten.ai/zeus-client/dev-helper-mcp
Project-URL: Repository, https://github.com/koten-ai/zeus_dev_helper_mcp
Project-URL: Changelog, https://github.com/koten-ai/zeus_dev_helper_mcp/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/koten-ai/zeus_dev_helper_mcp/issues
Author: Koten AI
License-Expression: BSD-3-Clause
License-File: LICENSE
Keywords: coach,koten,mcp,onboarding,zeus
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp<3,>=1.8.0
Provides-Extra: agent
Requires-Dist: kotenai-zeus-client>=2.3.0; extra == 'agent'
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine>=5.1; extra == 'dev'
Description-Content-Type: text/markdown

# Zeus Dev Helper MCP

<!-- mcp-name: io.github.koten-ai/zeus-dev-helper -->

Stdio MCP server that coaches a coding agent and a human to a first successful Zeus Client app turn.

This is not a data-plane MCP. It does not run Explore/Verify verbs on your behalf, invent contract hashes, or perform Hub admin mutations. After the first-green smokes pass, data-plane and multi-agent work are **handoffs only**.

| | |
| --- | --- |
| **Package** | `zeus-dev-helper-mcp` |
| **Registry name** | `io.github.koten-ai/zeus-dev-helper` |
| **Transport** | stdio |
| **Python** | 3.11+ |
| **MCP SDK** | `mcp` (`FastMCP` on 1.x / `MCPServer` on 2.x) |

## What it does

The server walks a first-app checklist: prereqs, live readiness on the public Zeus API, catalog templates, contract bind (copy a stamped hash only), surface/verb coaching, config lint, and smoke tests. Prefer a live Zeus stamp for catalogs. `fetch_chat_request` is always **template only**.

Hard constraints the tools enforce:

- Public Zeus API on port **8080** only (never Hub **9091** from the app path)
- Never invent `contract_hash`
- No secrets in tool results, checklist evidence, or support packs
- Semantic cache stays off

## Install

`verify_local_setup` and `smoke_test_agent` import `zeus_client` in this Helper process. Install the `agent` extra into that environment. The app `.venv` does not satisfy the check.

```bash
pip install "zeus-dev-helper-mcp[agent]"
# or
uvx --from 'zeus-dev-helper-mcp[agent]' zeus-dev-helper-mcp
```

## Run

```bash
zeus-dev-helper-mcp
# or
python -m zeus_dev_helper_mcp
```

Prefer the published console script (`uvx` / `pip install`) so hosts do not need a source checkout.

## Host install

Set `ZEUS_URL` to your Zeus **public API** on port **8080** (never Hub `:9091`). Prefer the remote host you actually use. Use `http://localhost:8080` only when Zeus runs on the **same machine** as the MCP host.

```bash
# Remote Zeus (typical lab / shared engine) — put your host here
export ZEUS_URL=http://192.168.0.219:8080
# or: http://<zeus-host>:8080
#
# Same-machine Zeus only:
# export ZEUS_URL=http://localhost:8080
```

If the user names a URL or sample in chat, call **`set_prereq`** with that `zeus_url` / bucket / scope (do not keep a stale localhost default). `doctor` reports **stored vs effective** URL routing (see [ZDM-3](https://kotenai.atlassian.net/browse/ZDM-3)).

### Grok Build

`grok mcp add` treats flags like `-m` as its own unless they come **after `--`**. The `uvx` argument is the **PyPI package** `zeus-dev-helper-mcp`, not the MCP server id `zeus-dev-helper`.

```bash
grok mcp add zeus-dev-helper \
  -e ZEUS_URL=http://192.168.0.219:8080 \
  -- uvx --from 'zeus-dev-helper-mcp[agent]' zeus-dev-helper-mcp
```

From a local checkout after `pip install -e ".[dev,agent]"`, point `command` at this tree’s venv so the host can start the server even when it was launched without the venv activated:

```bash
grok mcp add zeus-dev-helper \
  -e ZEUS_URL=http://192.168.0.219:8080 \
  -- "$(pwd)/.venv/bin/python" -m zeus_dev_helper_mcp
```

Equivalent config:

```toml
[mcp_servers.zeus-dev-helper]
command = "uvx"
args = ["--from", "zeus-dev-helper-mcp[agent]", "zeus-dev-helper-mcp"]
env = { ZEUS_URL = "http://192.168.0.219:8080" }
enabled = true
```

Then refresh MCP servers, or `grok mcp doctor zeus-dev-helper`.

Common failures:

- `unexpected argument '-m'` — missing `--` before the python command
- `uvx zeus-dev-helper` / `No solution found` — wrong package name; use **`uvx --from 'zeus-dev-helper-mcp[agent]' zeus-dev-helper-mcp`**
- `No module named 'zeus_client'` — this Helper process has no `agent` extra. Installing `kotenai-zeus-client` into the app `.venv` leaves the check red. Restart the MCP server after installing the extra into the Helper environment.
- `No module named 'zeus_dev_helper_mcp'` / `python: No such file or directory` — the host did not inherit the venv; use the `.venv/bin/python` path above
- `No module named 'mcp.server.fastmcp'` — mcp 2.x renamed FastMCP; use Helper **0.6.0+** (`mcp>=1.8.0,<3`)

### Claude Code / Claude Desktop

```json
{
  "mcpServers": {
    "zeus-dev-helper": {
      "command": "uvx",
      "args": ["--from", "zeus-dev-helper-mcp[agent]", "zeus-dev-helper-mcp"],
      "env": {
        "ZEUS_URL": "http://192.168.0.219:8080"
      }
    }
  }
}
```

### Cursor

Add (or merge) `.cursor/mcp.json` in the project (or use Cursor’s global MCP settings):

```json
{
  "mcpServers": {
    "zeus-dev-helper": {
      "command": "uvx",
      "args": ["--from", "zeus-dev-helper-mcp[agent]", "zeus-dev-helper-mcp"],
      "env": {
        "ZEUS_URL": "http://192.168.0.219:8080"
      }
    }
  }
}
```

### Codex

The permission profile `:workspace` does not enable network. With `sandbox_approval` false, Codex does not ask to enable it. Pip then reports `[Errno -2] Name or service not known`. That is `EAI_NONAME` from the closed network. A package host that answers outside the sandbox can still look like a DNS failure inside it.

Set a top-level profile that extends `:workspace` and enables network. Do not also set `sandbox_mode` or `[sandbox_workspace_write]`. Start a new Codex thread after the change. Leave the network proxy off unless localhost is allowlisted, because sandboxed commands still need local Zeus.

```toml
default_permissions = "workspace-net"

[permissions.workspace-net]
description = "Workspace writes plus outbound network so sandboxed commands can resolve package hosts."
extends = ":workspace"

[permissions.workspace-net.network]
enabled = true
```

```toml
[mcp_servers.zeus-dev-helper]
command = "uvx"
args = ["--from", "zeus-dev-helper-mcp[agent]", "zeus-dev-helper-mcp"]
```

Install the app `requirements.txt` from a process that already has network. That install does not put `zeus_client` on the Helper interpreter. Restart the MCP server after the Helper environment gains the `agent` extra.

### Other stdio hosts

Point the host’s MCP stdio entry at `uvx --from 'zeus-dev-helper-mcp[agent]' zeus-dev-helper-mcp` (or `python -m zeus_dev_helper_mcp` from a venv that has the `agent` extra) with the same env vars. Replace the sample IP with your Zeus host.

## Day-one coach path

```text
doctor → (if user named URL/sample) set_prereq → start_project → next_step
  → readiness_check
  → use_sample | scaffold_app → bind_contract → recommend_surface
  → smoke_test_zeus → smoke_test_agent → diagnose_error
```

Prefer `next_step` over dumping the full checklist. Two first-green paths (TravelPlan is **not** the only path):

- **Travel + LLM (UI default):** `start_project(sample=travel)` → **`use_sample`**, which **clones** public [`demo_travel_sample`](https://github.com/koten-ai/demo_travel_sample) when missing (optional `project_name` for the directory) and sets `DEMO_TRAVEL_SAMPLE_DIR`. Checklist **1.2** stays open until this process has `LLM_API_KEY`, `XAI_API_KEY`, or `OPENAI_API_KEY`. `smoke_test_agent` reads that variable. Standalone clones pin `kotenai-zeus-client>=2.4.0,<2.5` so `run_turn` can recover a fenced pipeline inside the SDK.
- **Beer catalog UI:** `start_project(sample=beer)` → `use_sample(sample=beer)` **clones** public [`demo_beer_sample`](https://github.com/koten-ai/demo_beer_sample) when missing and sets `DEMO_BEER_SAMPLE_DIR`. That checkout is the app. Start it with Python 3.11 or newer. The `use_sample` run string uses `python3 -m venv` only when `python3` is 3.11 or newer. Then `pip install -r requirements.txt` and `python main.py` (binds `127.0.0.1:8090`). When that checkout has both a `Dockerfile` and a compose file, `use_sample` asks the agent to let the user choose Python or Docker before either command starts. `website_green(serve_with=python|docker)` records the choice. The helper does not run Docker. That requirements file installs `kotenai-zeus-client>=2.5.3,<2.6` from PyPI. `use_sample` writes mode 600 `.env` from `.env.example`, keeps populated values, and adds missing template keys. It resolves `LLM_API_KEY`, `LLM_BASE_URL`, and `LLM_MODEL` together, and copies `OPENAI_API_KEY` or `XAI_API_KEY` only when the base URL and model match that provider. The clone keeps `LLM_MODEL=grok-4.5-latest`. `run` and `next_action` do not say to copy `.env.example` over that file. `website_green` does not run pip when the app `.venv` is older than 3.11. Lists are Direct and need no LLM key. Pour matches travel: `rt.agent.run_turn` with `chat_request` omitted so `catalog.load_for_turn` merges the live SCOPE BRIEF and MINI-SCHEMA. A helper-written catalog page uses `max_rounds` 4. Pour stays off until `LLM_API_KEY`, `XAI_API_KEY`, or `OPENAI_API_KEY` is in the app `.env`, including when `has_llm_key=false`. Leave `config.json` `llm.api_key_env` as that variable name. `verify_local_setup` keeps checklist **3.2** open until that file check passes. The BFF does not build a pipeline body. Do not clone `demo_travel_sample`. Do not write a job for this one-scope page.
- **Yelp demo UI:** `start_project(sample=demo_yelp)` → `use_sample(sample=demo_yelp)` **clones** the LocalAI template [`demo_yelp`](https://github.com/koten-ai/demo_yelp) when missing (utterances `yelp-demo` / `demo_yelp`) and sets `DEMO_YELP_SAMPLE_DIR`. When `parent_dir` is set, the clone is created in that directory. That checkout is the app: run it, and do not write a replacement or copy the beer sample. `use_sample` also downloads the public business photo set into `frontend/public/business-images/<id>/{1,2,3}.png` (no `biz:` prefix, no API key). Search POSTs `/api/search` and sends the live chat request for `yelp-demo` / `_default` as the session body. Search cards unwrap a hybrid `{node, score}` hit and a nested pipeline row. The business page GETs `/api/business/{id}` when the id is not in the bundled catalog. Review text is the source document, not a `rev:` doc key. `set_prereq` bucket is `yelp-demo`, scope `_default`. Do not clone `demo_travel_sample`. Bare `sample=yelp` stays the multi-agent handoff.
- **API-only:** user asks for an API/REST app → `start_project(sample=api)` → `scaffold_app(app_kind=api, coding_language=python)` (FastAPI `POST /turn` on `kotenai-zeus-client`). Other languages not scaffolded yet.
- Credentials from chat → process env / gitignored `.env`; `set_prereq` presence flags only. `has_llm_key=true` does not count as the key. Pass the user’s Zeus URL into `set_prereq(zeus_url=…)`. Do not paste the secret into `llm.api_key_env`.
- Integrating into an arbitrary existing repo is **out of scope**.

Read `zeus-helper://` resources for glossary, verbs, policies, and catalog modes. Hosts can pick prompts `first_green`, `smoke_question`, and `support_pack`.

## Default tools (`core`)

Live `tools/list` is the call contract. Default surface is the **core** toolset (`ZEUS_DEV_HELPER_TOOLSETS=core`).

| Tool | Job |
| --- | --- |
| `doctor` | Health. `detail=health\|env\|compat\|cache\|all` (env/compat/cache fold lint-toolset checks) |
| `start_project` | Init checklist; `sample=travel` (UI default), `sample=beer` (catalog UI, `run_turn`), `sample=demo_yelp` (clone `demo_yelp`), or `sample=api` |
| `next_step` | Current item plus recommended tools and resource links |
| `set_prereq` | Store non-secret prereqs (presence flags only; `has_llm_key` is not the key) |
| `readiness_check` | Live gates: healthz / readyz / version, auth, bootstrap. Marks **1.2** done only when the URL is set and, on a `run_turn` path, the process has an LLM key |
| `explain_scope` | Live public `:8080` `chat_request.json` summary: entity types, display fields, text-search fields, FK fields, and list/detail/search verbs. When that body has no `## MINI-SCHEMA` heading, parse `bootstrap.chat_request`. A failed stamp leaves entity types empty. `fetch_chat_request` stays template only |
| `scaffold_app` | CLI or FastAPI (`app_kind=cli\|api`) ZeusRuntime app; python only |
| `use_sample` | Travel UI clone, beer catalog clone (`demo_beer_sample`, `python main.py`, Direct lists, Pour `run_turn` with `chat_request` omitted), `sample=catalog` from `explain_scope`, or yelp demo clone (`sample=demo_yelp`, sets `DEMO_YELP_SAMPLE_DIR`; downloads public photos into `frontend/public/business-images/<id>/`, no API key; live search and business page, review text from the source document) |
| `bind_contract` | Copy a stamped `contract.hash` only. With no path, the source is the live bootstrap `chat_request`. A directory pointer is not a catalog. Refuses empty / local compute |
| `recommend_surface` | Intent → Client surface + do-not list |
| `smoke_test_zeus` | No LLM: readiness plus a read-only describe |
| `website_green` | Install, start, and check the catalog page (named list card, page ids, search when Pour is on). A title-cased `doc_key` is not a search card. A describe 200 is not this check |
| `smoke_test_agent` | One Client `run_turn`. Needs `[agent]` extra and `LLM_API_KEY`, `XAI_API_KEY`, or `OPENAI_API_KEY` in this process |
| `diagnose_error` | Map a symptom, hop name, and result keys to a failure class and one generated-file change |
| `sample_support_pack` | Read-only paste for a beer, travel, or yelp-demo gate failure. Writes nothing and calls no Zeus API. Session ids stay in `support_pack_from_turn` |

Opt-in toolsets (static, comma-separated): `catalog`, `lint`, `travel`, `support`, `handoff`. `all` enables every set. Full when/args/side-effects map: [`docs/TOOLS.md`](docs/TOOLS.md).

Resources (always on): `zeus-helper://checklist`, `zeus-helper://glossary/{topic}`, `zeus-helper://verbs/{name}`, `zeus-helper://policy/hash-boundary`, `zeus-helper://policy/req-id`, `zeus-helper://catalog/modes`.

## Environment

Secrets stay in the process environment. `set_prereq` stores presence flags only. Tool results redact secret values.

| Variable | Purpose |
| --- | --- |
| `ZEUS_URL` | Public Zeus API base URL (port 8080). Remote host first; `localhost` only when Zeus is local |
| `ZEUS_BUCKET` / `ZEUS_SCOPE` / `ZEUS_COLLECTION` | Scope for bootstrap and auth probes |
| `ZEUS_MODE` | Default catalog mode (`analytics`) |
| `ZEUS_AUTH_MODE` | Auth mode (`none`, basic, bearer) |
| `ZEUS_USERNAME` / `ZEUS_PASSWORD` | Basic auth (never logged) |
| `ZEUS_BEARER_TOKEN` | Bearer auth (never logged) |
| `LLM_API_KEY` / `XAI_API_KEY` / `OPENAI_API_KEY` | Process key for checklist **1.2**, `validate_env`, and `smoke_test_agent`. The app `.env` needs the same name for Pour / `uvicorn`. `config.json` `llm.api_key_env` stays the name. A stored `has_llm_key` flag does not count |
| `LLM_BASE_URL` / `LLM_MODEL` | OpenAI-compatible endpoint and model. Offered defaults: Grok `https://api.x.ai/v1` / `grok-4.5-latest`, OpenAI `https://api.openai.com/v1` / `gpt-5.6-sol`, Anthropic `https://api.anthropic.com/v1` / `claude-opus-5-5`, Gemini `https://generativelanguage.googleapis.com/v1beta/openai/` / `gemini-3.8-flash`, or a base URL the user types. `load_process_login` reads both names from a mode-600 file |
| `ZEUS_CHAT_REQUEST_DIR` | Local directory of min catalog templates; auto-set when `list_catalog_modes` / `fetch_chat_request` locate or clone public `zeus_chat_request` |
| `DEMO_TRAVEL_SAMPLE_DIR` | Local sample directory for `use_sample` / `travel_golden_path` |
| `DEMO_YELP_SAMPLE_DIR` | Local `demo_yelp` directory for `use_sample(sample=demo_yelp)` |
| `BUSINESS_IMAGES_BASE_URL` | Optional CDN prefix for the yelp photo download (no trailing slash). Default is the public `koten-yelp-demo-photos` Space. No API key |
| `ZEUS_DEV_HELPER_SKIP_YELP_IMAGES` | Set to `1` to skip the yelp photo download during `use_sample(sample=demo_yelp)` |
| `YELP_IMAGE_FETCH_WORKERS` | Parallel downloads for that photo set. Default `8` |
| `ZEUS_DEV_HELPER_STATE_DIR` | Checklist, prereqs, local metrics, the write-once sample creation logs (`beer-sample-build.md`, `travel-sample-build.md`, `yelp-demo-build.md`), and the support journals (`beer-sample-support.md`, `travel-sample-support.md`, `yelp-demo-support.md`). Default `~/.config/zeus_dev_helper` |
| `ZEUS_DEV_HELPER_TOOLSETS` | Static toolsets: `core` (default), plus `catalog,lint,travel,support,handoff` or `all` |

## Boundaries

| This MCP | Not this MCP |
| --- | --- |
| Onboarding coach to first green | Data-plane Explore/Verify tools |
| Catalog **templates** plus readiness and smoke | Inventing or locally computing `contract_hash` |
| Verb explain / lint / draft (`posted=false`) | POSTing `find` / `search` / `get` / `pipeline` |
| Detective **URL templates** | Hub scrape or Hub admin mutations |
| Multi / data-plane **handoffs** | Multi-agent job runtime |
| Local checklist and metrics | Shipping secrets in evidence or support packs |

## Dev install

From a local checkout:

```bash
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,agent]"
export ZEUS_URL=http://localhost:8080
```

```bash
pytest -q
```

## MCP Registry

Official registry name: `io.github.koten-ai/zeus-dev-helper`. The registry hosts metadata only; the install artifact is the PyPI package `zeus-dev-helper-mcp`.

## License

BSD-3-Clause — see [LICENSE](LICENSE).
