@customaise/mcp 3.0.0 — the 2026-07-28 revision and a terminal control plane
[3.0.0] - 2026-08-21
Added
-
customaise, a terminal control plane. A second binary alongsidecustomaise-mcp. It talks to a resident daemon over a loopback MCP endpoint, so a coding agent with a shell can list scripts, install them, drive tabs and call WebMCP tools without an IDE in the loop.npm i -g @customaise/mcp customaise doctor customaise scripts install ./my-tool.agent.js customaise tab reload 42 customaise call my_tool --args '{"q":"hello"}'JSON on stdout, diagnostics on stderr, and exit codes an agent can branch on:
0ok,2usage,3extension or daemon unreachable (signing out counts, because it takes the bridge down with it),4the token expired or could not refresh while the bridge was up,5cap reached,6consent denied,7consent timed out,8rejected by Customaise.8is the one to handle first when installing scripts: it means the sanitization pipeline refused the file and the diagnostics in the payload say what to change, where1means something broke and rewriting the script will not help. Everything routes through the same cap enforcement and the same human-in-the-loop consent gate as the IDE path; the CLI is another door onto the same room, not a way around it.The daemon starts on first use and stops with
customaise daemon stop. It authenticates the CLI with a token in a0600file that only exists while the endpoint is live, and it binds127.0.0.1only. -
The CLI now tells you when "Allow user scripts" is off. That toggle lives on the Customaise card in
chrome://extensions, it resets every time Chrome restarts or the extension reloads, and while it is off no script runs and no WebMCP tool registers. The warning existed, but only in the half of a tool result a model reads: the CLI parses the structured half, deliberately kept as clean JSON, so a terminal agent got silence in exactly the situation the warning exists for. Installs succeeded, tools never appeared, and nothing said why. It is now a field on the structured result, printed to stderr so stdout stays pipeable, andcustomaise doctorreportsuserScriptsand exits 3 rather than claiming a healthy setup that cannot run anything. -
The core loop no longer bills twice. Five tools fetched the "Allow user scripts" banner with a second, invisible
dispatchTool, and that dispatch spent a cap unit:list_scripts,export_script,reload_tab,list_webmcp_toolsandcall_webmcp_tool. The documented loop of install, reload, list, call therefore cost eight units instead of four, so the free tier's real budget for the workflow the product is built around was half what it advertises. The extension now attaches that state to everydispatch_ackand toinit_session, so the banner is fresher than a cached fetch would be and costs nothing. No change to what counts as usage; the second call simply stopped existing. -
get_bridge_status, anddoctornow costs nothing. Reports whether the extension is attached, your plan tier, whether you are signed in, whether remote approvals are on, and how much of the cap is left today and this week. It spends no cap units: everything it reports already arrives on the bridge'sinit_sessionframe, so the server answers from state it holds rather than calling the browser.customaise doctorpreviously ranlist_tabs, which meant working out why MCP was failing cost one of the fifty daily calls that might have been why it was failing. Fields that the extension has not reported come back asunknownrather than as a confidentfalse. -
--versionand--helponcustomaise-mcp. The published install instructions have told every IDE flow to verify withnpx -y @customaise/mcp --version. There was no argument handling, so that command started a stdio server and hung the terminal with no output: the one step meant to say "it worked" was the step that looked broken. It now prints the version and exits. -
Machine-readable tool errors. Every tool now fails with a structured payload carrying a stable
typealongside the human message, instead of a thrown string:auth_required,cap_exceeded,extension_not_connected,dispatch_timeout,extension_outdated,integrity_violation,consent_denied,consent_timeout,internal_error. Sixteen handlers previously threw untyped, which reached the client as an opaque failure that an agent could only respond to by retrying. Branch ontype, never on the message text or the numeric code: the numbers sit in a range the2026-07-28revision has since reserved and may yet move, and the strings will not.
Changed
-
Speaks the MCP
2026-07-28revision, and still speaks2025-11-25. The server now runs on the v2 SDK (@modelcontextprotocol/server) through itsserveStdioentry, which negotiates the protocol revision per connection. A client that has not moved gets2025-11-25, the exact revision this server spoke before, served from the same factory. A 2026-capable client gets2026-07-28. One binary, both eras, nothing to configure and no flag day.Why the major version. The package was at
2.0.7while the specification revision is colloquially called "MCP 2.0", so2.0.7read as though it already spoke it. It did not. Shipping the real migration as2.1.0would have made that worse, so the version jumps to make the two numbers stop arguing. Nothing about the extension-to-server bridge protocol changed:MIN_EXTENSION_VERSIONis still1.2.3and no working install is stranded. -
Node 20 or newer is now required (was 18), following the v2 SDK's floor. Claude Desktop bundles its own Node and clears this comfortably.
-
zod 4.2 or newer is now required (was 3.24), also following the SDK. Tool descriptions written with
.describe()are preserved through the new schema conversion, and the emitted JSON Schema now declares the 2020-12 dialect. -
Tool and resource list results carry cache hints on 2026-07-28 connections.
tools/list,resources/list,resources/templates/listandserver/discoveradvertise a one-hour TTL, because those registration sets are fixed at build time.resources/readdeliberately does not: it coverscustomaise://scripts, which is your live script library, and a cached copy of that would have an agent writing against scripts you no longer have. The three static conventions handbooks opt into caching individually. Everything iscacheScope: private.
Fixed
-
A second MCP process no longer breaks when the first one exits. Only one
customaise-mcpbinds the extension's WebSocket port; the rest run as followers and proxy through it. When that leader went away, followers never reattached, so restarting one IDE left every other MCP client and the CLI daemon returning "extension not connected" until each was restarted by hand. Followers now reconnect with a capped backoff and pick up whichever process holds the port next. The code comment describing the old behaviour claimed a promotion mechanism that was never implemented, which is why this survived review. -
The connected-IDE name no longer disappears on modern clients. Client identity arrives through the
initializehandshake on2025-11-25and through a per-request_metaenvelope on2026-07-28, and neither source is populated in the other era. The server now reads both, so the extension's Settings panel names the connected IDE whichever revision it negotiated.
Internal
- The test suite no longer substitutes a hand-written stub for the MCP SDK. It had done so since March, which meant 105 tests had never exercised the library they describe. Removing the substitution required no test changes.
mcp/is covered by the repository's CI for the first time, along with a changelog currency gate mirroring the extension's.