feat(mcp): serve tools from the Ix CLI instead of shipping a server - #24
Open
KageBinary wants to merge 3 commits into
Open
feat(mcp): serve tools from the Ix CLI instead of shipping a server#24KageBinary wants to merge 3 commits into
KageBinary wants to merge 3 commits into
Conversation
This plugin shipped its own MCP server: `mcp/server.ts` plus 23 tools in `mcp/tools/`, each wrapping an `ix` CLI call. The CLI now serves the same 23 tools as `ix mcp`, so this was a second implementation of one surface, maintained separately from the other five plugins' servers. mcp.json points Cursor at `ix mcp`. Tool parity is exact — the CLI serves the same 23 names — so nothing an agent could call before is gone. What stays: `mcp/hooks/`, `mcp/lib/` and `mcp/shared/`. hooks.json runs `node mcp/dist/hooks/*.js`, and MCP has no concept of a hook, so this is the part `ix mcp` cannot absorb. The npm build stays with it; the install messages just no longer call it "the MCP server". Also removed as unreachable once tools/ is gone: - `lib/llm.ts` — only tools/ ever imported it. Redaction on the hook path is unaffected: that lives in shared/secrets.ts, which lib/parser.ts and lib/errors.ts use directly. - `tests/integration/llm-passthrough.test.ts` (4 tests) — its subject was the tool layer's llm-vs-JSON dispatch, which is now the CLI's. - `tests/unit/llm.test.ts` (8 tests) — covered the module above. Test count therefore drops 15 -> 3; all three pass, as do typecheck and a clean rebuild, and all seven hooks.json entrypoints still emit to mcp/dist/hooks/. The 12 removed tests covered removed code. @modelcontextprotocol/sdk and zod are dropped from mcp/package.json — the server and tools were their only consumers.
KageBinary
force-pushed
the
feat/mcp-delegate-to-ix-cli
branch
from
August 12, 2026 00:29
d17ba12 to
05340b5
Compare
mcp.json points Cursor straight at `ix mcp`, which only exists from 0.9.3. On an older CLI nothing here objects: the registration is written, accepted, and then fails at spawn with "unknown command 'mcp'", which Cursor reports as a generic connection failure. Nothing tells the user to upgrade. ix-codex-plugin gates this at runtime through MIN_IX_VERSION_FOR_MCP. Cursor has no equivalent hook — mcp.json names the binary directly, and adding a shim to hold a version check would put back the wrapper this PR removes. So the check goes where there is still somewhere to print: the installer. An unreadable version warns rather than blocks. A version this script cannot parse is not grounds for refusing an install that may well work, and on Windows the likeliest cause of an unreadable one is a broken launcher, which is its own message. The PowerShell path reads the version inside try/catch. $ErrorActionPreference is Stop and from PowerShell 7.4 $PSNativeCommandUseErrorActionPreference makes a non-zero exit terminating, so a broken `ix` — the exact case the warning is for — would otherwise abort with a native-command error instead. shellcheck clean. Gate verified against 0.8.1/0.9.2 (block), 0.9.3/0.9.4/ 0.10.0/1.0.0 (pass, including the 0.10-over-0.9 ordering), and empty or unparseable output (warn).
Collaborator
Author
|
The version gate is satisfied —
Nothing further is needed here — the floor this PR gates on now exists. Ready to merge; the repo ruleset means it needs someone with bypass rights. |
…spawn
mcp.json now names the bare `ix`, and Cursor spawns that itself through
CreateProcess -- which consults no PATHEXT, while npm ships no ix.exe, only
ix.CMD. So the registration this PR introduces could never start on Windows.
The old entry ran `node ./mcp/dist/server.js` and was unaffected, making this a
regression rather than a pre-existing gap.
The bare name is correct on macOS and Linux and survives an upgrade that moves
the install, so this is fixed where the file is copied rather than in the file
itself: install.ps1 resolves a launcher and rewrites the copied mcp.json.
Resolution mirrors ix-cli/src/mcp/hosts.ts, including the part that is not
obvious -- `where ix` lists the exact-name match FIRST, and npm's is an
extensionless `#!/bin/sh` shim that CreateProcess cannot launch, so taking the
first line records the one entry that does not work. Only an entry carrying a
PATHEXT extension is accepted. Failing to resolve one warns rather than throws:
the hooks and skills do not depend on it, and leaving the bare name is no worse
than not trying.
Written with WriteAllText and a BOM-less UTF8Encoding, because Set-Content
-Encoding UTF8 emits a BOM on Windows PowerShell 5.1 and a BOM ahead of `{`
breaks a strict JSON parser -- which would corrupt the file being repaired.
Entries are matched by command rather than by server name, since the name
follows $PluginName.
Also carries over two edits install.sh got in this PR and install.ps1 did not:
the build gate still tested for mcp\dist\server.js, the file this PR deletes,
so every Windows install re-ran `npm ci && npm run build` unconditionally and
announced it as "Building MCP server..." for a server that no longer exists. It
now gates on the hooks entry point, as install.sh does.
Not executed: no PowerShell on the machine this was written on, and this repo's
CI has no Windows job.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces this plugin's own MCP server with the one the Ix CLI now ships.
What changed
mcp/server.tsplus 23 tools inmcp/tools/each wrapped anixCLI call. The CLI serves the same 23 tools itself asix mcp, so this was a second implementation of one surface — maintained here, and drifting independently of the other five plugins' servers.mcp.jsonnow points Cursor atix mcp.Tool parity is exact.
ix mcpserves the same 23 names, verified by diffing the two surfaces. Nothing an agent could call before is gone.What stays, and why
mcp/hooks/,mcp/lib/andmcp/shared/are untouched.hooks/hooks.jsonrunsnode mcp/dist/hooks/*.js, and MCP has no concept of a hook — this is the partix mcpcannot absorb. The npm build stays with it; the install messages just stop calling it "the MCP server". All sevenhooks.jsonentrypoints still emit tomcp/dist/hooks/after a clean rebuild.Also removed, as unreachable once
tools/is gonelib/llm.ts—tools/was its only importer. Redaction on the hook path is unaffected: that lives inshared/secrets.ts, whichlib/parser.tsandlib/errors.tsuse directly.tests/integration/llm-passthrough.test.ts(4 tests) — its subject was the tool layer's llm-vs-JSON dispatch, which is now the CLI's business.tests/unit/llm.test.ts(8 tests) — covered the module above.@modelcontextprotocol/sdkandzodfrommcp/package.json— the server and tools were their only consumers.Flag this one on review if you would rather keep
lib/llm.ts: it is dead after this change, but it is recent deliberate work and reverting that part is a one-file change.Tests
Test count drops 15 → 3; all three pass, plus typecheck and a clean rebuild. The 12 removed tests covered removed code.
plugin-success-loop.test.tskept its coverage — it drove the hook loop throughtools/subsystems, and now reads the graph throughlib/cli, asserting againstix subsystems --format jsonas the CLI actually emits it rather than the envelope the tool used to build.Note the baseline: a fresh clone fails 6/15 until
npm ciruns inmcp/. That is pre-existing and unrelated.Version floor
ix mcpneedsix >= 0.9.3, the first release carrying the subcommand. This PR cannot land before that release exists. It is opened now so the migration is reviewable, not because it is ready to merge.Not in scope
Hooks, rules, skills and subagents stay exactly as they are — see
docs/mcp-plugin-consolidation.mdin the Ix repo for the full matrix.