Skip to content

feat: manage MCP servers in Settings - #694

Merged
Rinat S (rsolmano) merged 10 commits into
mainfrom
mcp-stack/6-mcp-settings
Oct 13, 2026
Merged

Rinat S (rsolmano) merged 10 commits into
mainfrom
mcp-stack/6-mcp-settings

Conversation

@danyaberezun

@danyaberezun danyaberezun commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

With the host service in place (#692) and the chat's server list (#693), every management step still
means editing mcp.json by hand and having a pi executable, which ThinkRail doesn't ship. That covers
adding a server, approving a repository-defined one, signing in to an OAuth server, turning a server off
for one project, and reading its log.

Approach

  • Settings › MCP servers covers the active workspace's project. It is hidden below
    MCP_PROTOCOL_VERSION.

    • Rows. Each row is derived in the store (deriveMcpServerRows) from the configured entries plus
      every live chat's status. A problem in any chat wins, and the row names the chats reporting it.
    • Row content. A row has a status dot and a reason line, the enable switch, and at most one
      primary and one secondary action. The rest are in a menu: Sign in / Sign out, Test connection,
      Reconnect, Reload now, Open a chat, Show log, Share with repo, Remove.
    • Banner. A repository-defined server is Review & approve: the dialog shows what will run,
      then sends mcp.approve at that exact fingerprint.
  • One write rule.

    • User-level server. It changes for this project only, through mcp.setProjectOverride, and the
      global mcp.json is never written.
    • Repository server. It is rewritten in .pi/mcp.json through mcp.update, which carries the
      rendered fingerprint as expectedFingerprint. A stale row therefore never overwrites or approves
      newer content.
    • No user-level Edit. User-level Edit is disabled and points at the file. The wire carries no raw
      entry, so the edit could not be lossless.
  • Adding a server. There are three ways, and each shows what will run before it writes:

    • Presets. Five pinned ones: Context7, DeepWiki, Linear (read-only), Sentry, and Playwright as a
      disabled user entry with a per-project opt-in.
    • Form.
    • Pasted JSON. GitHub is a recipe for this route, not a preset.

    Settings stores references only. Secrets must be ${VAR} or !command. Credentials in URLs and a
    plain oauth.clientSecret are refused. A !command that is slow to resolve gets a warning, because pi
    resolves it on every connect.

  • Sign-in and Test connection reuse auth/LoginDialog. The login state keeps the push's MCP
    target, so only an MCP sign-in opens this section's dialog, and Providers ignores it.

  • Chat links. The chat's MCP attention marker (sign-in, failure, approval) and the inspector's
    Settings action open this section. Open a chat shares the workbench's startChatInTab.

  • Host skill. managing-mcp-servers tells the agent to edit mcp.json, never run pi mcp …, and
    point the user at this section. The server's own skills/ directory is wired into dev and the
    compiled binary.

Changes

  • New panels (apps/web/src/panels/), each with tests:
    • McpSettings.tsx and McpServerDialogs.tsx: add, approve, details, log, remove;
    • mcpServerView.ts: the status-table view model;
    • mcpEntries.ts: form/JSON parsing and the reference rules;
    • mcpPresets.ts.
  • Store.
    • store/selectMcpServers.ts gains deriveMcpServerRows / McpServerRow.
    • selectChatResourceGroups gains mcpAttentionCount.
    • The transport barrel exports requestMcpList for mutations.
  • Settings dialog. A new section in SettingsDialog.tsx, plus SettingsSection.Mcp, a disabled
    state for ToggleSegment, and the login target in auth/loginState.ts and appStore.
  • Chat. ResourcesAttention in the chat header, and the Settings action on the inspector's MCP
    rows.
  • Open a chat. panels/openChat.ts gains startChatInTab, and shell/WorkspaceWorkbench.tsx
    uses it.
  • Host skill.
    • packages/server/skills/managing-mcp-servers/SKILL.md;
    • the host skills dir in extensions.ts (dev) and buildSupport.ts (binary);
    • apps/cli/SPEC.md.
  • Docs. README and goal-and-requirements.md gain the MCP capability. UI-TERMINOLOGY.md and the
    specs are updated.
  • e2e/mcp-settings.spec.ts:
    • add a user server through the form;
    • Not running → Connected · 2 tools once a chat attaches;
    • disable it for that chat from the inspector, then remove it;
    • a repository server flags the attention marker, waits for Review & approve, and starts once
      approved.

Notes for reviewers:

  • Besides the web app, this PR wires the server's own skills/ directory into dev and the compiled binary for the host
    skill, and the server/contracts specs now name Settings as the client of the probe and approval paths.
  • The workbench's New-chat start moves into panels/openChat.ts (startChatInTab) so Open a chat shares it; behaviour
    is unchanged.
  • The rows derivation (deriveMcpServerRows, the starting-since bound), the attention count and the wide
    requestMcpList arrive here with their first callers.

Screenshots

Captured with the e2e harness's hermetic fixture project, 1440×900 at 2×, dark theme; the same throwaway scenario ran on the base PR's tree (before) and on this PR's tree (after).

Settings sections

Before After
Settings sections, before Settings sections, after

Settings › MCP servers — a connected user server and a repository server awaiting approval (new in this PR)

Settings › MCP servers — a connected user server and a repository server awaiting approval

Add server (presets tier) (new in this PR)

Add server (presets tier)

Review & approve (new in this PR)

Review & approve

Chat header MCP attention marker (new in this PR)

Chat header MCP attention marker

Related issues

No tracked issue. This is part of the MCP support stack (milestone 1); review and merge in order:

  1. feat: upgrade pi to 1.1.0, gate session reloads and teardown, import the login env #689 feat: upgrade pi to 1.1.0, gate session reloads and teardown, import the login env
  2. feat: pass each project's trust to pi and name what trusting it loads #690 feat: pass each project's trust to pi and name what trusting it loads
  3. feat(server): run the MCP servers from mcp.json in chats on pi's built-in engine #691 feat(server): run the MCP servers from mcp.json in chats on pi's built-in engine
  4. feat(server): serve MCP server management, status and sign-in to clients #692 feat(server): serve MCP server management, status and sign-in to clients
  5. feat(web): track MCP status and list each chat's MCP servers in its resources #693 feat(web): track MCP status and list each chat's MCP servers in its resources
  6. feat: manage MCP servers in Settings #694 feat: manage MCP servers in Settings ← this PR
  7. feat(web): render MCP tool calls, resources and tool_search as cards #695 feat(web): render MCP tool calls, resources and tool_search as cards

Base: #693, 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 main at 9d6ad0b2, preserving Extensions Settings/reload integration. MCP uses protocol 83; the extension catalog retains 82. Existing MCP product policy and pi engine ownership are unchanged.

  • Name-only runtime actions target only the effective configured row. Stale approval failures refresh the fingerprint without silently approving changed content.
  • Providers and MCP share one synchronous login-start reservation; removed-workspace dialogs and late frames/responses cannot strand it.
  • Reference recognition agrees with pi for malformed braced fragments. No new compiler bailout is accepted.
  • A saved preset add is no longer reported as failed when project opt-in fails: Add closes, the existing row explains the uncertain enablement, and its switch retries only the project override.

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.

  • Fast gates (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 frontend src tests were rerun successfully; other package inputs were unchanged.
  • Final combined stack (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 clean main 3/8 times; no scroll code/assertion was changed or skipped. The final suite includes the preset opt-in recovery and JSON partial-add regressions.
  • Focused real-Central acceptance → 9 agent/resources/queue/tool-card cases plus 1 disabled-extension case passed; agent + queue rerun after the final retry correction → 2 passed. The complete paid-provider suite was not run.
  • Final CLI compilation (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.
  • Additional review → no remaining local blockers; no suppressions were added. Spec validation retains only two pre-existing dangling task links.

Stack status (2026-10-13): rebased onto main bf4da661 on top of #723 (pi 1.2.0), which fixes the vanilla-pi parity gate broken by the
pi-codemode 1.2.0 release. #723 merges first; this stack then rebases to drop that commit. The branches remain stacked in the original
order 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.md in #695): the public
MCP exports, loader/writer code, shutdown ordering and startup dispatch are unchanged, so nothing is removed. Pi 1.2 widens
structuredContent to any JSON value and stops listing resources on connect (connected · N tools · resources); the status parser now
counts tools in that dotted wording (it previously read 0 for it) and both changes have fixtures.

Testing

  • Final stack on pi 1.2.0 / main bf4da661: fast gates + bun run typecheck 20/20; isolated bun run test 20/20 packages;
    bun run check:pi-packages OK (fresh npm install of pi 1.2.0 under Node 22.19); bun run e2e 551 passed + the known touch-momentum
    flaky (passed on retry); build-binary + smoke:binary passed; focused live agent/queue/chat-resources/tool-cards/subagents
    specs 11 passed; independent review of the upgrade and the new stack commits → no findings.

On this PR's tree:

  • bunx turbo run typecheck --filter='!@thinkrail/desktop' → 19/19
  • bun 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
  • cd apps/web && bun test → 1635 pass
  • bun test ./scripts/ → 91 pass; bunx turbo run test --continue for every other package (desktop excluded) → 17/17 tasks
  • bun run lint → clean, no warnings; check:deps, check:boundaries, check:seams, check:spec-surface → OK
  • bun run e2e → all 8 shards passed (495 tests)
  • bun run build:binary && bun run smoke:binary → smoke OK. The binary carries the host skill

Desktop: @thinkrail/desktop's typecheck could not run as configured on this machine. Its electrobun prepare step waits on a shared cache lock that another process holds. Run without prepare, cd apps/desktop && tsc --noEmit reports the same 18 electrobun-declaration errors (TS7016/TS7006/TS7031) as on origin/main and none from this change. Its bun test passes (123 pass, 1 skip, as on origin/main). This change touches no desktop file.

Checklist

  • Fast gates pass: bun run lint, bun run typecheck, bun run test
  • E2E suite passes for app-affecting changes (bun run e2e, or bun run e2e:full when touching agent behavior)
  • Before/after screenshots are included for frontend changes, or marked not applicable
  • Relevant SPEC.md / top-level specs updated to reflect any boundary, contract, or behavior change
  • I have read the Contributing guide and agree to the Code of Conduct

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/panels/McpSettings.tsx Resolved
@danyaberezun
danyaberezun force-pushed the mcp-stack/6-mcp-settings branch from cbf815f to 1281754 Compare October 9, 2026 10:51

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@danyaberezun
danyaberezun force-pushed the mcp-stack/6-mcp-settings branch from 1281754 to 312f5db Compare October 9, 2026 11:08

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline finding.

Comment thread apps/web/src/panels/McpSettings.tsx Resolved
Comment thread apps/web/src/panels/mcpServerView.ts Resolved
@danyaberezun
danyaberezun force-pushed the mcp-stack/6-mcp-settings branch from 312f5db to 53335e1 Compare October 9, 2026 11:25

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/panels/McpSettings.tsx Resolved
@danyaberezun
danyaberezun force-pushed the mcp-stack/6-mcp-settings branch from 53335e1 to 7ac5ef1 Compare October 9, 2026 11:43

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/panels/mcpEntries.ts Resolved
@danyaberezun
danyaberezun force-pushed the mcp-stack/6-mcp-settings branch from 7ac5ef1 to e95a7ee Compare October 9, 2026 11:52

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline finding.

Comment thread apps/web/src/panels/McpSettings.tsx Resolved

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/panels/mcpEntries.ts Resolved

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline finding.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Comment thread apps/web/src/store/appStore.ts Resolved

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

Base automatically changed from mcp-stack/5-web-mcp-state to main October 13, 2026 13:48
danyaberezun and others added 10 commits October 13, 2026 15:48
- Settings › MCP servers: per-workspace rows from configuration plus every
  live chat's status, with approve, enable, exposure, sign in, test,
  reconnect, reload, open a chat, show log, share with repo and remove.
- Add from five pinned presets, a form or pasted JSON; references only for
  secrets; repository writes carry the rendered fingerprint.
- The chat's attention marker and resource rows link to the section.
- A managing-mcp-servers host skill tells the agent to edit mcp.json.
Settings kept the cached project-scope rows actionable until the mcp.list
refresh landed; they are now filtered client-side while the project is
untrusted. The MCP settings e2e waits for the auto-opened persisted chat
before adding a server instead of racing it.
An open Edit, Review & approve or project-scope Remove dialog closes, and
an open Add dialog falls back to User scope, so a stale dialog cannot act
on repository entries Settings no longer lists.
… fingerprint, drop stale repository flows on revoke

A user-server toggle sends just the changed field so two clients cannot
overwrite each other's setting; a project-scope Remove carries the rendered
fingerprint; a trust revoke also resets a project-scope Add review step and
ignores an Edit/Review read that was still in flight.
…this workspace's MCP sign-in

Edit and Remove build their target through mcpRenderedTarget, matching the
host's McpRenderedTarget contract; the MCP login dialog mounts only for a
sign-in started in the workspace Settings is showing.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@rsolmano
Rinat S (rsolmano) added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit e5eeebf Oct 13, 2026
17 checks passed
@rsolmano
Rinat S (rsolmano) deleted the mcp-stack/6-mcp-settings branch October 13, 2026 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants