0.3.0 — grouped tools, output caps, annotations, prompts
grouped tools, output caps, annotations, prompts
Cuts the tool surface from 26 tools to 10 and adds the three things a
client needs to use them safely and cheaply.
Tools (26 -> 10, ~39% smaller schema payload)
Every tool schema sits in the model's context for the whole session, so
related CLI subcommands are now grouped behind an action/resource
argument instead of one tool per subcommand. Nothing was dropped:
list_modal_resources covers all eight read-only lookups, and the
manage_* tools cover app stop/rollback, container exec/stop, volume
create/delete/rename, volume file put/get/cp/rm, and secret
create/delete. See the upgrade table in the README for the mapping.
Output caps
The streaming runner was bounded by time, not volume, so a chatty app
could return megabytes of logs into the caller's context in one result.
Text fields are now capped (head + tail, line-snapped, with a marker
naming what was dropped) at MCP_MODAL_MAX_OUTPUT_CHARS, default 40000,
0 to disable; JSON listings cap at 200 entries with omitted_items.
Capping happens at the response boundary only: JSON is parsed intact,
and search_modal_logs greps the whole log before capping the returned
blocks, so match_count stays exact.
Tool annotations
Every tool declares readOnlyHint / destructiveHint / idempotentHint, so
clients can auto-approve the three read-only tools and keep prompting
for volume deletes and container exec.
Prompts
Adds debug_modal_app, deploy_and_verify and review_modal_account.
Clients fetch prompts on demand, so multi-step guidance costs nothing
in per-session tool schema.
Fixes
- Volume file operations now accept env. Volumes are environment-scoped
and every modal volume subcommand takes -e, but ls/put/get/cp/rm
silently used the default environment. Container logs/exec/stop
correctly still take no -e; the CLI accepts none there. - modal_volume_files supports recursive for cp.
- Log tools accept target="auto", resolving app vs container from the
ta- ID prefix. - Pin mcp>=1.9.2,<2. mcp 2.x renames FastMCP to MCPServer, and uvx
resolves from PyPI metadata rather than uv.lock, so an unbounded
specifier breaks new installs. - Reissue LICENSE with the correct copyright holder.
Install
uvx mcp-modal@0.3.0 # run this exact version
claude mcp add mcp-modal -- uvx mcp-modal@0.3.0Also on PyPI: mcp-modal 0.3.0. The .whl and
.tar.gz attached below are the exact artifacts published to PyPI for this version.
Full changelog: v0.2.4...v0.3.0