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 setupoffers 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
mcpScripton, 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 setupoffers it when the app is installed and tells you how to turn its server on. /mcp-adapter setupis 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.
mcpScriptis 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
mcpScriptis off by default. To keep using it, setsettings.scriptModetotrueinmcp-adapter.json. Its bundled skill, the pointer to it in themcptool description, and the large-result hint (see Changed) follow the same setting.tools.describeinmcpScriptnow looks tools up the same way asmcp({ describe }). Where it used to return the first server's match, it can now returnerror: { code, message }:ambiguous_toolwhen equally good matches exist on more than one server, andserver_disabledorserver_backoffwhen 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 theserverfrom the search result when the target matters:tools.describe({ path, server }).observedOutput.targetfromtools.describeis now the full expression that reads the JSON, such as(await tools.call("github_list_issues", args)).data.structuredContent, instead ofdata.structuredContent. Models misread the short form.observedOutputno longer hascalls, anddescribeno 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:v1on Pi's event bus. The call goes through the same tool lookup and approval asmcp({ tool }), andrequest.resultresolves to{ ok: true, result }or{ ok: false, error }. Thanks to @Djarid for PR #735. /mcp-adapter setupoffers Figma (desktop) when the Figma app is installed. It adds the app's local server athttp://127.0.0.1:3845/mcpand, 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.describeandtools.callinmcpScriptaccept theserverfrom a search result:tools.describe({ path, server })andtools.call(path, args, { server }). This makes a tool usable when two servers share its name, as withtoolPrefix: "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
mcpScripton, the output shapes seen from tools are saved inmcp-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
mcpScriptrun 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 themcp-scriptingskill's path to themcpScriptdescription so the model reads it before writing a script. The default,"manual", leaves the skill to/skill:mcp-scripting.
Changed
/mcp-adapter setupkeeps one size as you move through it, groups actions into sections, and shows details beside the list. PgUp/PgDn scroll long details. TheCloserow 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, setoauth.clientIdif the provider gave you one. Before, it only saidDynamic Client Registration rejected (HTTP 403): Forbidden. - When nothing is listening at a
localhost,127.0.0.1, or[::1]server URL, the error now addsNothing is listening at <url>. Start the app or local process that serves this MCP server. tools.searchinmcpScriptnow behaves likemcp({ search }). An empty query with aserverlists that server's tools, and a search that can't run returnserror: { code, message }next toitems: [], with the same codes asmcp({ search }), instead of a bare empty result.- With
mcpScripton, MCP tool results of 8 KiB or more end with a one-line hint to usemcpScriptwhen passing them to another call, so models stop retyping large results by hand. - The
mcpScriptdescription is shorter and now explains that a tool call'sdatais 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-scriptingskill is about half as long, withjev.evaluatedetails moved toreferences/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/mcpand warned aboutmcp.jsonon 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-aipeer 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 asssh://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
privateis no longer reused from the cache in a later session, including output shapes saved formcpScript. 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: trueinmcpScript'stools.searchwas ignored: scripts got ranked word matches, and an invalid pattern gave no error. It now runs the same checked regex search asmcp({ search }).- Models no longer call doubled names such as
tracker_tracker_list_issuesinmcpScript. Thecodeparameter's example now uses the tool name exactly asmcplists it:tools.call("github_search_issues", args). - When two servers share a tool name, the
tools.callexamples inobservedOutput.targetand in the fields listed after a failed or empty script include the server, such astools.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
describeno longer drop nested fields such aslabels: { name: string }[]on GitHub-style lists. - The
mcptool description mentionsmcpScriptonly when it is available. Before, it pointed tomcpScripteven withsettings.scriptModeset tofalse.