Skip to content

feat(mcp-store): personal/shared MCP installation scope#3311

Open
cvolzer3 wants to merge 5 commits into
mainfrom
feat/mcp-shared-installation-scope
Open

feat(mcp-store): personal/shared MCP installation scope#3311
cvolzer3 wants to merge 5 commits into
mainfrom
feat/mcp-shared-installation-scope

Conversation

@cvolzer3

@cvolzer3 cvolzer3 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Problem

MCP Store installations are user-scoped only, so team-wide (shared) MCP connections aren't usable from PostHog Code, and autonomous agents can only use the task creator's personal connections. Backend support is being added in PostHog/posthog#69658 plus the stacked phase-1 branch feat/shared-mcp-phase1 (share/unshare escalation, admin delete override, is_owner, sandbox dedupe, basic audit logging). This is the Code-client half of phase 1.

Phase 2 (tracked separately) covers full audit logs, richer in-session differentiation, correct attribution, and per-MCP access controls.

Changes

Screenshot 2026-07-09 at 2 52 25 PM
  • api-client: scope (personal | shared) and is_owner on MCPServerInstallation; scope accepted by install_custom/install_template; new shareMcpInstallation/unshareMcpInstallation (POST {id}/share|unshare/).
  • core: scope threaded through the custom-server form builder and OAuth install flows.
  • ui:
    • Visibility (Personal/Shared) selector on the custom-server form; the Shared option is admin-gated (creation is admin-only server-side since a shared install exposes the installer's credential).
    • Template Connect stays one-click personal; Share with project escalation lives in the server detail view (owner + admin), behind a consent dialog spelling out that project members and autonomous agents will act as the sharer on the connected service. Unshare reverts (owner or admin).
    • Owner/admin gating from is_owner: tool policy, refresh, and enable/disable are owner-only on shared servers; Remove is owner-or-admin. Unknown is_owner (older backends) keeps controls usable — the backend enforces.
    • Connect personally on a teammate's shared server, so a shared install doesn't block members from connecting their own account.
    • Shared badge in the detail header and installed rail.
  • workspace-server: agent session wiring dedupes installations by URL with personal-over-shared precedence — sessions act as the user whenever they have their own connection.

Forward-compatible with today's backend: without the posthog changes deployed, scope is ignored server-side, is_owner/share endpoints simply aren't exercised, and everything behaves as before.

How did you test this?

  • pnpm typecheck (23/23 packages)
  • Unit tests: api-client 71, core 2162, ui 1421, workspace-server 656 — all passing; new coverage for scope pass-through (core install flows/form builder) and personal-over-shared dedupe (auth-adapter)
  • biome check clean on all touched files; biome lint packages/core shows zero noRestrictedImports

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

cvolzer3 added 2 commits July 9, 2026 11:25
Port of PostHog/posthog#69658 to the Code client. The backend now
supports a scope on MCP Store installations: personal (per-user,
the existing default) or shared (team-wide, visible to all project
members and autonomous agents).

- api-client: add scope to MCPServerInstallation and the
  install_custom/install_template request contracts, mirroring the
  regenerated OpenAPI types; export McpInstallationScope.
- core: thread scope through CustomServerFormValues,
  buildCustomServerRequest, and the OAuth install flows.
- ui: Visibility (Personal/Shared) selector in the add-server form,
  with the shared option gated to admins (creation is admin-only on
  the backend since a shared install exposes the installer's
  credential); Shared badge in the installed rail and server detail
  header.

Shared installations returned by the list endpoint flow into agent
sessions automatically via the existing workspace-server wiring.
…-wins dedupe

Builds on the personal/shared installation scope:

- Share with project / Unshare actions in the server detail view. Sharing
  is owner+admin only and sits behind a consent dialog spelling out that
  project members and autonomous agents will act as the sharer on the
  connected service. Backed by new shareMcpInstallation /
  unshareMcpInstallation api-client methods (POST {id}/share|unshare).
- Owner/admin gating driven by the new is_owner serializer field: tool
  policy toggles, bulk actions, refresh, and the enable switch are
  owner-only on shared servers; Remove is owner-or-admin. Unknown
  is_owner (older backends) keeps controls usable — the backend is the
  enforcement point.
- "Connect personally" on a teammate's shared server so members can use
  their own identity instead of the shared credential.
- Personal wins over shared: agent session wiring dedupes installations
  by URL, dropping a shared install when the user has their own personal
  connection to the same server.

Pairs with the posthog backend phase-1 branch (share/unshare endpoints,
admin delete override, is_owner, sandbox dedupe, basic audit logging).
@trunk-io

trunk-io Bot commented Jul 9, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

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

3 warnings

src/features/mcp-servers/components/McpServersView.tsx

src/features/mcp-servers/components/parts/ServerDetailView.tsx

Reviewed by React Doctor for commit 5665ba4.

@cvolzer3 cvolzer3 changed the title feat(mcp-store): personal/shared MCP installation scope (phase 1) feat(mcp-store): personal/shared MCP installation scope Jul 9, 2026
@cvolzer3 cvolzer3 marked this pull request as ready for review July 9, 2026 18:52
@cvolzer3 cvolzer3 requested a review from veryayskiy July 9, 2026 18:52
@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "chore(mcp-servers): tighten share dialog..." | Re-trigger Greptile

Comment thread packages/ui/src/features/mcp-servers/components/McpServersView.tsx Outdated
Comment on lines 9721 to 9722
description?: string | undefined;
auth_type?: MCPAuthTypeEnum | undefined;

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.

P2 scope typed as required but absent on older backends

scope: MCPServerInstallationScopeEnum is non-optional in the generated type, but the PR description explicitly notes that older backends won't include it. At runtime scope will be undefined for those environments, even though TypeScript asserts it's always a string union. Every call site in this PR handles this correctly (scope === "shared" evaluates to false for undefined), but the misleading type means future code won't get a compiler warning if it treats scope as guaranteed — e.g. a switch on scope without a default. Marking it scope?: MCPServerInstallationScopeEnum would make the contract accurate. If this file is purely auto-generated it can only be fixed upstream in the schema, but it's worth noting the discrepancy given auth-adapter.ts already declares it as optional in its local type.

cvolzer3 added 2 commits July 9, 2026 16:03
- Clear the pending-install id snapshot when "Connect personally" fails,
  so a later-appearing row (e.g. a teammate sharing a server) can't
  hijack the view
- Only dedupe personal-over-shared agent installations on truthy URLs;
  absent URLs no longer collapse unrelated servers. Align local types
  with the generated schema (url is optional) and end name fallbacks at
  the always-present id
- Prefer the personal row in the marketplace template->installation map
  so card navigation doesn't depend on API ordering
- Don't flash the admins-only visibility hint while the org role loads
- Drop a redundant installation guard; document phase-1 template-only
  scope of "Connect personally"
- Tests: share/unshare client methods (paths + error surfaces), missing-
  URL dedupe case
Older backends without PostHog/posthog#69658 omit scope from the
serializer, so the field is undefined at runtime even though the
hand-mirrored type asserted it was always present. Type it optional —
matching is_owner, which shipped with the same forward-compat
treatment — so future call sites can't assume it's guaranteed.
Becomes required again on the next regen once the backend is deployed
everywhere.
@cvolzer3 cvolzer3 requested a review from a team July 10, 2026 17:38
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.

1 participant