Skip to content

MCP server page: exposure grid, preview as role/key, who can connect, modes, connect snippets (#523) - #524

Merged
nicdavidson merged 6 commits into
feat/mcp-exposurefrom
feat-mcp-exposure-page
Sep 18, 2026
Merged

nicdavidson merged 6 commits into
feat/mcp-exposurefrom
feat-mcp-exposure-page

Conversation

@nicdavidson

Copy link
Copy Markdown
Contributor

Summary

The MCP service page now shows exactly what a server exposes and lets an admin preview it as any role or API key.

  • Header: endpoint URL, health chip from mcp-health (link to the System page), reach chip (any logged-in user / N roles granted), Preview-as selector (Any admin, each role from mcp-access, each API key), summary tiles (tools advertised, ~tokens per turn, catalog mode + why, who can connect).
  • Modes strip: Lazy (Auto/On/Off), Tool style (Merged/Prefixed; hidden for system_mcp), Writes (allow_writes), Authentication, Require role access. Each shows a one-line consequence that updates live from the local catalog model.
  • What the client carries each turn: full-catalog vs 5-tool-facade bars against the 32 KB auto threshold, and the four lazy steps (greyed when the server is direct).
  • Who can connect: rows from mcp-access joined with the real role rows and any bound API key (read/write level, reach across exposed APIs, requests/denied, Preview as, Edit access, Role page). Add existing role (server only unless APIs are ticked), Edit access (per exposed API None/Read/Read+write; table-limited grants link to the role page), Create role (optional API key shown once). Every save shows a plain diff first and states the change applies everywhere, not only through MCP. With require_role_access off: "Any logged-in user can connect" plus the roles seen in the last 30 days without a grant, each with Grant.
  • Exposure grid: rows = attachable backends (Database: 16 verbs in Read/Spec/Procedures/Write; File: 6 verbs), row switch = exposed_services, cell = disabled_tools key (<sanitized>_<verb>, identical in both styles). Write verbs amber with a W badge. States: on, off, writes-off, denied (role lacks the verb), gone (hidden from this identity). Component-scoped grants show "limited to N tables" instead of marking every tool denied. Legend included. This replaces the synthesised Built-in Tools panels and the merged matrix from Feat/mcp merged tools UI #522; the custom tools editor is unchanged.
  • Catalog panel: the previewed identity's tool chips (W on writes, facade chips distinct, custom tools dashed), counts, and a note on where the sizes come from.
  • Connect card: Claude / Cursor / VS Code / ChatGPT / curl snippets that switch with the auth mode and the selected identity (key header when a key is previewed and key auth is on).
  • Last 7 days: calls per exposed backend from mcp-usage (merged verbs land in an "All databases" row), zero calls highlighted.
  • Create flow for a new mcp service: name -> attach APIs -> who can connect -> client settings -> review (this page in preview mode) -> connect snippet with a "waiting for the first call" state. New servers default to merged style and require role access on.
  • Fixes on the way: the df-ai-mcp-servers create link now points at /ai/mcp/create; system_mcp never shows Tool style.

Screenshots were captured with Playwright against ng serve proxied to the dev instance (demo_mcp as admin, as orders_analyst_app, sysmcp, and the create-flow review step); the CLI cannot attach images to a PR body, so they are not embedded here.

Behaviour changes

Before: the MCP page listed tools for every active database/file service regardless of exposed_services (demo_mcp: 3 exposed, 10 shown), the health panel reported "No role grants access" although any authenticated user could connect, and there was no way to see what a role gets, who can connect, or what lazy/merged/key auth change.

After: the page shows only exposed backends; tool toggles map 1:1 to disabled_tools; new controls for require_role_access and allow_writes; role grants can be added, edited and created from the page (real role_service_access rows, diff shown first); the preview-as selector shows each role's/key's real catalog from mcp-catalog.

Upgrade impact: none on saved config. Existing disabled_tools keys are read as-is. When the backend lacks allow_writes / require_role_access the controls render disabled with a "needs a newer df-mcp-server" note; when mcp-catalog or mcp-health are missing the page falls back to tools/list calibration and says so. dist/ is rebuilt.

How verified: unit spec for the model (18 tests), npm run test:ci (22 suites / 187 tests), Playwright spec against the dev instance data through ng serve, manual screenshots of all four page states, npm run build.

Testing

  • npm run lint: no errors in new or touched files (the two pre-existing label-has-associated-control errors in the custom-tools editor are unchanged from develop).
  • npm run test:ci: 22 suites, 187 tests passing (adds src/app/adf-ai/mcp/mcp-model.spec.ts).
  • PLAYWRIGHT_BASE_URL=http://localhost:4200 npx playwright test e2e/mcp-exposure.spec.ts with ng serve --proxy-config pointed at the dev instance: passes; asserts every grid row switch matches demo_mcp's exposed_services.
  • npm run build succeeds; dist/ rebuilt in the final commit.

Closes #523

Catalog shaping (prefixed/merged, lazy threshold, per-identity reach),
grid cell states, role grant diffs and PATCH rows, connect snippets and
usage attribution live in mcp-model.ts with no Angular dependency.
DfMcpApiService wraps /_internal/ai/mcp-{access,catalog,health,usage},
the tools/list JSON-RPC fallback and the role/app/service system calls,
returning null when an endpoint is not deployed.
df-mcp-exposure composes the MCP server page: endpoint + health chips,
Preview-as (admin, each role from mcp-access, each API key), summary
tiles, modes strip with live consequences, what-the-client-carries bars,
the backends x verbs exposure grid (row = exposed_services, cell =
disabled_tools, states on/off/writes-off/denied/gone), the previewed
identity's catalog chips, connect snippets for Claude/Cursor/VS Code/
ChatGPT/curl and last-7-days calls per backend.

df-mcp-access lists who can connect from mcp-access joined with real
role rows and keys; add existing role / edit access / create role go
through df-mcp-access-dialog, which shows a plain diff before writing
role_service_access rows and states the change applies everywhere.

Role previews use mcp-catalog (backends[].verbs, component_scoped shown
as 'limited to N tables'); the admin view calibrates sizes from
tools/list and says so.
name -> attach APIs -> who can connect -> client settings -> review (the
exposure page in preview mode) -> connect snippet that waits for the
first call. Defaults for new servers: merged tool style, require role
access on, writes allowed. Grants selected roles server access after
the POST.
Replace the synthesised Built-in Tools panels (every active DB/file
service, ignoring exposed_services) and the merged matrix with
df-mcp-exposure for mcp and system_mcp; system_mcp keeps its fixed tool
toggles and never shows Tool style. The MCP-owned config fields are
hidden from the generic Options loop; the health panel is replaced by
the page's own health/reach chips. New mcp services render
df-mcp-create. Fix the df-ai-mcp-servers create link to /ai/mcp/create.
Logs in, reads demo_mcp's config over the API and asserts each grid row
switch matches exposed_services, exposed cells are live, hidden rows are
gone, and the tiles/access/connect cards render.
@nicdavidson
nicdavidson merged commit 0cc4851 into feat/mcp-exposure Sep 18, 2026
@nicdavidson
nicdavidson deleted the feat-mcp-exposure-page branch September 18, 2026 18:33
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