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