Skip to content

feat(agent-applications): manage MCP connections in the agent builder#2929

Open
benjackwhite wants to merge 15 commits into
mainfrom
ben/agent-mcp-connections
Open

feat(agent-applications): manage MCP connections in the agent builder#2929
benjackwhite wants to merge 15 commits into
mainfrom
ben/agent-mcp-connections

Conversation

@benjackwhite

@benjackwhite benjackwhite commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Builder UI for the agent-level shared MCP connection feature. Pairs with the runtime in PostHog/posthog#66007 (spec.mcps[].connection). An owner connects a remote MCP server once via PostHog Code's native mcp_store flow, attaches it to an agent, and every asker uses that one shared credential.

What you can do

  • Add an MCP to an agent from a connected server, or connect a new one via a popout modal (AddCustomServerDialog, shared with the agent-builder connect_mcp punch-out — native OAuth/DCR or api-key flow).
  • Pick the connection for an MCP entry, edit its per-tool requires_approval toggles, and remove an MCP entry (drops the mcps[] ref; the shared installation is untouched).
  • All edits persist via draft-branch-then-PATCH (a fresh draft is branched off a non-draft revision, then selected).

Changes

  • mcp-server-manager/ (new shared module): useMcpConnect (installations query + connect/reauthorize over the host OAuth callback) and the moved AddCustomServerForm. The standalone MCP-servers scene now consumes the shared mcpKeys/createOAuthCallback (no behaviour change — core mcp-servers tests still green).
  • agent-applications: editable McpsOverview (add-from-connection + connect-new) and McpBody (connection picker, tool-permission toggles, remove-server).
  • Legacy integrations removed (deliberate). This PR drops the integrations config section (IntegrationsOverview/IntegrationBody, the cfg:integrations node, SECTION_INFO entry) and the AgentSpec.integrations?: string[] field in packages/shared — a total removal, not a soft UI-only regression. Nothing reads the field and the agent-platform schema already dropped it; team-OAuth use cases are served by mcps[].connection / identity_providers[]. (Closes @dmarticus's review note.)
  • Editing foundation, built on main: api-client.updateAgentRevisionSpec + useApplyAgentSpec (+ test). Intentionally ported compatible with the in-flight agent-model-policy-ui branch so the two reconcile cleanly on merge.
  • Drive-by: cast spec.entrypoint in ModelBody — fixes a pre-existing @posthog/ui typecheck error (AgentSpec's [key: string]: unknown index signature), unrelated to this change but blocking a clean typecheck.

Validation

@posthog/api-client + @posthog/ui typecheck clean (full pnpm typecheck green via pre-commit); biome clean; core mcp-servers suite (41) + new useApplyAgentSpec suite (5) pass.

Notes / follow-ups

  • Base branch: targets main (the ben/agent-supported-client-tools base PR was merged; this branch absorbed master and reconciled the supported_client_tools producer, keeping the connect_mcp client tool).
  • Overlaps the agent-model-policy-ui editing work (ported compatibly).
  • Component-level tests for the new MCP panels are a follow-up (hooks/logic are covered).

⚠️ Outstanding / known gaps before this is production-good

UI add/edit/remove was driven against the live app and works. Remaining concerns:

  1. Connected but no tools selected. Add-from-connection creates an mcps[] entry with 0 tools, and McpBody only shows/edits already-selected tools (approval toggles). There's no picker to choose which of the connected server's tools to expose, so the agent can call nothing until tools are added another way. Highest-impact UX gap.
  2. needs_reauth not surfaced. The connectionMissing hint only covers "connection isn't in this project". There's no UI for an expired/revoked shared connection (the runtime returns needs_reauth; see feat(agent-platform): agent-level shared MCP connections (runner + spec) posthog#66007 gap chore: set up biome and ci #3–4) — the owner gets no prompt to reconnect.
  3. Stale-spec agents can't be edited. Example agents seeded with an older models (plural) spec shape fail the write schema ('model' is a required property), so any MCP edit 400s. Re-seed to refresh. Pre-existing data issue, not introduced here, but users will hit it on old agents.
  4. Runtime is unproven end-to-end — see the matching section in feat(agent-platform): agent-level shared MCP connections (runner + spec) posthog#66007. The UI can attach a connection, but it hasn't been observed driving a real agent→MCP tool call.

Agent context

Authored from a Claude Code session (Opus 4.8).

🤖 Generated with Claude Code

Lets an owner attach a shared MCP connection to an agent and edit its
per-tool permissions, reusing PostHog Code's native mcp_store connect flow.
Pairs with the runtime in posthog#66007 (spec.mcps[].connection).

- mcp-server-manager: new shared module — useMcpConnect (installations query +
  connect/reauthorize over the host OAuth callback) + the moved AddCustomServerForm.
  mcp-servers' useMcpServers now consumes the shared mcpKeys/createOAuthCallback.
- agent-applications: editable McpsOverview (add an MCP from a connection, or
  connect a new server inline) + McpBody (connection picker, per-tool
  requires_approval toggles), persisted via useApplyAgentSpec.
- foundation (built on main): api-client updateAgentRevisionSpec + useApplyAgentSpec
  (+ test) — draft-branch-on-save then PATCH. Compatible with the in-flight
  agent-model-policy-ui branch so they merge cleanly.
- drive-by: cast spec.entrypoint in ModelBody to fix a pre-existing @posthog/ui
  typecheck error (AgentSpec index signature) unrelated to this change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

React Doctor found 3 issues in 3 files · 3 warnings.

3 warnings

src/features/agent-applications/agent-builder/AgentBuilderDock.tsx

src/features/agent-applications/components/AgentConfigurationPane.tsx

src/features/mcp-server-manager/AddCustomServerForm.tsx

Reviewed by React Doctor for commit c6fa424.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat(agent-applications): manage MCP con..." | Re-trigger Greptile

benjackwhite and others added 8 commits June 25, 2026 14:16
- useApplyAgentSpec: invalidate the revision detail via a new
  agentApplicationsKeys.revisionPrefix() instead of a hardcoded key array, so
  the centralised key registry stays the single source of truth.
- McpBody: destructure the ctx fields the apply() callback reads (revisionId,
  revisionState, onSelectRevision) into its dep array; ctx is a fresh object
  literal each render, so depending on it defeated the useCallback memoization.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dock

The Edit-with-AI meta-agent's connect_mcp client tool parks the turn and renders
a PREFILLED AddCustomServerForm in the dock; the user completes the OAuth/api-key
connect themselves (auth never reaches the agent). On success the new mcp_store
connection is attached to the target agent's draft spec (mcps[].connection) and
the session is woken with { connected, connection_id, mcp_id }. Mirrors the
set_secret punch-out.

- agentBuilderStore: pendingMcpConnect state + setter
- useAgentBuilderClientTools: connect_mcp handler (parks + defers)
- AgentBuilderDock: connect form rendering + connect -> attach-to-spec -> resolve
- AddCustomServerForm: initialValues prop for prefill
- useMcpConnect: connectCustomAsync + refetchInstallations

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… legacy integrations

- buildTree renders the authorable folder sections (triggers, secrets, skills,
  tools, mcps, identities) even when empty, so the add/connect affordance is
  reachable on a fresh agent (you couldn't add an MCP to an agent that had none).
- Remove the deprecated integrations UI from the config pane (tree section,
  overview/body, routing, description, the legacy mcps[].auth.integration row,
  now-unused LinkIcon). Removing integrations from the agent-platform spec +
  runtime is a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agent-builder dock now sends the kind:'client' tool ids it can execute
(AGENT_BUILDER_CLIENT_TOOLS — set_secret, connect_mcp, focus_*, toast,
get_context) in the /run body so the runner knows it can punch out the
interactive connect_mcp form here instead of relaying a URL. Threaded
AGENT_BUILDER_CLIENT_TOOLS → useAgentChat (supportedClientTools option) →
AgentChatSession → agentChatService → runAgentSession (api-client) → POST /run
body. Replaces relying on the never-sent x-posthog-client header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The inline punch-out crammed the full AddCustomServerForm into the dock's narrow
above-composer strip — ugly. Move connect_mcp to a proper Dialog
(AgentBuilderMcpConnectDialog); the set_secret one-line punch-out stays inline.
Adds a hideHeader prop to AddCustomServerForm so the dialog owns the title/close
chrome (no in-form Back button / duplicate heading).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Producer counterpart to the agent-platform server change that gates
client-tool exposure on a per-run capability list. The agent-builder dock now
declares the `kind:'client'` tool ids it can fulfil and sends them in the /run
body as `supported_client_tools`, so the runner exposes only those to the model
(spec ∩ supported).

- `runAgentSession` (api-client): optional `supportedClientTools`, added to the
  /run body when non-empty.
- `AgentChatSession` (core): carries `supportedClientTools`; `agentChatService`
  forwards it to `runAgentSession`.
- `useAgentChat` (ui): new `supportedClientTools` option threaded into the
  session config.
- `AGENT_BUILDER_CLIENT_TOOLS` declares the dock's fulfillable ids
  (set_secret, focus_*, toast, get_context) — verified to exactly match the
  agent-builder spec's `kind:'client'` tools — and is passed from the dock.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agent-config MCP sections expanded the custom-server form inline under
a Connect-new/Cancel toggle. Pop it out in a dialog instead (matching the
agent builder's connect_mcp punch-out). Extract AddCustomServerDialog as the
shared modal chrome and refactor AgentBuilderMcpConnectDialog to delegate to
it, so both the manual UI and the punch-out share one wrapper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…' into ben/agent-mcp-connections

# Conflicts:
#	packages/api-client/src/posthog-client.ts
#	packages/core/src/agent-chat/identifiers.ts
#	packages/ui/src/features/agent-applications/agent-builder/useAgentBuilderClientTools.ts
#	packages/ui/src/features/agent-applications/hooks/useAgentChat.ts
@benjackwhite benjackwhite changed the base branch from main to ben/agent-supported-client-tools June 25, 2026 18:38
The MCP config could add (Connect new / Add from a connection) and edit the
connection, but had no way to drop an mcps[] entry — only clear its connection.
Add a Remove server action to the MCP detail that filters the entry out of the
spec and returns to the list. The shared mcp_store installation is untouched;
only the agent's reference goes away.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@dmarticus dmarticus 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.

Just one question on an unstated removal — no blockers on the draft itself, the gaps you list cover it.

}),
});

// Top-level authorable sections always render — even with no entries — so the

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.

The list of always-render sections here conspicuously drops integrations — and the rest of the PR removes IntegrationsOverview/IntegrationBody, the cfg:integrations tree node, and the SECTION_INFO entry. But AgentSpec.integrations?: string[] is still in packages/shared/src/agent-platform-types.ts:70.

Net: if any shipped agent has spec.integrations: ["github"] today, the field is preserved on the backend but the UI silently stops showing or editing it — a soft regression that's easy to miss because nothing typechecks-broken.

Two clean ways out:

  • If no real specs use it: drop the type field in the same PR so the removal is total.
  • If some do: keep a read-only render path until the field is properly retired (deprecation note + migration).

Mostly want to make sure this was a deliberate "nobody uses integrations" call rather than collateral from the MCP refactor — the PR description doesn't mention it.

Base automatically changed from ben/agent-supported-client-tools to main June 26, 2026 08:17
…ions

# Conflicts:
#	packages/ui/src/features/agent-applications/agent-builder/useAgentBuilderClientTools.ts
#	packages/ui/src/features/agent-applications/hooks/useAgentChat.ts
@benjackwhite benjackwhite marked this pull request as ready for review June 26, 2026 08:39
@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (1)

  1. packages/ui/src/features/agent-applications/agent-builder/AgentBuilderDock.tsx, line 133-165 (link)

    P1 connect_mcp punch-out skips draft-branching

    submitMcpConnect calls client.updateAgentRevisionSpec directly with pending.revisionId, but the server only accepts a PATCH on a revision that is already in draft state. pending.revisionId falls back to pageRevision (the currently-viewed revision in the agent-config pane), which can be live, ready, or archived. When it is, the server rejects the PATCH with a 4xx and the operation fails — the agent gets the error token and the user sees nothing useful.

    Every other edit path in this PR goes through useApplyAgentSpec, which branches to a new draft when the source isn't one. submitMcpConnect needs the same treatment: check rev.state, and if it's not "draft", call client.createAgentDraftRevisionFrom first before patching.

Reviews (2): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

benjackwhite and others added 4 commits June 26, 2026 10:55
…ntSpec

The UI removal of the integrations section (IntegrationsOverview/IntegrationBody,
cfg:integrations node, SECTION_INFO entry) left `AgentSpec.integrations?: string[]`
behind — a soft regression where a shipped spec's integrations would be silently
un-editable. Nothing in the app reads the field (the agent-platform schema already
dropped it), so remove it for a total removal. Per review: this is a deliberate
"nobody uses integrations" call, not collateral from the MCP refactor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ions

# Conflicts:
#	packages/ui/src/features/agent-applications/components/AgentConfigurationPane.tsx
#	packages/ui/src/features/agent-applications/hooks/agentApplicationsKeys.ts
#	packages/ui/src/features/agent-applications/hooks/useApplyAgentSpec.test.ts
#	packages/ui/src/features/agent-applications/hooks/useApplyAgentSpec.ts
…+ per-tool overrides)

The connection MCP detail now shows the server's live tool catalog
(useMcpInstallationTools) with a connection-wide default permission and per-tool
overrides, reusing the standalone manager's ToolRow / ToolPolicyToggle. Levels
map allow/approve/deny <-> approved/needs_approval/do_not_use at the boundary;
edits persist to spec.mcps[].default_tool_approval + tools[].level via the
existing draft-branch-then-PATCH apply(). Add-from-connection now stamps a safe
default_tool_approval: 'approve' so the runtime and UI agree from first save.

Also clarifies the agent-level (shared connection — owner connects once, every
asker reuses) vs principal-level (per-asker identity provider) distinction in
the connection description.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…issions

Extract the searchable/expandable tool list (counts, per-tool policy toggle, expandable descriptions) into a presentational ToolPermissionList beside the mcp-servers parts, and wire McpBody to it. The parent owns config + persistence (spec default_tool_approval + per-tool level overrides); the component is callback-driven so it can also back the global MCP-servers manager unchanged. ServerDetailView is left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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