Compare commits
2 commits
68d8e875e0
...
386b9793ee
| Author | SHA1 | Date | |
|---|---|---|---|
| 386b9793ee | |||
| c00c699a9f |
27 changed files with 205 additions and 150 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
All notable user-visible changes to `pyro-mcp` are documented here.
|
||||
|
||||
## 4.0.0
|
||||
|
||||
- Flipped the default MCP/server profile from `workspace-full` to
|
||||
`workspace-core`, so bare `pyro mcp serve`, `create_server()`, and
|
||||
`Pyro.create_server()` now match the recommended narrow chat-host path.
|
||||
- Rewrote MCP-facing docs and shipped host-specific examples so the normal
|
||||
setup path no longer needs an explicit `--profile workspace-core` just to
|
||||
get the default behavior.
|
||||
- Added migration guidance for hosts that relied on the previous implicit full
|
||||
surface: they now need `--profile workspace-full` or
|
||||
`create_server(profile=\"workspace-full\")`.
|
||||
## 3.11.0
|
||||
|
||||
- Added first-class host-specific MCP onramps for Claude Code, Codex, and
|
||||
|
|
|
|||
32
README.md
32
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.11.0: [CHANGELOG.md#3110](CHANGELOG.md#3110)
|
||||
- What's new in 4.0.0: [CHANGELOG.md#400](CHANGELOG.md#400)
|
||||
- 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.11.0
|
||||
Catalog version: 4.0.0
|
||||
...
|
||||
[pull] phase=install environment=debian:12
|
||||
[pull] phase=ready environment=debian:12
|
||||
|
|
@ -126,7 +126,7 @@ That stable workspace path gives you:
|
|||
After the quickstart works:
|
||||
|
||||
- prove the full one-shot lifecycle with `uvx --from pyro-mcp pyro demo`
|
||||
- start most chat hosts with `uvx --from pyro-mcp pyro mcp serve --profile workspace-core`
|
||||
- start most chat hosts with `uvx --from pyro-mcp pyro mcp serve`
|
||||
- create a persistent workspace with `uvx --from pyro-mcp pyro workspace create debian:12 --seed-path ./repo`
|
||||
- add a human-friendly workspace name with `uvx --from pyro-mcp pyro workspace create debian:12 --name repro-fix --label issue=123`
|
||||
- rediscover or retag workspaces with `uvx --from pyro-mcp pyro workspace list` and `uvx --from pyro-mcp pyro workspace update WORKSPACE_ID --label owner=codex`
|
||||
|
|
@ -148,12 +148,12 @@ After the quickstart works:
|
|||
|
||||
## Chat Host Quickstart
|
||||
|
||||
For most MCP chat hosts, start with `workspace-core`. It exposes the practical
|
||||
For most MCP chat hosts, bare `pyro mcp serve` now starts `workspace-core`. It exposes the practical
|
||||
persistent editing loop without shells, services, snapshots, secrets, network
|
||||
policy, or disk tools.
|
||||
|
||||
```bash
|
||||
uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
Copy-paste host-specific starts:
|
||||
|
|
@ -166,13 +166,13 @@ Copy-paste host-specific starts:
|
|||
Claude Code:
|
||||
|
||||
```bash
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
Codex:
|
||||
|
||||
```bash
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
OpenCode `opencode.json` snippet:
|
||||
|
|
@ -183,20 +183,22 @@ OpenCode `opencode.json` snippet:
|
|||
"pyro": {
|
||||
"type": "local",
|
||||
"enabled": true,
|
||||
"command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"]
|
||||
"command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
command with `pyro` in the same host-specific command or config shape. Use
|
||||
`--profile workspace-full` only when the host truly needs the full advanced
|
||||
workspace surface.
|
||||
|
||||
Profile progression:
|
||||
|
||||
- `workspace-core`: recommended first profile for normal persistent chat editing
|
||||
- `workspace-core`: default and recommended first profile for normal persistent chat editing
|
||||
- `vm-run`: smallest one-shot-only surface
|
||||
- `workspace-full`: advanced 3.x compatibility surface when the chat truly needs shells, services, snapshots, secrets, network policy, or disk tools
|
||||
- `workspace-full`: explicit advanced opt-in when the chat truly needs shells, services, snapshots, secrets, network policy, or disk tools
|
||||
|
||||
## Supported Hosts
|
||||
|
||||
|
|
@ -249,7 +251,7 @@ uvx --from pyro-mcp pyro env list
|
|||
Expected output:
|
||||
|
||||
```bash
|
||||
Catalog version: 3.11.0
|
||||
Catalog version: 4.0.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.
|
||||
|
|
@ -366,7 +368,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.11.0`; if it fails
|
||||
later host-side changes into a started workspace. Sync is non-atomic in `4.0.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
|
||||
|
|
@ -395,7 +397,7 @@ The public user-facing interface is `pyro` and `Pyro`. After the CLI validation
|
|||
|
||||
- `pyro` for direct CLI usage, including one-shot `run` and persistent `workspace` workflows
|
||||
- `from pyro_mcp import Pyro` for Python orchestration
|
||||
- `pyro mcp serve --profile workspace-core` for MCP clients
|
||||
- `pyro mcp serve` for MCP clients
|
||||
|
||||
Command forms:
|
||||
|
||||
|
|
@ -462,7 +464,7 @@ Run the MCP server after the CLI path above works. Start most chat hosts with
|
|||
`workspace-core`:
|
||||
|
||||
```bash
|
||||
pyro mcp serve --profile workspace-core
|
||||
pyro mcp serve
|
||||
```
|
||||
|
||||
Profile progression for chat hosts:
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 3 MiB |
|
|
@ -5,10 +5,10 @@ Require python3
|
|||
|
||||
Set Shell "zsh"
|
||||
Set FontSize 18
|
||||
Set Width 1400
|
||||
Set Height 860
|
||||
Set Width 1480
|
||||
Set Height 900
|
||||
Set Theme "Dracula"
|
||||
Set TypingSpeed 35ms
|
||||
Set TypingSpeed 34ms
|
||||
Set Padding 24
|
||||
Set WindowBar Colorful
|
||||
|
||||
|
|
@ -25,62 +25,68 @@ Type "alias pyro='uv run pyro'"
|
|||
Enter
|
||||
Type "SEED_DIR=$(mktemp -d)"
|
||||
Enter
|
||||
Type "SYNC_DIR=$(mktemp -d)"
|
||||
Enter
|
||||
Type "EXPORT_DIR=$(mktemp -d)"
|
||||
Enter
|
||||
Type 'printf "%s\n" "hello from seed" > "$SEED_DIR/note.txt"'
|
||||
Enter
|
||||
Type 'printf "%s\n" "hello from sync" > "$SYNC_DIR/note.txt"'
|
||||
Type 'printf "%s\n" "--- a/note.txt" "+++ b/note.txt" "@@ -1 +1 @@" "-hello from seed" "+hello from patch" > "$SEED_DIR/fix.patch"'
|
||||
Enter
|
||||
Type 'printf "%s\n" "temporary drift" > "$SEED_DIR/drift.txt"'
|
||||
Enter
|
||||
Type "pyro env pull debian:12 >/dev/null"
|
||||
Enter
|
||||
Show
|
||||
|
||||
Type "# Create a stable workspace from host content and capture its id"
|
||||
Type "# Create a named workspace from host content"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace create debian:12 --seed-path "$SEED_DIR" --json | tee /tmp/pyro-workspace.json'
|
||||
Type 'WORKSPACE_ID="$(pyro workspace create debian:12 --seed-path "$SEED_DIR" --name repro-fix --label issue=123 --id-only)"'
|
||||
Enter
|
||||
Sleep 2200ms
|
||||
|
||||
Hide
|
||||
Type 'export WORKSPACE_ID=$(python3 -c "import json; print(json.load(open(\"/tmp/pyro-workspace.json\", encoding=\"utf-8\"))[\"workspace_id\"])")'
|
||||
Sleep 500ms
|
||||
Type 'echo "$WORKSPACE_ID"'
|
||||
Enter
|
||||
Show
|
||||
Sleep 1600ms
|
||||
|
||||
Type "# Push a later host-side change into the same workspace"
|
||||
Type "# Inspect the seeded file, then patch it without shell quoting"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace sync push "$WORKSPACE_ID" "$SYNC_DIR"'
|
||||
Type 'pyro workspace file read "$WORKSPACE_ID" note.txt --content-only'
|
||||
Enter
|
||||
Sleep 1400ms
|
||||
Type 'pyro workspace patch apply "$WORKSPACE_ID" --patch-file "$SEED_DIR/fix.patch"'
|
||||
Enter
|
||||
Sleep 1800ms
|
||||
Type 'pyro workspace exec "$WORKSPACE_ID" -- cat note.txt'
|
||||
Enter
|
||||
Sleep 1800ms
|
||||
|
||||
Type "# Run inside the live workspace"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace exec "$WORKSPACE_ID" -- cat note.txt'
|
||||
Enter
|
||||
Sleep 2000ms
|
||||
|
||||
Type "# Capture a checkpoint, then start one long-running service"
|
||||
Type "# Capture a checkpoint, then drift away from it"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace snapshot create "$WORKSPACE_ID" checkpoint'
|
||||
Enter
|
||||
Sleep 1600ms
|
||||
Type 'pyro workspace file write "$WORKSPACE_ID" note.txt --text-file "$SEED_DIR/drift.txt"'
|
||||
Enter
|
||||
Sleep 1800ms
|
||||
Type 'pyro workspace exec "$WORKSPACE_ID" -- cat note.txt'
|
||||
Enter
|
||||
Sleep 1800ms
|
||||
|
||||
Type "# Start one service, then reset the whole sandbox to the checkpoint"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace service start "$WORKSPACE_ID" web --ready-file .web-ready -- sh -lc "touch .web-ready && while true; do sleep 60; done"'
|
||||
Enter
|
||||
Sleep 2200ms
|
||||
|
||||
Type "# Reset the full sandbox back to that checkpoint"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace reset "$WORKSPACE_ID" --snapshot checkpoint'
|
||||
Enter
|
||||
Sleep 2200ms
|
||||
Type 'pyro workspace exec "$WORKSPACE_ID" -- cat note.txt'
|
||||
Enter
|
||||
Sleep 1800ms
|
||||
|
||||
Type "# Export one file back to the host and inspect it locally"
|
||||
Type "# Export the recovered file back to the host"
|
||||
Enter
|
||||
Sleep 700ms
|
||||
Type 'pyro workspace export "$WORKSPACE_ID" note.txt --output "$EXPORT_DIR/note.txt"'
|
||||
|
|
@ -88,7 +94,7 @@ Enter
|
|||
Sleep 1800ms
|
||||
Type 'cat "$EXPORT_DIR/note.txt"'
|
||||
Enter
|
||||
Sleep 1800ms
|
||||
Sleep 1600ms
|
||||
|
||||
Type "# Remove the workspace when the loop is done"
|
||||
Enter
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Networking: tun=yes ip_forward=yes
|
|||
|
||||
```bash
|
||||
$ uvx --from pyro-mcp pyro env list
|
||||
Catalog version: 3.11.0
|
||||
Catalog version: 4.0.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.
|
||||
|
|
@ -115,12 +115,13 @@ $ uvx --from pyro-mcp pyro workspace shell open WORKSPACE_ID --secret-env API_TO
|
|||
$ uvx --from pyro-mcp pyro workspace service start WORKSPACE_ID app --secret-env API_TOKEN --ready-file .ready -- sh -lc 'touch .ready && while true; do sleep 60; done'
|
||||
$ 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
|
||||
$ uvx --from pyro-mcp pyro mcp serve
|
||||
$ claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
$ codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
For most chat hosts, `workspace-core` is the recommended first MCP profile.
|
||||
For most chat hosts, bare `pyro mcp serve` now starts `workspace-core`, the
|
||||
recommended first MCP profile.
|
||||
Move to `workspace-full` only when the host truly needs shells, services,
|
||||
snapshots, secrets, network policy, or disk tools.
|
||||
|
||||
|
|
@ -268,7 +269,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.11.0`; if it fails partway through, prefer `pyro workspace reset`
|
||||
workspace. Sync is non-atomic in `4.0.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
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ uvx --from pyro-mcp pyro env list
|
|||
Expected output:
|
||||
|
||||
```bash
|
||||
Catalog version: 3.11.0
|
||||
Catalog version: 4.0.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.
|
||||
|
|
@ -231,16 +231,17 @@ After the CLI path works, you can move on to:
|
|||
- interactive shells: `pyro workspace shell open WORKSPACE_ID --id-only`
|
||||
- long-running services: `pyro workspace service start WORKSPACE_ID app --ready-file .ready -- sh -lc 'touch .ready && while true; do sleep 60; done'`
|
||||
- localhost-published ports: `pyro workspace create debian:12 --network-policy egress+published-ports` and `pyro workspace service start WORKSPACE_ID app --ready-http http://127.0.0.1:8080/ --publish 18080:8080 -- ./start-app`
|
||||
- MCP: `pyro mcp serve --profile workspace-core`
|
||||
- MCP: `pyro mcp serve`
|
||||
- Python SDK: `from pyro_mcp import Pyro`
|
||||
- Demos: `pyro demo` or `pyro demo --network`
|
||||
|
||||
## Chat Host Quickstart
|
||||
|
||||
For most chat-host integrations, start with `workspace-core`:
|
||||
For most chat-host integrations, bare `pyro mcp serve` now starts
|
||||
`workspace-core`:
|
||||
|
||||
```bash
|
||||
uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
Copy-paste host-specific starts:
|
||||
|
|
@ -253,25 +254,27 @@ Copy-paste host-specific starts:
|
|||
Claude Code:
|
||||
|
||||
```bash
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
Codex:
|
||||
|
||||
```bash
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
```
|
||||
|
||||
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.
|
||||
command with `pyro` in the same host-specific command or config shape. Use
|
||||
`--profile workspace-full` only when the host truly needs the full advanced
|
||||
workspace surface.
|
||||
|
||||
Use profile progression like this:
|
||||
|
||||
- `workspace-core`: recommended first profile for normal persistent chat editing
|
||||
- `workspace-core`: default and recommended first profile for normal persistent chat editing
|
||||
- `vm-run`: one-shot-only integrations
|
||||
- `workspace-full`: advanced 3.x compatibility surface when the host truly needs shells, services, snapshots, secrets, network policy, or disk tools
|
||||
- `workspace-full`: explicit advanced opt-in when the host truly needs shells, services, snapshots, secrets, network policy, or disk tools
|
||||
|
||||
## Stable Workspace
|
||||
|
||||
|
|
@ -320,7 +323,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.11.0`; if it fails partway through, prefer `pyro workspace reset` to recover
|
||||
is non-atomic in `4.0.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
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ CLI path in [install.md](install.md) or [first-run.md](first-run.md).
|
|||
|
||||
## Recommended Default
|
||||
|
||||
Start most chat hosts with `workspace-core`. Use `vm_run` only for one-shot
|
||||
Bare `pyro mcp serve` now starts `workspace-core`. Use `vm_run` only for one-shot
|
||||
integrations, and promote the chat surface to `workspace-full` only when it
|
||||
truly needs shells, services, snapshots, secrets, network policy, or disk
|
||||
tools.
|
||||
|
|
@ -21,7 +21,7 @@ That keeps the model-facing contract small:
|
|||
|
||||
Profile progression:
|
||||
|
||||
- `workspace-core`: recommended first profile for persistent chat editing
|
||||
- `workspace-core`: default and recommended first profile for persistent chat editing
|
||||
- `vm-run`: one-shot only
|
||||
- `workspace-full`: the full stable workspace surface, including shells, services, snapshots, secrets, network policy, and disk tools
|
||||
|
||||
|
|
@ -55,12 +55,12 @@ Best when:
|
|||
|
||||
Recommended entrypoint:
|
||||
|
||||
- `pyro mcp serve --profile workspace-core`
|
||||
- `pyro mcp serve`
|
||||
|
||||
Profile progression:
|
||||
|
||||
- `pyro mcp serve --profile vm-run` for the smallest one-shot surface
|
||||
- `pyro mcp serve --profile workspace-core` for the normal persistent chat loop
|
||||
- `pyro mcp serve` for the normal persistent chat loop
|
||||
- `pyro mcp serve --profile workspace-full` only when the model truly needs advanced workspace tools
|
||||
|
||||
Host-specific onramps:
|
||||
|
|
@ -84,7 +84,7 @@ Best when:
|
|||
Recommended default:
|
||||
|
||||
- `Pyro.run_in_vm(...)`
|
||||
- `Pyro.create_server(profile="workspace-core")` for most chat hosts
|
||||
- `Pyro.create_server()` for most chat hosts now that `workspace-core` is the default profile
|
||||
- `Pyro.create_workspace(name=..., labels=...)` + `Pyro.list_workspaces()` + `Pyro.update_workspace(...)` when repeated workspaces need human-friendly discovery metadata
|
||||
- `Pyro.create_workspace(seed_path=...)` + `Pyro.push_workspace_sync(...)` + `Pyro.exec_workspace(...)` when repeated workspace commands are required
|
||||
- `Pyro.list_workspace_files(...)` / `Pyro.read_workspace_file(...)` / `Pyro.write_workspace_file(...)` / `Pyro.apply_workspace_patch(...)` when the agent needs model-native file inspection and text edits inside one live workspace
|
||||
|
|
|
|||
|
|
@ -129,8 +129,8 @@ Primary facade:
|
|||
|
||||
Supported public entrypoints:
|
||||
|
||||
- `create_server(profile="workspace-full")`
|
||||
- `Pyro.create_server(profile="workspace-full")`
|
||||
- `create_server()`
|
||||
- `Pyro.create_server()`
|
||||
- `Pyro.list_environments()`
|
||||
- `Pyro.pull_environment(environment)`
|
||||
- `Pyro.inspect_environment(environment)`
|
||||
|
|
@ -180,7 +180,7 @@ Supported public entrypoints:
|
|||
|
||||
Stable public method names:
|
||||
|
||||
- `create_server(profile="workspace-full")`
|
||||
- `create_server()`
|
||||
- `list_environments()`
|
||||
- `pull_environment(environment)`
|
||||
- `inspect_environment(environment)`
|
||||
|
|
@ -277,9 +277,9 @@ Stable MCP profiles:
|
|||
|
||||
Behavioral defaults:
|
||||
|
||||
- `pyro mcp serve` and `create_server()` default to `workspace-full` for 3.x compatibility.
|
||||
- `workspace-core` is the recommended first profile for most new chat-host integrations.
|
||||
- `create_server(profile="workspace-core")` and `Pyro.create_server(profile="workspace-core")` are the recommended entrypoints for most new chat-host integrations.
|
||||
- `pyro mcp serve`, `create_server()`, and `Pyro.create_server()` default to `workspace-core`.
|
||||
- `workspace-core` is the default and recommended first profile for most new chat-host integrations.
|
||||
- `create_server(profile="workspace-full")` and `Pyro.create_server(profile="workspace-full")` opt into the full advanced workspace surface explicitly.
|
||||
- `workspace-core` narrows `workspace_create` by omitting `network_policy` and `secrets`.
|
||||
- `workspace-core` narrows `workspace_exec` by omitting `secret_env`.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ goal:
|
|||
make the core agent-workspace use cases feel trivial from a chat-driven LLM
|
||||
interface.
|
||||
|
||||
Current baseline is `3.11.0`:
|
||||
Current baseline is `4.0.0`:
|
||||
|
||||
- the stable workspace contract exists across CLI, SDK, and MCP
|
||||
- one-shot `pyro run` still exists as the narrow entrypoint
|
||||
|
|
@ -35,10 +35,7 @@ More concretely, the model should not need to:
|
|||
|
||||
The remaining UX friction for a technically strong new user is now narrower:
|
||||
|
||||
- the generic MCP guidance is strong, but Codex and OpenCode still ask the user
|
||||
to translate the generic config into host-specific setup steps
|
||||
- `workspace-core` is clearly the recommended profile, but `pyro mcp serve` and
|
||||
`create_server()` still default to `workspace-full` for `3.x` compatibility
|
||||
- no major chat-host ergonomics gaps remain in the current roadmap
|
||||
|
||||
## Locked Decisions
|
||||
|
||||
|
|
@ -64,7 +61,7 @@ The remaining UX friction for a technically strong new user is now narrower:
|
|||
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) - Done
|
||||
11. [`4.0.0` Workspace-Core Default Profile](llm-chat-ergonomics/4.0.0-workspace-core-default-profile.md)
|
||||
11. [`4.0.0` Workspace-Core Default Profile](llm-chat-ergonomics/4.0.0-workspace-core-default-profile.md) - Done
|
||||
|
||||
Completed so far:
|
||||
|
||||
|
|
@ -93,13 +90,12 @@ Completed so far:
|
|||
- `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.
|
||||
- `4.0.0` flipped the default MCP/server profile to `workspace-core`, so the bare entrypoint now
|
||||
matches the recommended narrow chat-host profile across CLI, SDK, and package-level factories.
|
||||
|
||||
Planned next:
|
||||
|
||||
- `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
|
||||
advanced surface.
|
||||
- no further chat-ergonomics milestones are currently planned in this roadmap.
|
||||
|
||||
## Expected Outcome
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# `4.0.0` Workspace-Core Default Profile
|
||||
|
||||
Status: Planned
|
||||
Status: Done
|
||||
|
||||
## Goal
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,20 @@ Recommended profile: `workspace-core`.
|
|||
Package without install:
|
||||
|
||||
```bash
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
claude mcp list
|
||||
```
|
||||
|
||||
Already installed:
|
||||
|
||||
```bash
|
||||
claude mcp add pyro -- pyro mcp serve --profile workspace-core
|
||||
claude mcp add pyro -- pyro mcp serve
|
||||
claude mcp list
|
||||
```
|
||||
|
||||
Move to `workspace-full` only when the chat truly needs shells, services,
|
||||
snapshots, secrets, network policy, or disk tools.
|
||||
snapshots, secrets, network policy, or disk tools:
|
||||
|
||||
```bash
|
||||
claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-full
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"mcpServers": {
|
||||
"pyro": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"]
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,16 +5,20 @@ Recommended profile: `workspace-core`.
|
|||
Package without install:
|
||||
|
||||
```bash
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-core
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve
|
||||
codex mcp list
|
||||
```
|
||||
|
||||
Already installed:
|
||||
|
||||
```bash
|
||||
codex mcp add pyro -- pyro mcp serve --profile workspace-core
|
||||
codex mcp add pyro -- pyro mcp serve
|
||||
codex mcp list
|
||||
```
|
||||
|
||||
Move to `workspace-full` only when the chat truly needs shells, services,
|
||||
snapshots, secrets, network policy, or disk tools.
|
||||
snapshots, secrets, network policy, or disk tools:
|
||||
|
||||
```bash
|
||||
codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve --profile workspace-full
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"mcpServers": {
|
||||
"pyro": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"]
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# MCP Client Config Example
|
||||
|
||||
Recommended default for most chat hosts: `workspace-core`.
|
||||
Default for most chat hosts in `4.x`: `workspace-core`.
|
||||
|
||||
Use the host-specific examples first when they apply:
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ Generic stdio MCP configuration using `uvx`:
|
|||
"mcpServers": {
|
||||
"pyro": {
|
||||
"command": "uvx",
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"]
|
||||
"args": ["--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ If `pyro-mcp` is already installed locally, the same server can be configured wi
|
|||
"mcpServers": {
|
||||
"pyro": {
|
||||
"command": "pyro",
|
||||
"args": ["mcp", "serve", "--profile", "workspace-core"]
|
||||
"args": ["mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,9 +41,9 @@ If `pyro-mcp` is already installed locally, the same server can be configured wi
|
|||
|
||||
Profile progression:
|
||||
|
||||
- `workspace-core`: the recommended first persistent chat profile
|
||||
- `workspace-core`: the default and recommended first persistent chat profile
|
||||
- `vm-run`: expose only `vm_run`
|
||||
- `workspace-full`: advanced 3.x compatibility surface for shells, services, snapshots, secrets, network policy, and disk tools
|
||||
- `workspace-full`: explicit advanced opt-in for shells, services, snapshots, secrets, network policy, and disk tools
|
||||
|
||||
Primary profile for most agents:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ Requirements:
|
|||
- `pip install openai` or `uv add openai`
|
||||
- `OPENAI_API_KEY`
|
||||
|
||||
This is the recommended persistent-chat example. It mirrors the
|
||||
`workspace-core` MCP profile by deriving tool schemas from
|
||||
`Pyro.create_server(profile="workspace-core")` and dispatching tool calls back
|
||||
through that same profiled server.
|
||||
This is the recommended persistent-chat example. In 4.x the default MCP server
|
||||
profile is already `workspace-core`, so it derives tool schemas from
|
||||
`Pyro.create_server()` and dispatches tool calls back through that same
|
||||
default-profile server.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
|
@ -45,7 +45,7 @@ async def run_openai_workspace_core_example(*, prompt: str, model: str = DEFAULT
|
|||
from openai import OpenAI # type: ignore[import-not-found]
|
||||
|
||||
pyro = Pyro()
|
||||
server = pyro.create_server(profile="workspace-core")
|
||||
server = pyro.create_server()
|
||||
tools = [_tool_to_openai(tool) for tool in await server.list_tools()]
|
||||
client = OpenAI()
|
||||
input_items: list[dict[str, Any]] = [{"role": "user", "content": prompt}]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"pyro": {
|
||||
"type": "local",
|
||||
"enabled": true,
|
||||
"command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve", "--profile", "workspace-core"]
|
||||
"command": ["uvx", "--from", "pyro-mcp", "pyro", "mcp", "serve"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "pyro-mcp"
|
||||
version = "3.11.0"
|
||||
version = "4.0.0"
|
||||
description = "Stable Firecracker workspaces, one-shot sandboxes, and MCP tools for coding agents."
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
|
|
|
|||
|
|
@ -462,11 +462,12 @@ class Pyro:
|
|||
allow_host_compat=allow_host_compat,
|
||||
)
|
||||
|
||||
def create_server(self, *, profile: McpToolProfile = "workspace-full") -> FastMCP:
|
||||
def create_server(self, *, profile: McpToolProfile = "workspace-core") -> FastMCP:
|
||||
"""Create an MCP server for one of the stable public tool profiles.
|
||||
|
||||
`workspace-full` remains the default for 3.x compatibility. New chat
|
||||
hosts should usually start with `profile="workspace-core"`.
|
||||
`workspace-core` is the default stable chat-host profile in 4.x. Use
|
||||
`profile="workspace-full"` only when the host truly needs the full
|
||||
advanced workspace surface.
|
||||
"""
|
||||
normalized_profile = _validate_mcp_profile(profile)
|
||||
enabled_tools = set(_PROFILE_TOOLS[normalized_profile])
|
||||
|
|
|
|||
|
|
@ -760,13 +760,13 @@ def _build_parser() -> argparse.ArgumentParser:
|
|||
help="Run the MCP server.",
|
||||
description=(
|
||||
"Run the MCP server after you have already validated the host and "
|
||||
"guest execution with `pyro doctor` and `pyro run`. Start most "
|
||||
"chat hosts with `workspace-core`."
|
||||
"guest execution with `pyro doctor` and `pyro run`. Bare `pyro "
|
||||
"mcp serve` now starts the recommended `workspace-core` profile."
|
||||
),
|
||||
epilog=dedent(
|
||||
"""
|
||||
Examples:
|
||||
pyro mcp serve --profile workspace-core
|
||||
pyro mcp serve
|
||||
pyro mcp serve --profile vm-run
|
||||
pyro mcp serve --profile workspace-full
|
||||
"""
|
||||
|
|
@ -778,22 +778,23 @@ def _build_parser() -> argparse.ArgumentParser:
|
|||
"serve",
|
||||
help="Run the MCP server over stdio.",
|
||||
description=(
|
||||
"Expose pyro tools over stdio for an MCP client. "
|
||||
"`workspace-core` is the recommended first profile for most chat hosts."
|
||||
"Expose pyro tools over stdio for an MCP client. Bare `pyro mcp "
|
||||
"serve` now starts `workspace-core`, the recommended first profile "
|
||||
"for most chat hosts."
|
||||
),
|
||||
epilog=dedent(
|
||||
"""
|
||||
Recommended first start:
|
||||
pyro mcp serve --profile workspace-core
|
||||
Default and recommended first start:
|
||||
pyro mcp serve
|
||||
|
||||
Profiles:
|
||||
workspace-core: recommended default for normal persistent chat editing
|
||||
workspace-core: default for normal persistent chat editing
|
||||
vm-run: smallest one-shot-only surface
|
||||
workspace-full: advanced 3.x compatibility surface for shells, services,
|
||||
workspace-full: advanced 4.x opt-in surface for shells, services,
|
||||
snapshots, secrets, network policy, and disk tools
|
||||
|
||||
`workspace-full` remains the default in 3.x for compatibility, but most new
|
||||
chat hosts should start with `workspace-core`.
|
||||
Use --profile workspace-full only when the host truly needs the full
|
||||
advanced workspace surface.
|
||||
"""
|
||||
),
|
||||
formatter_class=_HelpFormatter,
|
||||
|
|
@ -801,11 +802,11 @@ def _build_parser() -> argparse.ArgumentParser:
|
|||
mcp_serve_parser.add_argument(
|
||||
"--profile",
|
||||
choices=PUBLIC_MCP_PROFILES,
|
||||
default="workspace-full",
|
||||
default="workspace-core",
|
||||
help=(
|
||||
"Expose only one model-facing tool profile. `workspace-core` is the "
|
||||
"recommended first profile for most chat hosts; `workspace-full` "
|
||||
"preserves the current full MCP surface for 3.x compatibility."
|
||||
"Expose only one model-facing tool profile. `workspace-core` is "
|
||||
"the default and recommended first profile for most chat hosts; "
|
||||
"`workspace-full` is the explicit advanced opt-in surface."
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,12 +11,13 @@ from pyro_mcp.vm_manager import VmManager
|
|||
def create_server(
|
||||
manager: VmManager | None = None,
|
||||
*,
|
||||
profile: McpToolProfile = "workspace-full",
|
||||
profile: McpToolProfile = "workspace-core",
|
||||
) -> FastMCP:
|
||||
"""Create and return a configured MCP server instance.
|
||||
|
||||
`workspace-full` remains the default for 3.x compatibility. New chat hosts
|
||||
should usually start with `profile="workspace-core"`.
|
||||
`workspace-core` is the default stable chat-host profile in 4.x. Use
|
||||
`profile="workspace-full"` only when the host truly needs the full
|
||||
advanced workspace surface.
|
||||
"""
|
||||
return Pyro(manager=manager).create_server(profile=profile)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.11.0"
|
||||
DEFAULT_CATALOG_VERSION = "4.0.0"
|
||||
OCI_MANIFEST_ACCEPT = ", ".join(
|
||||
(
|
||||
"application/vnd.oci.image.index.v1+json",
|
||||
|
|
@ -48,7 +48,7 @@ class VmEnvironment:
|
|||
oci_repository: str | None = None
|
||||
oci_reference: str | None = None
|
||||
source_digest: str | None = None
|
||||
compatibility: str = ">=3.0.0,<4.0.0"
|
||||
compatibility: str = ">=4.0.0,<5.0.0"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ def test_pyro_run_in_vm_delegates_to_manager(tmp_path: Path) -> None:
|
|||
assert str(result["stdout"]) == "ok\n"
|
||||
|
||||
|
||||
def test_pyro_create_server_registers_full_profile_and_shell_read_schema(tmp_path: Path) -> None:
|
||||
def test_pyro_create_server_defaults_to_workspace_core_profile(tmp_path: Path) -> None:
|
||||
pyro = Pyro(
|
||||
manager=VmManager(
|
||||
backend_name="mock",
|
||||
|
|
@ -52,6 +52,34 @@ def test_pyro_create_server_registers_full_profile_and_shell_read_schema(tmp_pat
|
|||
tool_map = {tool.name: tool.model_dump() for tool in tools}
|
||||
return sorted(tool_map), tool_map
|
||||
|
||||
tool_names, tool_map = asyncio.run(_run())
|
||||
assert tuple(tool_names) == tuple(sorted(PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS))
|
||||
create_properties = tool_map["workspace_create"]["inputSchema"]["properties"]
|
||||
assert "network_policy" not in create_properties
|
||||
assert "secrets" not in create_properties
|
||||
exec_properties = tool_map["workspace_exec"]["inputSchema"]["properties"]
|
||||
assert "secret_env" not in exec_properties
|
||||
assert "shell_open" not in tool_map
|
||||
assert "service_start" not in tool_map
|
||||
assert "snapshot_create" not in tool_map
|
||||
assert "workspace_disk_export" not in tool_map
|
||||
|
||||
|
||||
def test_pyro_create_server_workspace_full_profile_keeps_shell_read_schema(tmp_path: Path) -> None:
|
||||
pyro = Pyro(
|
||||
manager=VmManager(
|
||||
backend_name="mock",
|
||||
base_dir=tmp_path / "vms",
|
||||
network_manager=TapNetworkManager(enabled=False),
|
||||
)
|
||||
)
|
||||
|
||||
async def _run() -> tuple[list[str], dict[str, dict[str, Any]]]:
|
||||
server = pyro.create_server(profile="workspace-full")
|
||||
tools = await server.list_tools()
|
||||
tool_map = {tool.name: tool.model_dump() for tool in tools}
|
||||
return sorted(tool_map), tool_map
|
||||
|
||||
tool_names, tool_map = asyncio.run(_run())
|
||||
assert tuple(tool_names) == tuple(sorted(PUBLIC_MCP_WORKSPACE_FULL_PROFILE_TOOLS))
|
||||
shell_read_properties = tool_map["shell_read"]["inputSchema"]["properties"]
|
||||
|
|
@ -568,7 +596,7 @@ def test_pyro_create_server_workspace_disk_tools_delegate() -> None:
|
|||
return cast(dict[str, Any], structured)
|
||||
|
||||
async def _run() -> tuple[dict[str, Any], ...]:
|
||||
server = pyro.create_server()
|
||||
server = pyro.create_server(profile="workspace-full")
|
||||
stopped = _extract_structured(
|
||||
await server.call_tool("workspace_stop", {"workspace_id": "workspace-123"})
|
||||
)
|
||||
|
|
@ -1078,7 +1106,7 @@ def test_pyro_create_server_workspace_status_shell_and_service_delegate() -> Non
|
|||
return cast(dict[str, Any], structured)
|
||||
|
||||
async def _run() -> tuple[dict[str, Any], ...]:
|
||||
server = pyro.create_server()
|
||||
server = pyro.create_server(profile="workspace-full")
|
||||
status = _extract_structured(
|
||||
await server.call_tool("workspace_status", {"workspace_id": "workspace-123"})
|
||||
)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ def test_cli_subcommand_help_includes_examples_and_guidance() -> None:
|
|||
assert "workspace-full" in mcp_help
|
||||
assert "vm-run" in mcp_help
|
||||
assert "recommended first profile for most chat hosts" in mcp_help
|
||||
assert "default in 3.x for compatibility" in mcp_help
|
||||
assert "workspace-core: default for normal persistent chat editing" in mcp_help
|
||||
assert "workspace-full: advanced 4.x opt-in surface" in mcp_help
|
||||
|
||||
workspace_help = _subparser_choice(parser, "workspace").format_help()
|
||||
assert "stable workspace contract" in workspace_help
|
||||
|
|
@ -2813,36 +2814,35 @@ def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
|
|||
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"
|
||||
)
|
||||
claude_cmd = "claude mcp add pyro -- uvx --from pyro-mcp pyro mcp serve"
|
||||
codex_cmd = "codex mcp add pyro -- uvx --from pyro-mcp pyro mcp serve"
|
||||
|
||||
assert "## Chat Host Quickstart" in readme
|
||||
assert "pyro mcp serve --profile workspace-core" in readme
|
||||
assert "uvx --from pyro-mcp pyro mcp serve" 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 "uvx --from pyro-mcp pyro mcp serve" in install
|
||||
assert claude_cmd in install
|
||||
assert codex_cmd in install
|
||||
assert "advanced 3.x compatibility surface" in install
|
||||
assert "workspace-full" 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 "Bare `pyro mcp serve` now starts `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 (
|
||||
'`Pyro.create_server()` for most chat hosts now that `workspace-core` '
|
||||
"is the default profile" in integrations
|
||||
)
|
||||
|
||||
assert "Recommended default for most chat hosts: `workspace-core`." in mcp_config
|
||||
assert "Default for most chat hosts in `4.x`: `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
|
||||
|
|
@ -2868,8 +2868,6 @@ def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
|
|||
"pyro",
|
||||
"mcp",
|
||||
"serve",
|
||||
"--profile",
|
||||
"workspace-core",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ from pyro_mcp.contract import (
|
|||
PUBLIC_CLI_WORKSPACE_SYNC_SUBCOMMANDS,
|
||||
PUBLIC_CLI_WORKSPACE_UPDATE_FLAGS,
|
||||
PUBLIC_MCP_PROFILES,
|
||||
PUBLIC_MCP_TOOLS,
|
||||
PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS,
|
||||
PUBLIC_SDK_METHODS,
|
||||
)
|
||||
from pyro_mcp.vm_manager import VmManager
|
||||
|
|
@ -335,7 +335,7 @@ def test_public_mcp_tools_match_contract(tmp_path: Path) -> None:
|
|||
return tuple(sorted(tool.name for tool in tools))
|
||||
|
||||
tool_names = asyncio.run(_run())
|
||||
assert tool_names == tuple(sorted(PUBLIC_MCP_TOOLS))
|
||||
assert tool_names == tuple(sorted(PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS))
|
||||
|
||||
|
||||
def test_pyproject_exposes_single_public_cli_script() -> None:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import pyro_mcp.server as server_module
|
|||
from pyro_mcp.contract import (
|
||||
PUBLIC_MCP_VM_RUN_PROFILE_TOOLS,
|
||||
PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS,
|
||||
PUBLIC_MCP_WORKSPACE_FULL_PROFILE_TOOLS,
|
||||
)
|
||||
from pyro_mcp.server import create_server
|
||||
from pyro_mcp.vm_manager import VmManager
|
||||
|
|
@ -30,7 +29,7 @@ def test_create_server_registers_vm_tools(tmp_path: Path) -> None:
|
|||
return sorted(tool.name for tool in tools)
|
||||
|
||||
tool_names = asyncio.run(_run())
|
||||
assert tuple(tool_names) == tuple(sorted(PUBLIC_MCP_WORKSPACE_FULL_PROFILE_TOOLS))
|
||||
assert tuple(tool_names) == tuple(sorted(PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS))
|
||||
|
||||
|
||||
def test_create_server_vm_run_profile_registers_only_vm_run(tmp_path: Path) -> None:
|
||||
|
|
@ -123,7 +122,7 @@ def test_vm_tools_status_stop_delete_and_reap(tmp_path: Path) -> None:
|
|||
list[dict[str, object]],
|
||||
dict[str, Any],
|
||||
]:
|
||||
server = create_server(manager=manager)
|
||||
server = create_server(manager=manager, profile="workspace-full")
|
||||
environments_raw = await server.call_tool("vm_list_environments", {})
|
||||
if not isinstance(environments_raw, tuple) or len(environments_raw) != 2:
|
||||
raise TypeError("unexpected environments result")
|
||||
|
|
@ -299,7 +298,7 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
return cast(dict[str, Any], structured)
|
||||
|
||||
async def _run() -> tuple[dict[str, Any], ...]:
|
||||
server = create_server(manager=manager)
|
||||
server = create_server(manager=manager, profile="workspace-full")
|
||||
created = _extract_structured(
|
||||
await server.call_tool(
|
||||
"workspace_create",
|
||||
|
|
|
|||
2
uv.lock
generated
2
uv.lock
generated
|
|
@ -715,7 +715,7 @@ crypto = [
|
|||
|
||||
[[package]]
|
||||
name = "pyro-mcp"
|
||||
version = "3.11.0"
|
||||
version = "4.0.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "mcp" },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue