Retire mcp-loader.ts in favour of pi's built-in MCP support

pi has had MCP as a built-in extension (builtin:mcp) since 0.99.0. It reads
~/.pi/agent/mcp.json and adds `pi mcp add|list|login`, a /mcp manager,
OAuth, per-tool exposure and resources. An extension that registers /mcp
REPLACES the built-in, so with mcp-loader installed pi never read mcp.json
and printed "registers command /mcp, so built-in extension mcp was not
loaded" on every start.

Measured on pi 1.1.0 (pi-devbox v1.11.0, tor-ms22) before removing it:
- time to the (auto) footer in a real pty, 7 interleaved runs each:
  -ne 0.276 s | -ne -e mcp-loader.ts 0.283 s | -ne -e builtin:mcp 0.272 s
- with no servers, the same prompt costs 79 input + 7680 cached tokens with
  the loader, the built-in, or neither
- a stdio server (server-everything) connected via `pi mcp list` in 3 s,
  and its echo tool ran end to end from `pi -p` with direct exposure
- no device in the fleet had an `mcp` block, so nothing needs migrating

install.sh now prunes links into this repo whose target is gone (.ts and
.ts.off), so the stale mcp-loader.ts link on a preserved pi-devbox volume is
removed on the first boot of an image without the file. It also warns once
if settings.json still carries an `mcp` block. Tested two-sided in a temp
HOME: the new script removes the repo link and a stale .ts.off, and keeps a
foreign dangling link and a real file. The old script leaves the dangling
link. Re-runs are idempotent, and there is no warning without an mcp block.

mempalace.ts (mempalace-toolkit) is unaffected: it registers mempalace_*
tools itself. Its vendored RemoteMcpClient loses its sync partner; that is
handled in mempalace-toolkit.
This commit is contained in:
2026-10-13 00:15:57 +02:00
parent a88fa99d39
commit 750b2a89c8
5 changed files with 100 additions and 988 deletions
+38
View File
@@ -120,6 +120,41 @@ build_install_set() {
fi
}
# ── stale links ──────────────────────────────────────
# An extension removed from this repo leaves its symlink behind in
# ~/.pi/agent/extensions/ — on a pi-devbox volume that link survives every
# recreate, pointing into an image that no longer has the file. Remove links
# that point into THIS repo and whose target is gone (.ts and the /ext-disabled
# .ts.off alike). Links into other repos and real files are never touched.
prune_stale_links() {
local dest pattern
for pattern in "*.ts" "*.ts.off"; do
for dest in "${EXTENSIONS_DEST}"/$pattern; do
[[ -L "$dest" ]] || continue
[[ -e "$dest" ]] && continue # target still exists
link_into_repo "$dest" || continue # someone else's link
rm "$dest"
ok "Removed stale $(basename "$dest") (no longer in this repo)"
done
done
}
# mcp-loader.ts was retired in favour of pi's built-in MCP support. Its config
# lived in settings.json under a top-level `mcp` key, which pi ignores; say so
# once instead of letting those servers disappear silently.
warn_retired_mcp_block() {
local settings="${PI_AGENT_DIR}/settings.json" has=""
[[ -f "$settings" ]] || return 0
if command -v jq >/dev/null 2>&1; then
has=$(jq -r 'if type == "object" and has("mcp") then "yes" else "" end' "$settings" 2>/dev/null || true)
elif command -v python3 >/dev/null 2>&1; then
has=$(python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print("yes" if isinstance(d, dict) and "mcp" in d else "")' "$settings" 2>/dev/null || true)
fi
[[ "$has" == "yes" ]] || return 0
warn "${settings} has an 'mcp' block, but mcp-loader.ts is retired and pi ignores it."
warn " Move those servers to ~/.pi/agent/mcp.json (pi's built-in MCP; see README 'MCP servers')."
}
# ── install ──────────────────────────────────────────
do_install() {
echo
@@ -128,6 +163,7 @@ do_install() {
echo
require_pi_installed
warn_retired_mcp_block
build_install_set
if [[ -z "$INSTALL_SET" ]]; then
@@ -143,6 +179,8 @@ do_install() {
confirm || { echo "Aborted."; exit 0; }
echo
prune_stale_links
for src in "${EXTENSIONS_SRC}"/*.ts; do
[[ -e "$src" ]] || continue
local name