Skip to content

[MCP] MCP Server Manager UI (#1309) - #4079

Draft
wwidergoldpimcore wants to merge 11 commits into
feature/oauth-1308-basic-integrationfrom
feature/mcp-1309-server-ui
Draft

[MCP] MCP Server Manager UI (#1309)#4079
wwidergoldpimcore wants to merge 11 commits into
feature/oauth-1308-basic-integrationfrom
feature/mcp-1309-server-ui

Conversation

@wwidergoldpimcore

Copy link
Copy Markdown

Adds the MCP Server Manager UI (#1309) — a Studio settings screen to CRUD MCP servers (name, tools, sharing, enabled) with the three-capability permission model (Config Read / Config Edit / MCP Server Access).

This branch is stacked on top of the OAuth consent branch (feature/oauth-1308-basic-integration) so the OAuth consent screen can roll out first. It targets that branch (not 2026.x) and will be rebased onto it as the base evolves; retarget to 2026.x once #1308 has merged.

Scope on top of the base branch is MCP-only:

  • assets/js/src/core/modules/mcp-servers/** — rail, tabs, editor (general + permissions/sharing), hooks
  • module registration (bootstrap.ts), McpServers permission, share-dropdown label fix
  • MCP OpenAPI schemas/paths + generated mcp-servers slice + mcp-servers.* translations

Verified: tsc clean, eslint clean, full jest suite (624 tests) green.

🤖 Generated with Claude Code

wwidergoldpimcore and others added 11 commits September 3, 2026 15:26
UsersRolesDropdown built its badge-label map from the assignable-options
list, which filters out the current user (you cannot share with yourself).
When the current user was already present in a shared value, their badge
rendered blank. Resolve labels from the full user list plus the current
user's own name as a fallback; the options list stays filtered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A Studio settings screen to manage MCP servers: group tools under a URL and
control who may use them. Master/detail layout mirroring the agent bundle —
a left rail of servers and a right configuration mask (identity, tools,
two-level read/write sharing, derived scopes + URL).

- Generated RTK Query client from the MCP OpenAPI tag (surgical merge of the
  MCP paths/schemas into docs.jsonopenapi.json + an openapi-config output
  entry) -> mcp-servers-api-slice.gen.ts
- Master/detail via ConfigLayout; delete confirm; errors routed via trackError
- Two-level sharing (read/write grants per user & role) via OperationalGrid,
  a Global-read toggle, and a live who-can-access summary
- Gating: screen reachable by read-consumers (list is row-filtered server-side);
  New gated on the mcp_servers permission; edit/delete driven by
  currentUserPermissions.write and the storage writeable flag
- Nav entry under Automation & Integration; mcp_servers permission enum case;
  i18n keys in studio.en.yaml

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks the #1309 MCP Server Manager screen to mirror the pimcore-agent-bundle
configuration UI:

- Master/detail: a server rail with a bottom refresh/new toolbar, and servers
  opened as editable-card tabs (New opens a create tab)
- Editor split into General and Permissions inner tabs; Save fixed in the
  tabs-level bottom toolbar (via portal slot), Delete moved to a rail context menu
- Two-level sharing grid (Read / Can edit per user and role) with a live
  who-can-access summary; share names resolved from the share collection with a
  current-user fallback
- Success toast on save; read-only handling driven by currentUserPermissions
  and the storage writeable flag

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The backend's McpServerAccessGrant now carries `name` instead of `id`, so the
sharing grid stores and shows the user/role name directly. Removes the id->name
resolution (share-collection lookup + current-user fallback) and the grid
remount workaround, which also fixes names briefly rendering as `#id` on first
load. Regenerated the MCP client from the updated OpenAPI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The backend split server access into three resolved bits: canView, canAccess
and canEdit. Grants now carry canAccess + canEdit as two independent booleans
instead of a single read/write enum, and currentUserPermissions gains canView.

The sharing grid follows the Agent bundle's run/update shape: two real-field
checkbox columns ("Can access" / "Can edit") written straight through onChange,
dropping the synthetic-enum column and its cell-data translation shim. Read-only
mask and delete gating move from currentUserPermissions.write to .canEdit.
Regenerated the MCP client from the updated OpenAPI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The tab's dirty marker stayed after saving (issue #1451): the dirty baseline and
the editor's live fields were seeded from the server at different times, so once
the post-save refetch moved the baseline the two never re-equalised for a
reordered tools/sharing array. The baseline and fields are now re-seeded together
from the same server object whenever it changes, and the dirty effect reacts to
data changes only (callbacks held in refs) so the optimistic clear is no longer
overwritten while the refetch is in flight — clearing the flag instantly, as the
Agent bundle does.

The left rail now blanks and rebuilds the whole list on any refetch (matching the
Agent tree) instead of patching rows in place, and the tab label is derived from
the refreshed server list, so renames surface without the removed renameTab patch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rows

Add a name filter (SearchInput, same props as the Agent tree) above the list and
tighten the row rhythm — smaller vertical padding, no inter-row gap — so the rail
resembles the Agent bundle's config list. The Custom/Preset view switch is
intentionally omitted; MCP servers are a flat list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
McpServerAccessGrant gains a canRead boolean (explicit Config Read per grant, with
edit implying read); patch the tracked codegen source and regenerate the slice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… row

Split the sharing grid into the three independent capabilities the backend now
models (issue #1452): Config Read (canRead), Config Edit (canEdit) and MCP Server
Access (canAccess). Config Read is forced on and disabled whenever Edit is set —
you cannot edit a config you cannot read — and a new grant starts read-only, with
Access and Edit opt-in.

The owner's own user row (matched against McpServer.owner) shows Config Read and
Config Edit locked-on and disabled — the backend grants the owner those implicitly
regardless of the stored flags — leaving only MCP Server Access meaningful to
toggle. A normalize pass keeps the displayed rows and any change self-consistent
so the disabled boxes always read ticked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The MCP server UI now lives on its own branch on top of the OAuth (1308) branch.
Re-merge the MCP schemas (McpServer/McpServerAccessGrant/McpServerUserPermissions/
McpToolItem) and the /mcp/* paths onto the branch's spec so it matches the
committed mcp-servers slice; the OAuth consent schemas from the base branch are
preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 3, 2026

Copy link
Copy Markdown

@pimcore-deployments

Copy link
Copy Markdown
Collaborator

🌐 Translations synced automatically

The key changes below were generated for all target languages, passed the
mechanical validation gate (key parity, order, placeholders, types, plurals),
and are being committed to this branch by the workflow (check the run status
if the commit is not visible).
Please review the generated translations.

Added (54):

  • mcp-servers.rail.new-server
  • mcp-servers.placeholder
  • mcp-servers.tabs.empty
  • mcp-servers.tabs.new-server
  • mcp-servers.read-only-notice
  • mcp-servers.save-success
  • mcp-servers.access.global
  • mcp-servers.access.admin-only
  • mcp-servers.access.user
  • mcp-servers.access.users
  • mcp-servers.access.role
  • mcp-servers.access.roles
  • mcp-servers.access.admins-owner
  • mcp-servers.access.admin-owner-only
  • mcp-servers.access.global-extra
  • mcp-servers.badge.read
  • mcp-servers.badge.write
  • mcp-servers.editor.create-title
  • mcp-servers.editor.edit-title
  • mcp-servers.editor.general
  • mcp-servers.editor.permissions
  • mcp-servers.editor.identity
  • mcp-servers.editor.name
  • mcp-servers.editor.name-required
  • mcp-servers.editor.url-slug
  • mcp-servers.editor.url-slug-required
  • mcp-servers.editor.url-slug-pattern
  • mcp-servers.editor.description
  • mcp-servers.editor.enabled
  • mcp-servers.editor.tools
  • mcp-servers.editor.tools-placeholder
  • mcp-servers.editor.scopes
  • mcp-servers.editor.scopes-empty
  • mcp-servers.editor.url
  • mcp-servers.editor.connect-hint
  • mcp-servers.sharing.title
  • mcp-servers.sharing.share-globally
  • mcp-servers.sharing.share-globally-tooltip
  • mcp-servers.sharing.users
  • mcp-servers.sharing.roles
  • mcp-servers.sharing.add-user
  • mcp-servers.sharing.add-role
  • mcp-servers.sharing.name
  • mcp-servers.sharing.config-read
  • mcp-servers.sharing.config-edit
  • mcp-servers.sharing.mcp-access
  • mcp-servers.sharing.level
  • mcp-servers.sharing.read
  • mcp-servers.sharing.write
  • mcp-servers.sharing.who-can-access
  • mcp-servers.delete.title
  • mcp-servers.delete.confirm
  • navigation.mcp-servers
  • widget.mcp-servers

⚠️ Ambiguous keys (review carefully)

Translation ambiguity notes

A few keys in this PR's delta (mcp-servers.*) had no existing precedent in the bundle and
required a judgment call. Flagging them here in case a native reviewer disagrees.

mcp-servers.editor.tools, mcp-servers.editor.tools-placeholder

  • English: "Tools" — refers to MCP protocol "tools" (functions the server exposes), not
    generic UI tooling.
  • Chosen reading: kept "Tools" untranslated in all six languages, treating it as an emerging
    MCP-protocol technical term (parallel to how "Webhooks"/"OAuth" stay English per the glossary).
    This matches existing precedent in oauth.consent.scope.mcp-read.description (de), which already
    renders "Tools" untranslated in an otherwise fully-German sentence.
  • Alternative: translate as ordinary nouns (Werkzeuge / outils / strumenti / herramientas /
    verktyg / verktøy).

mcp-servers.editor.scopes, mcp-servers.editor.scopes-empty

  • English: "scopes" — the OAuth/MCP permission-scope identifiers shown as tags (e.g. mcp:read),
    not the general English word "scope".
  • Chosen reading: kept "Scopes"/"scope" untranslated in all six languages, same rationale as
    above (technical protocol vocabulary, no existing translated precedent in the bundle).
  • Alternative: translate as "permissions" (as oauth.consent.no-scopes does, e.g. de
    "Berechtigungen"), since that key already renders the concept of scopes as "permissions" rather
    than using the literal word.

🧹 Pre-existing translation errors (backlog partly cleared)

24 validation error(s) predating this PR were present at the merge base. This run also fixed 12 of them; 12 still remain. The remainder is not blocking — later runs keep chipping at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants