Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,39 @@ All notable changes to this project are documented here. Format follows

## [Unreleased]

## [0.3.1] - 2026-08-02

### Added
- Every tool now declares what it does to the machine: `title`, and
`ToolAnnotations` with `readOnlyHint`, `destructiveHint`, `idempotentHint`
and `openWorldHint`. Rigout advertised fifteen tools identically, so reading a
CPU count and running an arbitrary command as root reached a client looking
the same and anything wanting to warn before the second had only the name to
go on. Four tools are read-only, nine are destructive, and two are neither -
they change something but only add or open it, never overwrite or remove.
Anything that runs a caller's command is marked destructive and not
idempotent, because what it does is decided by the caller and cannot be
known here.

### Changed
- The `mcp` bound widens to `>=1.0.0,<3`: Rigout now runs on both majors. 1.x
registers the tool handlers with decorators and 2.x removed them for explicit
`add_request_handler`, and that is the entire incompatibility - every tool
definition constructs unchanged, because 2.x renamed `Tool`'s fields while
keeping the camelCase spellings as aliases. Two reads did need care, since
the aliases cover construction and not attribute access: `CallToolResult`'s
error flag is `is_error` on 2.x and `isError` on 1.x, and the same holds for
annotation hints. Both are read through helpers that work either way.
Supporting both is deliberate rather than transitional - nobody is pushed onto
a major the week it appears, and nobody is stranded on the old one.
- `VERSIONING.md` records which capabilities of the current MCP line Rigout
adopts and which it declines. Tasks - long-running work a client polls rather
than waits for - are declined despite addressing Rigout's oldest limitation,
because the API is deprecated in the version Rigout pins and
`mcp.server.experimental.task_support` raises `ModuleNotFoundError` on 2.0.0,
the version Rigout must move to next. The types survive there, which makes the
feature look available to anyone reading `mcp.types`.

## [0.3.0] - 2026-08-01

### Added
Expand Down
69 changes: 69 additions & 0 deletions VERSIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,75 @@ Two things watch this so it does not become permanent:
- The same workflow reports which dependencies are held back and by how far, so an
overdue major is visible rather than forgotten.

## What Rigout adopts from a new MCP, and what it declines

Being behind on a major does not mean ignoring what the current line offers. Two
capabilities were assessed against mcp 1.29 in August 2026, and they went opposite ways.

**Tool annotations: adopted.** `Tool.title` and `ToolAnnotations` - `readOnlyHint`,
`destructiveHint`, `idempotentHint`, `openWorldHint` - let a client tell a question apart
from an action before it runs one, which matters more here than in most servers: reading
a CPU count and running an arbitrary command as root are both tools Rigout offers. The
fields are in the specification, present in 1.x and 2.x alike, and additive to clients
that ignore them.

**Tasks: declined, and this is worth stating so it is not rediscovered.** `Tool.execution`
with `taskSupport`, the `Task` type, `tasks/get` and its siblings, and
`mcp.server.experimental.task_support` together describe long-running work a client polls
rather than waits for. That addresses Rigout's oldest limitation directly - a command
that outlives its timeout fails, and builds, installs and downloads all can.

It is not adopted, because the API says of itself:

> The experimental tasks API is deprecated and will be removed in mcp 2.0: tasks
> (SEP-1686) were removed from the MCP specification and are expected to return as a
> separate MCP extension.

Checked rather than taken on the warning's word: `mcp.server.experimental.task_support`
raises `ModuleNotFoundError` on 2.0.0. The types survive there, which makes the feature
look available to anyone reading `mcp.types`, but the server half is gone.

Building on it would mean shipping a feature on an interface that is deprecated in the
version Rigout pins and absent from the version it must move to next. That is the same
trade as the unbounded `mcp>=1.0.0` in 0.2.0: it works until someone else's release day.
When tasks return as an extension, this is worth revisiting, and the reason to revisit is
recorded above.

## The mcp 2.x migration, mapped

Rigout pins `mcp>=1.0.0,<2` and speaks MCP protocol `2025-11-25` where 2.x speaks
`2026-07-28`. Moving is a release of its own. What it involves is recorded here because
the discovery is most of the work and is easy to redo badly.

What does **not** change, checked against 2.0.0 rather than assumed:

- `Tool(name=..., description=..., inputSchema=...)` constructs unchanged. 2.x renamed the
fields to `input_schema` and friends but keeps the camelCase spellings as aliases, so
every tool definition ports as written.
- `mcp.server.stdio`, `mcp.server.streamable_http_manager`, `mcp.server.models` and
`mcp.types` all still import.
- `Server`, `Server.run` and `create_initialization_options` all survive.

What does change, and is the whole of the migration:

- `@server.list_tools()` and `@server.call_tool()` are gone. Registration is now
`server.add_request_handler(method, params_type, handler)`, with
`"tools/list"` taking `PaginatedRequestParams` and `"tools/call"` taking
`CallToolRequestParams`.
- The handlers therefore return results directly rather than the bare list and content
the decorators wrapped, which also removes the wrinkle where an error result has to be
raised as `RuntimeError` for the SDK to rebuild it.

Two decisions to make before starting, neither obvious:

- **Whether to support both majors or move.** The incompatibility is only the
registration, so a single `hasattr(Server, "list_tools")` branch would let the cap
widen to `<3` and not force anybody onto a major that is days old. The cost is a fork
in the code that has to be tested twice, on both lines.
- **Whether it is time at all.** Nothing Rigout needs is exclusive to 2.x - tasks, which
looked like the reason to move, are gone from both. The protocol revision is the only
gain, and the caps mean nobody is broken meanwhile.

## Releasing

```bash
Expand Down
3 changes: 2 additions & 1 deletion production_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,13 @@ def validate_runtime_contracts() -> list[str]:
from rigout import __version__
from rigout.mcp_http_server import create_app
from rigout.server import handle_call_tool_result, server
from rigout.tools._results import result_is_error

if getattr(server, "version", None) != __version__:
issues.append(f"MCP server version is {getattr(server, 'version', None)}, expected {__version__}")

unknown_result = asyncio.run(handle_call_tool_result("definitely_unknown_tool", {}))
if not unknown_result.isError:
if not result_is_error(unknown_result):
issues.append("Unknown MCP tools are not marked with isError=true")

app = create_app(connection_file=None, setup_token="setup-check", auth_token="bearer-check")
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "rigout"
version = "0.3.0"
version = "0.3.1"
description = "Let AI agents use your computer through MCP."
readme = "README.md"
requires-python = ">=3.10"
Expand Down Expand Up @@ -39,7 +39,7 @@ classifiers = [
# which are not shipped, so it moved to the dev extra. cryptography still arrives
# transitively via paramiko, which owns the version it needs.
dependencies = [
"mcp>=1.0.0,<2",
"mcp>=1.0.0,<3",
"starlette>=0.37.0,<2",
"uvicorn>=0.29.0,<1",
"paramiko>=3.0.0,<6",
Expand Down
Loading
Loading