From 68d8e875e0c0880e7e04941dd16200336a674d08 Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Fri, 13 Mar 2026 13:42:45 -0300 Subject: [PATCH] Add host-specific MCP onramps for major chat clients Ship first-class MCP setup examples for Claude Code, Codex, and OpenCode so new users can copy one exact command or config instead of translating the generic MCP template by hand. Reposition the docs to surface those host-specific examples before the generic config fallback, keep workspace-core as the recommended profile everywhere user-facing, and retain Claude Desktop/Cursor as secondary fallback examples. Bump the package and catalog to 3.11.0, mark the roadmap milestone done, and add docs-alignment coverage that pins the new examples to the canonical workspace-core server command and the expected OpenCode config shape. Validation: - uv lock - ./.venv/bin/pytest --no-cov tests/test_cli.py - UV_CACHE_DIR=.uv-cache make check - UV_CACHE_DIR=.uv-cache make dist-check --- CHANGELOG.md | 11 ++++ README.md | 44 ++++++++++++---- docs/first-run.md | 13 ++++- docs/install.md | 28 +++++++++- docs/integrations.md | 13 +++-- docs/roadmap/llm-chat-ergonomics.md | 10 ++-- .../3.11.0-host-specific-mcp-onramps.md | 2 +- examples/claude_code_mcp.md | 20 +++++++ examples/codex_mcp.md | 20 +++++++ examples/mcp_client_config.md | 11 +++- examples/opencode_mcp_config.json | 9 ++++ pyproject.toml | 2 +- src/pyro_mcp/vm_environments.py | 2 +- tests/test_cli.py | 52 +++++++++++++++++++ uv.lock | 2 +- 15 files changed, 211 insertions(+), 28 deletions(-) create mode 100644 examples/claude_code_mcp.md create mode 100644 examples/codex_mcp.md create mode 100644 examples/opencode_mcp_config.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6ea7f..2b6ae71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable user-visible changes to `pyro-mcp` are documented here. +## 3.11.0 + +- Added first-class host-specific MCP onramps for Claude Code, Codex, and + OpenCode so major chat-host users can copy one exact setup example instead of + translating the generic MCP config by hand. +- Reordered the main integration docs and examples so host-specific MCP setup + appears before the generic `mcpServers` fallback, while keeping + `workspace-core` as the recommended first profile everywhere user-facing. +- Kept Claude Desktop and Cursor as generic fallback examples instead of the + primary onramp path. + ## 3.10.0 - Aligned the five guest-backed workspace smoke scenarios with the recipe docs diff --git a/README.md b/README.md index 8e59c0a..cb7a3eb 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ It exposes the same runtime in three public forms: - Stable workspace walkthrough GIF: [docs/assets/workspace-first-run.gif](docs/assets/workspace-first-run.gif) - Terminal walkthrough GIF: [docs/assets/first-run.gif](docs/assets/first-run.gif) - PyPI package: [pypi.org/project/pyro-mcp](https://pypi.org/project/pyro-mcp/) -- What's new in 3.10.0: [CHANGELOG.md#3100](CHANGELOG.md#3100) +- What's new in 3.11.0: [CHANGELOG.md#3110](CHANGELOG.md#3110) - Host requirements: [docs/host-requirements.md](docs/host-requirements.md) - Integration targets: [docs/integrations.md](docs/integrations.md) - Public contract: [docs/public-contract.md](docs/public-contract.md) @@ -60,7 +60,7 @@ What success looks like: ```bash Platform: linux-x86_64 Runtime: PASS -Catalog version: 3.10.0 +Catalog version: 3.11.0 ... [pull] phase=install environment=debian:12 [pull] phase=ready environment=debian:12 @@ -156,19 +156,42 @@ policy, or disk tools. uvx --from pyro-mcp pyro mcp serve --profile workspace-core ``` -Minimal MCP config: +Copy-paste host-specific starts: + +- Claude Code: [examples/claude_code_mcp.md](examples/claude_code_mcp.md) +- Codex: [examples/codex_mcp.md](examples/codex_mcp.md) +- OpenCode: [examples/opencode_mcp_config.json](examples/opencode_mcp_config.json) +- Generic MCP config: [examples/mcp_client_config.md](examples/mcp_client_config.md) + +Claude Code: + +```bash +claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +``` + +Codex: + +```bash +codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +``` + +OpenCode `opencode.json` snippet: ```json { - "mcpServers": { + "mcp": { "pyro": { - "command": "uvx", - "args": ["--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"] + "type": "local", + "enabled": true, + "command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"] } } } ``` +If `pyro-mcp` is already installed, replace the `uvx --from pyro-mcp pyro` +command with `pyro` in the same host-specific command or config shape. + Profile progression: - `workspace-core`: recommended first profile for normal persistent chat editing @@ -226,7 +249,7 @@ uvx --from pyro-mcp pyro env list Expected output: ```bash -Catalog version: 3.10.0 +Catalog version: 3.11.0 debian:12 [installed|not installed] Debian 12 environment with Git preinstalled for common agent workflows. debian:12-base [installed|not installed] Minimal Debian 12 environment for shell and core Unix tooling. debian:12-build [installed|not installed] Debian 12 environment with Git and common build tools preinstalled. @@ -343,7 +366,7 @@ machine consumption, use `--id-only` for only the identifier or `--json` for the workspace payload. Use `--seed-path` when you want the workspace to start from a host directory or a local `.tar` / `.tar.gz` / `.tgz` archive instead of an empty workspace. Use `pyro workspace sync push` when you want to import -later host-side changes into a started workspace. Sync is non-atomic in `3.10.0`; if it fails +later host-side changes into a started workspace. Sync is non-atomic in `3.11.0`; if it fails partway through, prefer `pyro workspace reset` to recover from `baseline` or one named snapshot. Use `pyro workspace diff` to compare the live `/workspace` tree to its immutable create-time baseline, and `pyro workspace export` to copy one changed file or directory back to the host. Use @@ -577,7 +600,10 @@ Recommended MCP tool profiles: - Python one-shot SDK example: [examples/python_run.py](examples/python_run.py) - Python lifecycle example: [examples/python_lifecycle.py](examples/python_lifecycle.py) - Python workspace example: [examples/python_workspace.py](examples/python_workspace.py) -- MCP client config example: [examples/mcp_client_config.md](examples/mcp_client_config.md) +- Claude Code MCP setup: [examples/claude_code_mcp.md](examples/claude_code_mcp.md) +- Codex MCP setup: [examples/codex_mcp.md](examples/codex_mcp.md) +- OpenCode MCP config: [examples/opencode_mcp_config.json](examples/opencode_mcp_config.json) +- Generic MCP client config: [examples/mcp_client_config.md](examples/mcp_client_config.md) - Claude Desktop MCP config: [examples/claude_desktop_mcp_config.json](examples/claude_desktop_mcp_config.json) - Cursor MCP config: [examples/cursor_mcp_config.json](examples/cursor_mcp_config.json) - OpenAI Responses API example: [examples/openai_responses_vm_run.py](examples/openai_responses_vm_run.py) diff --git a/docs/first-run.md b/docs/first-run.md index ea54aa7..40e5c3d 100644 --- a/docs/first-run.md +++ b/docs/first-run.md @@ -22,7 +22,7 @@ Networking: tun=yes ip_forward=yes ```bash $ uvx --from pyro-mcp pyro env list -Catalog version: 3.10.0 +Catalog version: 3.11.0 debian:12 [installed|not installed] Debian 12 environment with Git preinstalled for common agent workflows. debian:12-base [installed|not installed] Minimal Debian 12 environment for shell and core Unix tooling. debian:12-build [installed|not installed] Debian 12 environment with Git and common build tools preinstalled. @@ -116,12 +116,21 @@ $ uvx --from pyro-mcp pyro workspace service start WORKSPACE_ID app --secret-env $ uvx --from pyro-mcp pyro workspace create debian:12 --network-policy egress+published-ports $ uvx --from pyro-mcp pyro workspace service start WORKSPACE_ID app --ready-http http://127.0.0.1:8080/ --publish 18080:8080 -- ./start-app $ uvx --from pyro-mcp pyro mcp serve --profile workspace-core +$ claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +$ codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core ``` For most chat hosts, `workspace-core` is the recommended first MCP profile. Move to `workspace-full` only when the host truly needs shells, services, snapshots, secrets, network policy, or disk tools. +Host-specific MCP starts: + +- Claude Code: [examples/claude_code_mcp.md](../examples/claude_code_mcp.md) +- Codex: [examples/codex_mcp.md](../examples/codex_mcp.md) +- OpenCode: [examples/opencode_mcp_config.json](../examples/opencode_mcp_config.json) +- Generic MCP config: [examples/mcp_client_config.md](../examples/mcp_client_config.md) + `pyro demo` proves the one-shot create/start/exec/delete VM lifecycle works end to end. Once that stable workspace flow works, continue with the five recipe docs in @@ -259,7 +268,7 @@ State: started Use `--seed-path` when the workspace should start from a host directory or a local `.tar` / `.tar.gz` / `.tgz` archive instead of an empty `/workspace`. Use `pyro workspace sync push` when you need to import later host-side changes into a started -workspace. Sync is non-atomic in `3.10.0`; if it fails partway through, prefer `pyro workspace reset` +workspace. Sync is non-atomic in `3.11.0`; if it fails partway through, prefer `pyro workspace reset` to recover from `baseline` or one named snapshot. Use `pyro workspace diff` to compare the current `/workspace` tree to its immutable create-time baseline, `pyro workspace snapshot *` to create named checkpoints, and `pyro workspace export` to copy one changed file or directory back to the diff --git a/docs/install.md b/docs/install.md index c00bb31..c7b2ccf 100644 --- a/docs/install.md +++ b/docs/install.md @@ -85,7 +85,7 @@ uvx --from pyro-mcp pyro env list Expected output: ```bash -Catalog version: 3.10.0 +Catalog version: 3.11.0 debian:12 [installed|not installed] Debian 12 environment with Git preinstalled for common agent workflows. debian:12-base [installed|not installed] Minimal Debian 12 environment for shell and core Unix tooling. debian:12-build [installed|not installed] Debian 12 environment with Git and common build tools preinstalled. @@ -243,6 +243,30 @@ For most chat-host integrations, start with `workspace-core`: uvx --from pyro-mcp pyro mcp serve --profile workspace-core ``` +Copy-paste host-specific starts: + +- Claude Code: [examples/claude_code_mcp.md](../examples/claude_code_mcp.md) +- Codex: [examples/codex_mcp.md](../examples/codex_mcp.md) +- OpenCode: [examples/opencode_mcp_config.json](../examples/opencode_mcp_config.json) +- Generic MCP config: [examples/mcp_client_config.md](../examples/mcp_client_config.md) + +Claude Code: + +```bash +claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +``` + +Codex: + +```bash +codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +``` + +OpenCode uses the `mcp`/`type: "local"` config shape shown in +[examples/opencode_mcp_config.json](../examples/opencode_mcp_config.json). If +`pyro-mcp` is already installed, replace the `uvx --from pyro-mcp pyro` +command with `pyro` in the same host-specific command or config shape. + Use profile progression like this: - `workspace-core`: recommended first profile for normal persistent chat editing @@ -296,7 +320,7 @@ the identifier programmatically, use `--id-only` for only the identifier or `--j workspace payload. Use `--seed-path` when the workspace should start from a host directory or a local `.tar` / `.tar.gz` / `.tgz` archive. Use `pyro workspace sync push` for later host-side changes to a started workspace. Sync -is non-atomic in `3.10.0`; if it fails partway through, prefer `pyro workspace reset` to recover +is non-atomic in `3.11.0`; if it fails partway through, prefer `pyro workspace reset` to recover from `baseline` or one named snapshot. Use `pyro workspace diff` to compare the current workspace tree to its immutable create-time baseline, `pyro workspace snapshot *` to capture named checkpoints, and `pyro workspace export` to copy one changed file or directory back to the host. Use diff --git a/docs/integrations.md b/docs/integrations.md index 47c5d6c..36b5bb3 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -63,12 +63,15 @@ Profile progression: - `pyro mcp serve --profile workspace-core` for the normal persistent chat loop - `pyro mcp serve --profile workspace-full` only when the model truly needs advanced workspace tools -Starter config: +Host-specific onramps: -- [examples/mcp_client_config.md](../examples/mcp_client_config.md) -- [examples/claude_desktop_mcp_config.json](../examples/claude_desktop_mcp_config.json) -- [examples/cursor_mcp_config.json](../examples/cursor_mcp_config.json) -- [docs/use-cases/README.md](use-cases/README.md) +- Claude Code: [examples/claude_code_mcp.md](../examples/claude_code_mcp.md) +- Codex: [examples/codex_mcp.md](../examples/codex_mcp.md) +- OpenCode: [examples/opencode_mcp_config.json](../examples/opencode_mcp_config.json) +- Generic MCP config: [examples/mcp_client_config.md](../examples/mcp_client_config.md) +- Claude Desktop fallback: [examples/claude_desktop_mcp_config.json](../examples/claude_desktop_mcp_config.json) +- Cursor fallback: [examples/cursor_mcp_config.json](../examples/cursor_mcp_config.json) +- Use-case recipes: [docs/use-cases/README.md](use-cases/README.md) ## Direct Python SDK diff --git a/docs/roadmap/llm-chat-ergonomics.md b/docs/roadmap/llm-chat-ergonomics.md index c028071..1c83344 100644 --- a/docs/roadmap/llm-chat-ergonomics.md +++ b/docs/roadmap/llm-chat-ergonomics.md @@ -6,7 +6,7 @@ goal: make the core agent-workspace use cases feel trivial from a chat-driven LLM interface. -Current baseline is `3.10.0`: +Current baseline is `3.11.0`: - the stable workspace contract exists across CLI, SDK, and MCP - one-shot `pyro run` still exists as the narrow entrypoint @@ -63,7 +63,7 @@ The remaining UX friction for a technically strong new user is now narrower: 7. [`3.8.0` Chat-Host Onramp And Recommended Defaults](llm-chat-ergonomics/3.8.0-chat-host-onramp-and-recommended-defaults.md) - Done 8. [`3.9.0` Content-Only Reads And Human Output Polish](llm-chat-ergonomics/3.9.0-content-only-reads-and-human-output-polish.md) - Done 9. [`3.10.0` Use-Case Smoke Trust And Recipe Fidelity](llm-chat-ergonomics/3.10.0-use-case-smoke-trust-and-recipe-fidelity.md) - Done -10. [`3.11.0` Host-Specific MCP Onramps](llm-chat-ergonomics/3.11.0-host-specific-mcp-onramps.md) +10. [`3.11.0` Host-Specific MCP Onramps](llm-chat-ergonomics/3.11.0-host-specific-mcp-onramps.md) - Done 11. [`4.0.0` Workspace-Core Default Profile](llm-chat-ergonomics/4.0.0-workspace-core-default-profile.md) Completed so far: @@ -90,12 +90,12 @@ Completed so far: transcript separation for files that do not end with a trailing newline. - `3.10.0` aligned the five guest-backed use-case smokes with their recipe docs and promoted `make smoke-use-cases` as the trustworthy verification path for the advertised workspace flows. +- `3.11.0` added exact host-specific MCP onramps for Claude Code, Codex, and OpenCode so new + chat-host users can copy one known-good setup example instead of translating the generic MCP + config manually. Planned next: -- `3.11.0` adds exact host-specific onramps for Claude, Codex, and OpenCode so - a new chat-host user can copy one known-good config or command instead of - translating the generic MCP example by hand. - `4.0.0` flips the default MCP profile from `workspace-full` to `workspace-core` so the no-flag server entrypoint finally matches the recommended docs path, while keeping explicit opt-in access to the full diff --git a/docs/roadmap/llm-chat-ergonomics/3.11.0-host-specific-mcp-onramps.md b/docs/roadmap/llm-chat-ergonomics/3.11.0-host-specific-mcp-onramps.md index db44805..9edc0fa 100644 --- a/docs/roadmap/llm-chat-ergonomics/3.11.0-host-specific-mcp-onramps.md +++ b/docs/roadmap/llm-chat-ergonomics/3.11.0-host-specific-mcp-onramps.md @@ -1,6 +1,6 @@ # `3.11.0` Host-Specific MCP Onramps -Status: Planned +Status: Done ## Goal diff --git a/examples/claude_code_mcp.md b/examples/claude_code_mcp.md new file mode 100644 index 0000000..6f7a18f --- /dev/null +++ b/examples/claude_code_mcp.md @@ -0,0 +1,20 @@ +# Claude Code MCP Setup + +Recommended profile: `workspace-core`. + +Package without install: + +```bash +claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +claude mcp list +``` + +Already installed: + +```bash +claude mcp add pyro -- pyro mcp serve --profile workspace-core +claude mcp list +``` + +Move to `workspace-full` only when the chat truly needs shells, services, +snapshots, secrets, network policy, or disk tools. diff --git a/examples/codex_mcp.md b/examples/codex_mcp.md new file mode 100644 index 0000000..f9f2861 --- /dev/null +++ b/examples/codex_mcp.md @@ -0,0 +1,20 @@ +# Codex MCP Setup + +Recommended profile: `workspace-core`. + +Package without install: + +```bash +codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core +codex mcp list +``` + +Already installed: + +```bash +codex mcp add pyro -- pyro mcp serve --profile workspace-core +codex mcp list +``` + +Move to `workspace-full` only when the chat truly needs shells, services, +snapshots, secrets, network policy, or disk tools. diff --git a/examples/mcp_client_config.md b/examples/mcp_client_config.md index efd8af3..0fa7645 100644 --- a/examples/mcp_client_config.md +++ b/examples/mcp_client_config.md @@ -2,6 +2,15 @@ Recommended default for most chat hosts: `workspace-core`. +Use the host-specific examples first when they apply: + +- Claude Code: [examples/claude_code_mcp.md](claude_code_mcp.md) +- Codex: [examples/codex_mcp.md](codex_mcp.md) +- OpenCode: [examples/opencode_mcp_config.json](opencode_mcp_config.json) + +Use this generic config only when the host expects a plain `mcpServers` JSON +shape. + `pyro-mcp` is intended to be exposed to LLM clients through the public `pyro` CLI. Generic stdio MCP configuration using `uvx`: @@ -42,7 +51,7 @@ Primary profile for most agents: Use lifecycle tools only when the agent needs persistent VM state across multiple tool calls. -Concrete client-specific examples: +Other generic-client examples: - Claude Desktop: [examples/claude_desktop_mcp_config.json](claude_desktop_mcp_config.json) - Cursor: [examples/cursor_mcp_config.json](cursor_mcp_config.json) diff --git a/examples/opencode_mcp_config.json b/examples/opencode_mcp_config.json new file mode 100644 index 0000000..ce23db7 --- /dev/null +++ b/examples/opencode_mcp_config.json @@ -0,0 +1,9 @@ +{ + "mcp": { + "pyro": { + "type": "local", + "enabled": true, + "command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"] + } + } +} diff --git a/pyproject.toml b/pyproject.toml index bc66549..d6e3ded 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pyro-mcp" -version = "3.10.0" +version = "3.11.0" description = "Stable Firecracker workspaces, one-shot sandboxes, and MCP tools for coding agents." readme = "README.md" license = { file = "LICENSE" } diff --git a/src/pyro_mcp/vm_environments.py b/src/pyro_mcp/vm_environments.py index a89e86e..dc2f67a 100644 --- a/src/pyro_mcp/vm_environments.py +++ b/src/pyro_mcp/vm_environments.py @@ -19,7 +19,7 @@ from typing import Any from pyro_mcp.runtime import DEFAULT_PLATFORM, RuntimePaths DEFAULT_ENVIRONMENT_VERSION = "1.0.0" -DEFAULT_CATALOG_VERSION = "3.10.0" +DEFAULT_CATALOG_VERSION = "3.11.0" OCI_MANIFEST_ACCEPT = ", ".join( ( "application/vnd.oci.image.index.v1+json", diff --git a/tests/test_cli.py b/tests/test_cli.py index 17d84b9..52807f2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2807,21 +2807,73 @@ def test_cli_workspace_shell_open_prints_id_only( def test_chat_host_docs_and_examples_recommend_workspace_core() -> None: readme = Path("README.md").read_text(encoding="utf-8") install = Path("docs/install.md").read_text(encoding="utf-8") + first_run = Path("docs/first-run.md").read_text(encoding="utf-8") integrations = Path("docs/integrations.md").read_text(encoding="utf-8") mcp_config = Path("examples/mcp_client_config.md").read_text(encoding="utf-8") + claude_code = Path("examples/claude_code_mcp.md").read_text(encoding="utf-8") + codex = Path("examples/codex_mcp.md").read_text(encoding="utf-8") + opencode = json.loads(Path("examples/opencode_mcp_config.json").read_text(encoding="utf-8")) + claude_cmd = ( + "claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core" + ) + codex_cmd = ( + "codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core" + ) assert "## Chat Host Quickstart" in readme assert "pyro mcp serve --profile workspace-core" in readme + assert claude_cmd in readme + assert codex_cmd in readme + assert "examples/opencode_mcp_config.json" in readme assert "recommended first profile for normal persistent chat editing" in readme assert "## Chat Host Quickstart" in install assert "pyro mcp serve --profile workspace-core" in install + assert claude_cmd in install + assert codex_cmd in install assert "advanced 3.x compatibility surface" in install + assert claude_cmd in first_run + assert codex_cmd in first_run + assert "Start most chat hosts with `workspace-core`." in integrations + assert "examples/claude_code_mcp.md" in integrations + assert "examples/codex_mcp.md" in integrations + assert "examples/opencode_mcp_config.json" in integrations assert '`Pyro.create_server(profile="workspace-core")` for most chat hosts' in integrations assert "Recommended default for most chat hosts: `workspace-core`." in mcp_config + assert "Use the host-specific examples first when they apply:" in mcp_config + assert "claude_code_mcp.md" in mcp_config + assert "codex_mcp.md" in mcp_config + assert "opencode_mcp_config.json" in mcp_config + + assert claude_cmd in claude_code + assert "claude mcp list" in claude_code + assert "workspace-full" in claude_code + + assert codex_cmd in codex + assert "codex mcp list" in codex + assert "workspace-full" in codex + + assert opencode == { + "mcp": { + "pyro": { + "type": "local", + "enabled": True, + "command": [ + "uvx", + "--from", + "pyro-mcp", + "pyro", + "mcp", + "serve", + "--profile", + "workspace-core", + ], + } + } + } def test_content_only_read_docs_are_aligned() -> None: diff --git a/uv.lock b/uv.lock index 6bdffd0..f993b93 100644 --- a/uv.lock +++ b/uv.lock @@ -715,7 +715,7 @@ crypto = [ [[package]] name = "pyro-mcp" -version = "3.10.0" +version = "3.11.0" source = { editable = "." } dependencies = [ { name = "mcp" },