Repository navigation
feat(adapters)!: Pi connects through its native MCP client - #121
Merged
Merged
Conversation
Pi has shipped a native MCP client since 0.99. It reads .pi/mcp.json from the directory it runs in, only for a trusted project, and ignores a root .mcp.json, so the config SharedOS wrote was never read. The shape was also the one pi-mcp-adapter takes, which Pi rejects. piMcpConfig now emits Pi's own shape: url, the bearer token in headers.Authorization, timeout in seconds when the host set one, and direct exposure so each tool reaches the model as mcp__<server>__<tool>. harnessMcpConfigFile names it .pi/mcp.json, the runtime makes a config file's directory before writing it, and the Pi launch passes --approve so Pi trusts the file written for the turn. The vendor manifest stamps mcpSupport native, and the MCP conformance script records an extension only when the host configuration declares one.
Pi 0.99 and later need no extension. The docs now say where Pi reads the per-turn .pi/mcp.json, why the launch passes --approve and what else that trusts, how Pi names the catalogue's tools, and that the startup wait for direct servers is Pi's own. ADR 0014 gets a dated note rather than a rewrite. The systems-cost text and its renderer no longer name Pi's extension as the proxy example.
Pi expands $NAME and ${NAME} in a header value and reads $$ as one
dollar sign, so a host-chosen token with a dollar sign in it reached the
bridge rewritten and was refused. piMcpConfig now doubles each one. The
harnessToolAlias comment says Pi also rewrites the server part of a tool
name, which the alias does not, and a test comment gives the right reason
Pi skips an auth key.
The stand-in harness now sends the headers its config names, read the way Pi reads them, and keeps each response's HTTP status. New tests: a token with dollar signs reaches a bridge that wants it, a wrong or missing header is refused and the turn sees no catalogue, a turn file named .pi/mcp.json is refused before launch, and the Pi manifest says mcpSupport native.
A host configuration that gave mcpExtensionVersion without mcpExtension had the version dropped and the column stamped native, which says the opposite of what was declared. The script now stops before probing.
The toolshare page claimed no flag keeps Pi to the catalogue for one run. --tools 'mcp__<server>__*' does, and a host appends it through args; SharedOS does not pass it, so the model also sees the tools of servers in Pi's own mcp.json and Pi's codemode tool unless the host restricts them. A new section states what --approve trusts in Pi's own words, and advises fixed turn-file names and a workspaceRoot with no .agents/skills above it. The CHANGELOG lists what a host updates for Pi's native client.
PI_MCP_HARNESS no longer passes --no-builtin-tools, so the launch is --mode rpc --no-session --approve. SharedOS decides the calls that reach it over MCP and restricts none of a harness's own tools, as on feat/harness-any-version. Pi keeps read, bash, edit and write, and a host may narrow them through args with --tools. The MCP conformance script declares those four as Pi's harnessLocal, the docs and the CHANGELOG say Pi keeps its own tools, and the launch test asserts the new arguments.
SharedOS sets only what it takes to run the CLI, connect it to the bridge and let the bridge's tools run, so PI_MCP_HARNESS no longer passes --no-session and its launch is --mode rpc --approve. Pi keeps its own session records, as it would for any user, under ~/.pi/agent/sessions/ by default; a host that does not want them appends --no-session through args. The live Pi column in native-conformance.mjs drops the flag too. The spec comment, the launch test, the toolshare docs and the CHANGELOG Pi entry say so.
DaXu999
force-pushed
the
feat/pi-native-mcp
branch
from
November 9, 2026 19:41
747996b to
6c631cc
Compare
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.
Why
Pi has shipped its own MCP client since 0.99. The Pi column still connected through
pi-mcp-adapter, an extension that registers onemcpproxy tool, hides the catalogue behind it and replaces Pi's client when loaded. The host image pinned Pi 0.84 to keep that working. Pi's own client reads a different file in a different place, so the adapter's config was rejected outright on current Pi.What
harnessMcpConfigFile("pi")returns.pi/mcp.json(was.mcp.json).piMcpConfigwritesurl, the bearer token as anAuthorizationheader with every$doubled so Pi reads it literally,timeoutin seconds only when the host sets one, andexposure: "direct"so each tool is a tool of its own namedmcp__<server>__<tool>. The runtime makes a generated file's directory before writing it.--mode rpc --approve.--approveis what lets Pi read.pi/mcp.jsonfrom the scratch workspace; the docs state plainly what else it trusts.--no-builtin-toolsand--no-sessionare gone: Pi keepsread,bash,editandwriteand its own session records, and a host narrows either throughargswith--toolsor--no-session.mcpSupport: "native"andmcpExtensionis gone.scripts/mcp-conformance.mjsstamps the Pi columnnative, declares the four built-ins asharnessLocal, and stops onmcpExtensionVersionwithoutmcpExtension.--approvetrusts and the$escaping; ADR 0014 gains a dated note; CHANGELOG entry under Unreleased.19 files: 579 lines added, 212 removed. Of those, regenerated
docs/apiis 79 added and 71 removed, and tests are 225 added and 18 removed.What a host has to update
pi-mcp-adapter: an extension that replaces Pi's client stops Pi reading anymcp.json.mcpare wrong now; the tools aremcp__sharedos__<tool>..pi/first and doubles$in the header.--no-session.Related
Sibling of #123 (the harness branch, which owns every non-Pi change) and #122 (the limit notice). This branch owns every Pi change. It is rebased onto
mainafter both, with one docs commit for the Pi rows the harness branch wrote, and the checks below ran on the rebased head.Checks
pnpm checkis green on the rebased head: format, typecheck, vitest 1254, test:release 7/7,docs:api:checkandconformance:check.HOMEand a local fake model endpoint: the turn completes,files.readreaches the bridge with the token, a wrong or missing header is refused, and the session file appears where the docs say.