Repository navigation
feat(server): serve MCP server management, status and sign-in to clients - #692
Merged
Merged
Conversation
This was referenced Oct 9, 2026
danyaberezun
force-pushed
the
mcp-stack/4-mcp-host-service
branch
from
October 9, 2026 06:58
a1aa6a2 to
4d60ef1
Compare
danyaberezun
added this pull request to stack #696
October 9, 2026 07:52
danyaberezun
marked this pull request as ready for review
October 9, 2026 08:00
danyaberezun
requested review from
Olga Lavrichenko (OLavrik),
Rustam Sadykov (SBOne-Kenobi) and
Rinat S (rsolmano)
as code owners
October 9, 2026 08:00
danyaberezun
force-pushed
the
mcp-stack/4-mcp-host-service
branch
2 times, most recently
from
October 9, 2026 10:35
4d60ef1 to
4684896
Compare
danyaberezun
force-pushed
the
mcp-stack/4-mcp-host-service
branch
from
October 9, 2026 12:12
4eb561a to
5d061df
Compare
danyaberezun
force-pushed
the
mcp-stack/4-mcp-host-service
branch
from
October 9, 2026 12:24
5d061df to
c92b2cf
Compare
Rinat S (rsolmano)
force-pushed
the
mcp-stack/4-mcp-host-service
branch
from
October 13, 2026 11:56
aeb9718 to
4c06c9d
Compare
- Protocol v79: mcp.* methods, the mcp.status channel and SessionResources.mcpServers. - Per-session status is pi's own /mcp report, captured by dispatch and redacted, with a starting snapshot until pi answers. - Atomic, containment-checked config writers; updates carry the rendered fingerprint so no write approves repository content as a side effect. - Only chats whose effective MCP config changed reload, through the gate; the user mcp.json and .pi/ changes are watched. - Sign-in and Test connection run in a host probe session, owner-only, sharing one per-server lock with chats' /mcp login. - mcp.readOutput and mcp.readLog; an MCP probe in the artifact harness.
…server is gone An override-only .pi/mcp.json entry with no user-level definition behind it is invalid, so shareMcpOverrideWithRepo re-reads the user config first and leaves the record and the repository file untouched.
…ledElsewhere Every mutation (add, update, remove, setProjectOverride, approve, shareWithRepo) re-checks MCP ownership right before writing and fails with MCP_HANDLED_ELSEWHERE, matching the read-only contract of that state.
…CP entries approve, shareWithRepo and project-scope add/update/remove now fail with MCP_CONFIG_INVALID for an untrusted project, whose repository entries are not listed, so a dialog left open across a trust revoke cannot write them.
…rge project overrides mcp.remove takes the same expectedFingerprint precondition as mcp.update for project scope, and mcp.setProjectOverride merges the fields it carries into the existing override instead of replacing it.
… for repository writes, probe the effective server mcp.add/update/remove reject any scope but user/project before choosing a path; a project-scope update or remove must carry the fingerprint the row was rendered with (McpRenderedTarget); Test connection judges the name's effective server; a server named __proto__ is written as an own property.
…check and write one synchronous step A configured description now passes redactMcpText like every other text leaving the host; a project-scope update or remove compares the fingerprint and writes after its last await, so two requests rendered from the same entry cannot both pass and both write.
mcpHandledElsewhereBy reads the live /mcp owners after its only await, so a management mutation's synchronous write sees the current ownership.
…ement write mcpOwnershipGuard resolves pi settings, then answers synchronously from the live /mcp owners; mutateManaged runs that check and the mutation together, so a reload handing /mcp to another extension cannot slip between them.
… check and keep __proto__ out of the record's prototype mcp.login / mcp.testConnection sample the live /mcp owners right before the probe starts; project MCP approvals and overrides are read through null-prototype copies and written as own properties.
A stdio server's stderr tail reaches mcp.status verbatim from pi, so redactMcpText now masks credential-named 'key: value' pairs too, keeping a Bearer/Basic scheme and plain server status lines intact.
…ify against pi 1.2.0
Rinat S (rsolmano)
force-pushed
the
mcp-stack/4-mcp-host-service
branch
from
October 13, 2026 12:57
4c06c9d to
7d5abb2
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.
Problem
#691 runs MCP servers in chats, but the host keeps everything to itself. A client can't:
Edits made to
mcp.jsonoutside the app only take effect when a chat reloads for another reason.Approach
MCP_PROTOCOL_VERSION). All methods are workspace-scoped. The browser neverexecutes anything.
mcp.list,mcp.add/mcp.update/mcp.remove,mcp.setProjectOverride,mcp.setSessionOverride,mcp.approve,mcp.shareWithRepo,mcp.login/mcp.logout/mcp.testConnection,mcp.reconnect,mcp.readOutput,mcp.readLog.mcp.statuschannel.SessionResources.mcpServers.MCP_CONFIG_INVALID,MCP_PATH_UNSAFE,MCP_HANDLED_ELSEWHERE,LOGIN_NOT_OWNER./mcpreport. pi has no structured status API./mcpwith a command context whoseui.notifyalone reports to the capture. That dispatch's text never reaches the chat, and the user's own
/mcpalways prints there.
status.
starting: from registration, andagain after every gated reload.
leave the host.
/mcp, or-builtin:mcpis set (resolvedwithout a chat open),
mcp.listreportshandledElsewhere.symlinked
.pi/paths.mcp.updatecarriesexpectedFingerprint. Approval carries over only from an entry that wasalready approved, so a write never approves repository content as a side effect.
mcp.shareWithReporefuses to merge into unreviewed repository content.change under
.pi/, and eachagent_settled.pending-reloaduntil its reload runs.registered.
or loopback, and a paste-back is accepted only from that client.
/mcp login|logout <name>share one per-server sign-in lock.redactMcpText,maskMcpEndpoint) covers status details, configerrors, logs and probe errors. pi reports connection errors and stderr tails verbatim.
mcp.readOutputserves only a result's recorded full-output file, with anexpiredstate.
mcp.readLogreturns a server's last lines from pi's sharedmcp.log(+.1).Changes
domain.ts/wsProtocol.ts(+ the v80 pin), plus a contracts SPEC section.
packages/server/src/agent/mcp/(tests alongside or through the host/sign-in tests):status.ts,summaries.ts,redact.ts,log.ts;writers.ts,management.ts;signInLock.ts, plus the lock proxy inengine.ts;fixtures/oauthServer.ts.packages/server/src/agent/:mcpSessions.ts: status, reconciliation, watcher, listing, read output;mcpSignIn.ts: probes;interceptExtUiNotifyinwebUiContext.ts;mcpServersinchatResources.ts;isBuiltinExtensionEnabledinextensions.ts.agentSessionManager.ts:mcpSessionView/liveSessionIdsOf,dispatchSessionMcpCommand,setSessionMcpServerEnabled;approveProjectMcpServerandsetProjectMcpOverride.host/mcp.ts(+ tests): the handlers.provider.loginReply/provider.loginCancel.server.tswiring: the status channel, publishers, the watcher, client-reap cancellation, and the.pi/change reconcile.packages/artifact-testschecks the compiled binary: it connects a stdiofixture (
connected, 1 tool) and reports an OAuth fixture asneeds-sign-in.e2e/chat-resources-wire.spec.tsexpects the newmcpServerslist.Notes for reviewers:
"settings"and the chat message "A sign-in for "" is already running in Settings." arefinal wording for feat: manage MCP servers in Settings #694's Settings section; until then only a wire client can start a probe, so neither is reachable
from the app. The specs describe it as the host's sign-in probe.
status, turns it into status only.
management.ts,signInLock.tsandwriters.tsare tested throughhost/mcp.test.ts,mcpSignIn.test.tsandconfig.test.ts.Screenshots
Not applicable: no frontend changes. The web app adopts this wire in #693–#695.
Related issues
No tracked issue. This is part of the MCP support stack (milestone 1); review and merge in order:
Base: #691, so this diff shows only this layer. The branches remain stacked for merge order; checks on the current head are listed by GitHub.
Review hardening (2026-10-12)
Rebased onto
mainat9d6ad0b2, preserving Extensions Settings/reload integration. MCP uses protocol 83; the extension catalog retains 82. Existing MCP product policy and pi engine ownership are unchanged.effectiveauthority and retain folded configuration errors. OAuth URLs use pi’s public callback; sign-in aliases share the credential lock.Latest verification
These results supersede the earlier counts/environment limitations below. The latest combined stack tree was compared byte-for-byte with the locally verified canonical tree; each restacked layer also received focused tests and server/web typechecks.
check:deps, boundaries, seams, spec-surface, compiler, lint) and typecheck → green; all 20 packages, including desktop. Compiler baseline was not relaxed.bun run test, with isolated HOME/data/agent directories and no ambient provider credentials → all 20 package tasks plus root scripts passed. After the last UI-only preset correction, all 1,831 frontendsrctests were rerun successfully; other package inputs were unchanged.2451693b) complete no-agent browser suite → 552 passed, all four isolated shards, using the repository’s standard CI retry configuration. Earlier local repeats exposed the unchanged touch-momentum flake, reproduced on cleanmain3/8 times; no scroll code/assertion was changed or skipped. The final suite includes the preset opt-in recovery and JSON partial-add regressions.bun apps/cli/scripts/build-binary.ts) +bun run smoke:binary→ passed, including the shared MCP artifact probe; vanilla-pi package parity passed under Node 22.19.0.Stack status (2026-10-13): rebased onto
mainbf4da661on top of #723 (pi 1.2.0), which fixes the vanilla-pi parity gate broken by thepi-codemode1.2.0 release. #723 merges first; this stack then rebases to drop that commit. The branches remain stacked in the originalorder and merge one at a time through the merge queue.
Pi 1.2.0 (2026-10-13)
Every pi adaptation in this layer was re-checked against the installed 1.2.0 package (see
pi-compatibility.mdin #695): the publicMCP exports, loader/writer code, shutdown ordering and startup dispatch are unchanged, so nothing is removed. Pi 1.2 widens
structuredContentto any JSON value and stops listing resources on connect (connected · N tools · resources); the status parser nowcounts tools in that dotted wording (it previously read 0 for it) and both changes have fixtures.
Testing
bf4da661: fast gates +bun run typecheck20/20; isolatedbun run test20/20 packages;bun run check:pi-packagesOK (fresh npm install of pi 1.2.0 under Node 22.19);bun run e2e551 passed + the known touch-momentumflaky (passed on retry);
build-binary+smoke:binarypassed; focused liveagent/queue/chat-resources/tool-cards/subagentsspecs 11 passed; independent review of the upgrade and the new stack commits → no findings.
mcp.addand sharing an override now refuse a name that is already occupied in the target file by any value, including a malformedscalar/array/null entry a stale client never saw; previously the add overwrote it and auto-approved the replacement (review
feat(server): serve MCP server management, status and sign-in to clients #692 (comment)).
On this PR's tree:
bunx turbo run typecheck --filter='!@thinkrail/desktop'→ 19/19bun test packages/server packages/pi-delegation packages/pi-subagents packages/pi-background-commands packages/pi-todos packages/pi-dag packages/pi-thinkrail-workflow packages/contracts packages/shared packages/artifact-tests→ 2001 pass, 10 skip, 0 fail. The first run hit the knownjbcentralflake "falls back to a plain runtime…"; its file passed 25/25 on rerun, and so did the full reruncd apps/web && bun test→ 1580 passbun test ./scripts/→ 91 pass;bunx turbo run test --continuefor every other package (desktop excluded) → 17/17 tasksbun run lint→ clean, no warnings;check:deps,check:boundaries,check:seams,check:spec-surface→ OKbun run e2e→ all 8 shards passed. The first run hit the knownlayout.spec.ts:1061flake;e2e/layout.spec.tspassed 30/30 on rerunbun run build:binary && bun run smoke:binary→ smoke OK, including the MCP artifact probeNo live spec drives an MCP server, and the complete
bun run e2e:fullsuite was not run; the session-level MCP behaviour is covered bymcpEngine.test.tsandmcpSignIn.test.tsagainst pi's real engine and stdio/OAuth fixtures.The complete
bun run e2e:fullsuite ran on the top of the stack (#695), which contains this change: no-agent 8/8 shards; agent 53 passed, 2 failed —error-turn.live.spec.ts:35andvisualize.live.spec.ts:62, which fail onorigin/maintoo.Desktop:
@thinkrail/desktop's typecheck could not run as configured on this machine. Itselectrobun preparestep waits on a shared cache lock that another process holds. Run withoutprepare,cd apps/desktop && tsc --noEmitreports the same 18 electrobun-declaration errors (TS7016/TS7006/TS7031) as onorigin/mainand none from this change. Itsbun testpasses (123 pass, 1 skip, as onorigin/main). This change touches no desktop file.Checklist
bun run lint,bun run typecheck,bun run testbun run e2e, orbun run e2e:fullwhen touching agent behavior)SPEC.md/ top-level specs updated to reflect any boundary, contract, or behavior change