github nicobailon/pi-mcp-adapter v4.0.0

2 hours ago

pi-mcp-adapter 4.0.0 makes Figma work with Pi and gives /mcp-adapter setup a steadier, easier layout. Figma's remote server doesn't accept Pi yet, so setup now offers the Figma desktop app's local server instead and tells you how to switch it on. Other extensions can now call your MCP tools directly, going through the same approval rules as the model. mcpScript is now opt-in, and when you turn it on it picks the right tool more reliably and remembers what each tool returns between sessions. Errors are clearer too, and Pi 0.99 and git-installed Pi packages work again.

Highlights

  • Figma through the desktop app. /mcp-adapter setup offers Figma (desktop) when the app is installed, and tells you how to enable its server.
  • A calmer setup panel. It keeps one size, groups actions into sections, shows details beside the list, and scrolls long previews with PgUp/PgDn.
  • MCP tools for other extensions. Extensions can call your configured MCP tools through Pi's event bus, with the same approval rules.
  • Better scripting when you want it. With mcpScript on, scripts handle servers that share tool names and remember each tool's output fields across sessions.
  • Errors that say what to do. Clearer messages when an OAuth server refuses Pi or a local MCP server isn't running, plus fixes for Pi 0.99 and git-installed Pi packages.

Need to know

If you… Do this
use mcpScript Set settings.scriptMode to true in mcp-adapter.json. It is off by default now.
call tools.describe from scripts Pass the server from the search result, tools.describe({ path, server }), and handle error: { code, message } (for example ambiguous_tool) where it used to return the first match.
read observedOutput from tools.describe target is now the full expression that reads the JSON, and calls is gone.

Changelog

Highlights

  • Figma now works with Pi through the Figma desktop app. /mcp-adapter setup offers it when the app is installed and tells you how to turn its server on.
  • /mcp-adapter setup is easier to use: it keeps one size, groups actions into sections, shows details beside the list, and scrolls long previews.
  • Other extensions can call your MCP tools directly, with the same approval rules the model gets.
  • mcpScript is now opt-in. When you turn it on, scripts pick the right tool when servers share tool names and remember what each tool returns across sessions.
  • Errors now say what to do when an OAuth server refuses Pi or a local MCP server isn't running, and Pi 0.99 and git-installed Pi packages work again.

Breaking

  • mcpScript is off by default. To keep using it, set settings.scriptMode to true in mcp-adapter.json. Its bundled skill, the pointer to it in the mcp tool description, and the large-result hint (see Changed) follow the same setting.
  • tools.describe in mcpScript now looks tools up the same way as mcp({ describe }). Where it used to return the first server's match, it can now return error: { code, message }: ambiguous_tool when equally good matches exist on more than one server, and server_disabled or server_backoff when only a disabled or backed-off server has the tool. A clearly closer match, such as an exact name against a normalized one, is still picked without an error. Pass the server from the search result when the target matters: tools.describe({ path, server }).
  • observedOutput.target from tools.describe is now the full expression that reads the JSON, such as (await tools.call("github_list_issues", args)).data.structuredContent, instead of data.structuredContent. Models misread the short form.
  • observedOutput no longer has calls, and describe no longer says how many calls a shape came from, since saved shapes can come from earlier sessions.

Added

  • Other extensions can call a configured MCP tool by emitting pi-mcp-adapter:runtime-tool-call:v1 on Pi's event bus. The call goes through the same tool lookup and approval as mcp({ tool }), and request.result resolves to { ok: true, result } or { ok: false, error }. Thanks to @Djarid for PR #735.
  • /mcp-adapter setup offers Figma (desktop) when the Figma app is installed. It adds the app's local server at http://127.0.0.1:3845/mcp and, if nothing answers there yet, says how to turn it on in Figma. Figma's remote server only accepts clients Figma has approved, and Pi isn't one yet.
  • tools.describe and tools.call in mcpScript accept the server from a search result: tools.describe({ path, server }) and tools.call(path, args, { server }). This makes a tool usable when two servers share its name, as with toolPrefix: "none". Before, describe returned the first server's tool and call failed as ambiguous. The README has a new "Composable tool search" section showing search, filter, describe, and call in one script.
  • With mcpScript on, the output shapes seen from tools are saved in mcp-cache.json, so a later session can script a tool without first calling it to see its fields. Saved shapes hold field names and types only, and are dropped when the tool's description, input schema, or server config changes.
  • When an mcpScript run throws, times out, or returns nothing useful ([], {}, null, "", or no value), the result ends with the output shapes of the tools it called, so a wrong field guess can be fixed without another call.
  • settings.scriptSkill: "model" adds the mcp-scripting skill's path to the mcpScript description so the model reads it before writing a script. The default, "manual", leaves the skill to /skill:mcp-scripting.

Changed

  • /mcp-adapter setup keeps one size as you move through it, groups actions into sections, and shows details beside the list. PgUp/PgDn scroll long details. The Close row is gone; press Esc to close.
  • When a server refuses Pi's OAuth client registration, the error now says what to do: for Figma's remote server, use the desktop app's server through /mcp-adapter setup; for other servers, set oauth.clientId if the provider gave you one. Before, it only said Dynamic Client Registration rejected (HTTP 403): Forbidden.
  • When nothing is listening at a localhost, 127.0.0.1, or [::1] server URL, the error now adds Nothing is listening at <url>. Start the app or local process that serves this MCP server.
  • tools.search in mcpScript now behaves like mcp({ search }). An empty query with a server lists that server's tools, and a search that can't run returns error: { code, message } next to items: [], with the same codes as mcp({ search }), instead of a bare empty result.
  • With mcpScript on, MCP tool results of 8 KiB or more end with a one-line hint to use mcpScript when passing them to another call, so models stop retyping large results by hand.
  • The mcpScript description is shorter and now explains that a tool call's data is the raw MCP result and how to read JSON from it.
  • Output shapes list a wide object that repeats as a named type, so a GitHub-style issue list shape is about 40% shorter with every field still shown.
  • The mcp-scripting skill is about half as long, with jev.evaluate details moved to references/jev.md. It now says to write the real script first, check the first item's fields before a loop that writes, and fix the script from the listed fields when it fails or finds nothing.

Fixed

  • Pi 0.99's built-in MCP extension is detected again. Pi 0.99 renamed it builtin:mcp, so the adapter took over /mcp and warned about mcp.json on every start even though the built-in extension owns that file. Thanks to @Sebastianlopez-dev for reporting it in #736.
  • Installing next to Pi 0.99 no longer prints an npm peer dependency warning. The optional @earendil-works/pi-ai peer range now includes ^0.99.0, and the adapter is tested against Pi 0.99.1. Thanks to @fl4pj4ck for reporting it in #741.
  • MCP servers from a Pi package installed from a git URL with a port or a user other than git, such as ssh://git@gitlab.example.com:2235/acme/tools.git, now load. Before, they were skipped without a warning. Thanks to @shura-v for #746.
  • MCP servers from a Pi package installed at a ref that contains a slash, such as https://gitlab.example.com/acme/tools.git@release/v2, now load.
  • MCP metadata marked private is no longer reused from the cache in a later session, including output shapes saved for mcpScript. It is still used within the session that fetched it. Thanks to @quifox for #743.
  • When a server's tool list changes and saving the refreshed metadata fails, the update is retried instead of lost. Thanks to @quifox for #742.
  • regex: true in mcpScript's tools.search was ignored: scripts got ranked word matches, and an invalid pattern gave no error. It now runs the same checked regex search as mcp({ search }).
  • Models no longer call doubled names such as tracker_tracker_list_issues in mcpScript. The code parameter's example now uses the tool name exactly as mcp lists it: tools.call("github_search_issues", args).
  • When two servers share a tool name, the tools.call examples in observedOutput.target and in the fields listed after a failed or empty script include the server, such as tools.call("echo", args, { server: "other" }), so copying them works. A script that called the shared name on both servers now lists each server's fields, not just the last one's. Closes #751.
  • Output shapes in describe no longer drop nested fields such as labels: { name: string }[] on GitHub-style lists.
  • The mcp tool description mentions mcpScript only when it is available. Before, it pointed to mcpScript even with settings.scriptMode set to false.

Don't miss a new pi-mcp-adapter release

NewReleases is sending notifications on new releases.