Client integration
Install the client you use:
spill install codex spill install claude spill install cursor
claude-code is accepted as an alias. These commands configure local CLI clients — not Claude Desktop. All clients share the same ~/.spill/spill.duckdb database. Restart your client after installation and approve any MCP/hook trust prompts.
Configuration ownership
The installer backs up changed files and tracks ownership separately per client. It refuses conflicting entries and only removes entries it added during uninstall:
| Client | MCP config | Hook config | Result replacement |
|---|---|---|---|
| Cursor | ~/.cursor/mcp.json |
~/.cursor/hooks.json |
postToolUse.updated_mcp_tool_output |
| Codex | ~/.codex/config.toml |
~/.codex/hooks.json |
continue: false, descriptor in stopReason |
| Claude Code | ~/.claude.json |
~/.claude/settings.json |
hookSpecificOutput.updatedMCPToolOutput |
Codex
Codex registers [mcp_servers.spill] in ~/.codex/config.toml and appends a matching hook group to ~/.codex/hooks.json. Existing TOML comments and inline hook definitions remain intact.
Codex does not support updatedMCPToolOutput. The adapter uses continue: false with the dataset descriptor in stopReason — the model receives hook feedback in place of the raw result. This requires a Codex version implementing that PostToolUse behavior.
CODEX_HOME overrides the config directory. Paths must be absolute. Install and uninstall using the same directory.
Claude Code
Claude Code registers a user-scope mcpServers.spill in ~/.claude.json and a PostToolUse hook in ~/.claude/settings.json. Project-specific servers, permissions, and other settings remain intact.
The adapter uses hookSpecificOutput.updatedMCPToolOutput — this field works on versions predating the newer all-tool updatedToolOutput. If CLAUDE_CONFIG_DIR is set, the files are <dir>/.claude.json and <dir>/settings.json.
Cursor
Cursor registers the MCP server in ~/.cursor/mcp.json and a PostToolUse hook in ~/.cursor/hooks.json using the documented postToolUse replacement contract: tool_output, tool_use_id, the MCP matcher, and updated_mcp_tool_output.
Manual acceptance check
The automated tests exercise the documented contract but cannot inspect the client's internal context assembly. This check confirms the original result is excluded from model context on your specific build.
- Build/install Spill and run the installer for your client.
- Register the demo MCP fixture, substituting an absolute path:
bash
codex mcp add spill-demo -- python3 /absolute/path/to/spill/scripts/demo_mcp.py # or: claude mcp add --scope user spill-demo -- python3 /absolute/path/to/spill/scripts/demo_mcp.py - Restart the client. Confirm Spill's
query,list, anddescribetools are available. - Ask it to call
spill-demo.list_issuesthen count issues by state with Spill SQL. - Inspect the tool output — a compact descriptor with 2,000 rows should replace the full array. Expected counts: OPEN 1,000, CLOSED 1,000.
- Confirm with
spill list,spill describe <dataset>, andspill sql 'SELECT count(*) FROM <dataset>'. - Call
spill-demo.small_resultand confirm pass-through. - Run
spill uninstall cursor(or your client) and confirm unrelated config is preserved. - Remove the demo server:
codex mcp remove spill-demoorclaude mcp remove --scope user spill-demo.
Homebrew tap
This repository doubles as a custom Homebrew tap through its Formula/ directory. No separate tap repo is needed:
brew tap spill-ai/spill https://github.com/spill-ai/spill
brew trust --formula spill-ai/spill/spill # Homebrew 6+ only
brew install spill
spill install cursor
A bare brew install spill without the tap requires a future submission to homebrew/core. The explicit URL is necessary because Homebrew's default shorthand would look for spill-ai/homebrew-spill.
Stable builds
Formula/spill.rb pins a tagged release tarball and SHA256. Homebrew builds with cargo install --locked, including bundled DuckDB. There are no prebuilt bottles yet.
To publish an update:
- Run formatting, Clippy, Rust tests, and
scripts/smoke.py. - Update
Cargo.tomlversion and commit. - Tag the release:
git tag v0.2.0 <sha> && git push origin v0.2.0 - Get the tarball SHA:
curl -sL https://github.com/spill-ai/spill/archive/refs/tags/v0.2.0.tar.gz | shasum -a 256 - Update
url,sha256, andversioninFormula/spill.rb. - Commit the formula change and push. Users run
brew update && brew upgrade spill.
Local verification
brew tap spill-ai/spill https://github.com/spill-ai/spill brew install --build-from-source spill-ai/spill/spill brew test spill-ai/spill/spill
The formula test uses Homebrew's temporary test home. It checks installation, spilling a large result, SQL access to saved rows, and uninstall. It does not modify your actual client configuration.
Cursor acceptance demo
This manual check is required to confirm the original result stays out of model context — automated tests exercise the documented contract but cannot inspect Cursor's context assembly.
- Build with
cargo install --path ., then runspill install cursor. - Add the demo server to
~/.cursor/mcp.json:json{ "mcpServers": { "spill-demo": { "command": "python3", "args": ["/absolute/path/to/spill/scripts/demo_mcp.py"] } } } - In Cursor, verify both
spillandspill-demoare connected. - Ask: "Use spill-demo list_issues, then count issues by state using Spill SQL."
- Inspect tool output — it should contain a dataset descriptor, not 2,000 raw objects. Expected aggregate: OPEN 1,000, CLOSED 1,000.
- Run
spill list,spill describe <dataset>, and the count query in a terminal. - Ask Cursor to call
spill-demo small_result— the single object should pass through unchanged. - Run
spill uninstall cursorand confirm unrelated servers and hooks are preserved. - Remove the demo entry from
~/.cursor/mcp.json.
Development commands
cargo fmt --all -- --check cargo clippy --all-targets -- -D warnings cargo test cargo build python3 scripts/smoke.py target/debug/spill
CI runs on Linux and macOS. The smoke test exercises the real binary, stdio MCP transport, and hook path in a temporary directory without touching your actual client configuration.