# Exploit — rmcp Rust client MCP contract migration

## Winning Approach

The explore winner was a Rust-native MCP client test path using `rmcp` client features already compatible with BioMCP's rmcp server. The exploit built that out at full scale: pytest and markdown MCP-client checks now use Rust rmcp coverage/helpers instead of the Python `mcp` SDK dev dependency.

## Full-Scale Results

Full-scale command: `cargo nextest run --test rmcp_client_contract`

Measured result:

- 6 tests run, 6 passed, 0 failed.
- Total focused rmcp contract run: 3.812 s.
- Stdio explore-shaped core: 0.029 s in full run.
- Stdio chart contract: 0.058 s.
- HTTP explore-shaped core: 0.059 s in full run.
- HTTP chart contract: 0.085 s.
- HTTP full contract: 0.865 s.
- Stdio full contract: 3.812 s.

Full-scale coverage includes initialize, tool metadata/description, version calls, exact resource inventory and reads, help-resource/body parity, allowed read-only commands, rejected mutating/CLI-only commands, invalid-resource MCP error shape, chart text+SVG image content, and the same coverage over Streamable HTTP.

## Regression Control

Explore baseline:

- `cargo test --no-run --test rmcp_client_contract`: pass.
- `cargo nextest run --test rmcp_client_contract`: 2 tests, 2 passed.
- Stdio core runtime: 0.023 s.
- HTTP core runtime: 0.276 s.
- Mismatch count: 0.

Exploit reproduced the explore-shaped benchmark separately with:

```bash
cargo nextest run --test rmcp_client_contract rmcp_child_process_client_verifies_stdio_core_contract rmcp_streamable_http_client_verifies_core_contract
```

Measured control result:

- 2 tests run, 2 passed, 0 failed.
- Stdio core runtime: 0.022 s.
- HTTP core runtime: 0.054 s.
- Mismatch count: 0.

Regression rule result: pass. Correctness stayed equal at 0 mismatches. Stdio and HTTP throughput/latency both beat explore. No checksum baseline existed in explore.

Implementation note: I split the explore-shaped core checks back out from the new full-contract tests so the regression control stayed apples-to-apples, and tightened HTTP readiness polling from 250 ms to 25 ms.

## Validation

Passed gates:

- `make lint`
- `make test`
- `make spec`

Other focused checks run:

- `cargo test --no-run --test rmcp_client_contract`
- `cargo nextest run --test rmcp_client_contract`
- `cargo check --example rmcp_streamable_http_contract`
- `uv run --no-sync pytest tests/test_streamable_http_demo.py tests/test_upstream_planning_analysis_docs.py::test_runtime_contract_docs_and_scripts_align_on_release_target -q`

Dependency validation:

- Removed `mcp>=1.0.0` from `pyproject.toml` dev extras.
- Refreshed `uv.lock`; the Python MCP dependency tree was removed.
- Removed test/spec support imports of Python `mcp`.
- Left the public `examples/streamable-http/streamable_http_client.py` demo self-contained with inline `uv --script` metadata, but made its `mcp` import lazy so repo pytest no longer requires that package in dev extras.

Remaining gap: none for the ticket scope. The public Python demo still uses Python `mcp` as its own self-contained demo dependency; that is not part of the repo dev extra or test/spec support path.

## Produced Artifacts

Tracked source/docs artifacts:

- `tests/rmcp_client_contract.rs` — full Rust rmcp client contract coverage for stdio and Streamable HTTP.
- `examples/rmcp_streamable_http_contract.rs` — Rust helper used by `spec/surface/mcp.md` to exercise Streamable HTTP tool calls.
- `spec/surface/mcp.md` — markdown MCP spec now invokes the Rust helper instead of inline Python `mcp` blocks.
- `scripts/run-specs.sh` — removed MCP markdown Python dependency setup.
- `pyproject.toml` and `uv.lock` — Python `mcp` dev dependency removed.
- `architecture/experiments/rmcp-client-mcp-contract/exploit.md` — copied report.

Persistent local, gitignored measurement artifacts:

- `architecture/experiments/rmcp-client-mcp-contract/results/rmcp-client-contract.json` — explore result kept locally, no longer tracked.
- `architecture/experiments/rmcp-client-mcp-contract/results/rmcp-client-contract-exploit.json` — exploit result payload.

## Contract Numbers

Downstream spikes can depend on these exploit-measured values:

- Regression control: 2 rmcp tests, 2 passed; stdio core 0.022 s; HTTP core 0.054 s; mismatch count 0.
- Full rmcp contract: 6 tests, 6 passed; total focused run 3.812 s.
- Full stdio contract: 3.812 s.
- Full HTTP contract: 0.865 s.
- Chart-only checks: stdio 0.058 s; HTTP 0.085 s.
- Standard gates: `make lint`, `make test`, and `make spec` passed.
- Python dev dependency count after removal: `uv lock` resolved 46 packages and removed the Python MCP tree, including `mcp`, `pydantic`, `pydantic-settings`, `starlette`, `pyjwt`, `httpx`, `uvicorn`, and related transitive packages.

## Conclusions

The rmcp client migration works at full ticket scale. BioMCP no longer needs the Python `mcp` SDK in repo dev extras to verify its MCP contract. The contract is now closer to the Rust server implementation, covers both supported transports, and removes the recurring security-alert noise from the dev-only Python MCP tree.

Main risk remaining is dev/test compile cost from enabling rmcp client transports and the rmcp HTTP client dependency stack. That cost is confined to dev/test features and the standard gates passed with it.
