Skip to content

Develop - #532

Merged
thekevinm merged 36 commits into
mainfrom
develop
Sep 24, 2026
Merged

thekevinm merged 36 commits into
mainfrom
develop

Conversation

@thekevinm

Copy link
Copy Markdown
Contributor

No description provided.

Kevin McGahey and others added 30 commits August 27, 2026 22:51
Add isSystemMcp, derived from the selected (create) or loaded (edit)
service type name === 'system_mcp'. For such services the details page
shows a single "System API · 17 tools" panel driven by a fixed tool
catalogue (system-mcp-tools.ts, mirroring df-system-mcp-server TOOL_NAMES)
with the same enable/disable toggles bound to disabledTools, skips
loadMcpServices(), hides the per-service panels and the Custom Tools
section, and omits customTools from the save payload. MCP endpoint and
OAuth fields are unchanged.

Claude-Session: https://claude.ai/code/session_01PSYuns4gquVBXZc9STN6wa
The login card was height: 100% plus margin-top: 20vh, which made
mat-sidenav-content ~20vh taller than the viewport. Center with
min-height instead, and constrain the logo on narrow screens.

Fixes #517. Dist is not in this PR — rebuild on develop after merge.
…service-ui

feat(services): System API MCP Server (system_mcp) service details UI
…ger UI

The backend emits servers[0].url as '/api/v2/<service>' (valid, portable).
Swagger UI receives the spec inline, so it has no document URL to resolve
that against and prints host-less curl examples and Request URLs. Prefix
relative server URLs with window.location.origin at render time only; the
downloaded api-spec.json keeps the relative URL.

Fixes #519
The operations view passed '/api/v2/<service>' into df-try-it as baseUrl,
which it uses verbatim for the resolved-URL line and the curl / Python / JS
snippets, bypassing its own origin fallback. Prefix with the page origin so
the snippets are copy-pasteable. Includes rebuilt dist.

Refs #519
…les-and-request-url-show-rela

API Docs: show full instance URL in Swagger curl examples and Request URL
…ogue

Read-only tool that reports last-used / never-used / stale API keys, roles
and users from system/access_usage. Catalogue and spec go from 17 to 18
tools; df-system-mcp-server TOOL_NAMES must list it after list_admins.
…, roles, users, admins

Join GET system/access_usage client-side (like the apps table's AI usage
join) through a new DfAccessUsageService, and opt the apps, roles, users
and admins tables into it via DfManageTableComponent.enableAccessUsage():

- "Last used" (apps, roles) / "Last active" (users, admins) column with
  relative time or "Never"; tooltip carries the exact time, the service
  and status of the last use, the last denial, stale window, last login
  and 30-day volume when present, and "no use recorded since" tracking
  start for never-used subjects
- muted text for stale / never-used subjects, a warning icon for inactive
  keys that clients still send, an "Unreferenced" badge on roles
- "Not used in" selector (Any / 30 / 90 / 180 days / Never used),
  filtering the loaded rows client-side; the column sorts by last use

The request is silent: on 404 (older DreamFactory), 401/403, 400 or any
error the column and filter stay hidden and the tables render as before.
…ess-usage-ui

feat: access-usage last-used column and filter; get_access_audit in System MCP tool catalogue
With tool_style=merged the daemon registers each database verb once and
selects the backend with a `service` argument, so the per-service panels -
which list dvdstore_delete_records, db_delete_records and so on - no longer
describe the tools a client actually sees.

In merged mode the database panels are replaced by one "Database Tools
(merged)" panel: 16 bare verbs down the side, one column per database, and a
toggle per cell. Columns are labelled with the API name rather than the
display label, because the name is what the `service` argument takes.

Disable keys stay prefixed (<service>_<verb>) in both modes. The daemon reads
those entries and enforces them per service, dropping the database from the
merged tool's `service` enum and refusing it at call time, so the same
checkbox means the same thing whichever style is selected. Writing bare verbs
here would instead disable the verb for every database.

File services keep their own panels; merged mode merges database tools only.
Shared tool catalog (daemon-exact verbs), effective-access model with
camelCase-aware config parse/serialize, editor store with migration-safe
mutations, shell component (endpoint header, Connect/Tools/Settings tabs,
dirty bar with tool-count delta, save pipeline with auto cache flush),
route shim so mcp/system_mcp services get the new editor, and the
create-save redirect fix: a new MCP server lands on its own Connect tab
(?created=1) instead of API Docs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Connect: first-run checklist (?created=1), endpoint card with reachability
probe (401 renders as healthy auth), OAuth/API-key cards, six auth-aware
client setup panels with one-click Claude redirect-URI add.
Tools: unified exposure+curation surface — exposed-service rows with
tri-state capability drill-ins, derived access chips, orphan
needs-attention flow (keep-curation remove + rename successor with key
rewrite), filter strip + bulk bar at scale, global/aggregator and custom
tool sections, the what-an-agent-gets rail with derived read-only and
make-read-only, expose-services picker (read-only default, simulated
consequence footer), what-an-agent-sees preview drawer with named
exclusion reasons; system_mcp renders the fixed catalog with the same
grammar.
Settings: identity with rename warning, redirect URIs, API-key toggle,
honest tool-naming radio (null renders as server default, never rewritten
on load), catalog delivery, itemized orphan housekeeping, masked full
config viewer, danger zone.
Create: one-decision page — type cards, live URL preview, exposure picker
with read-only default and simulated consequence line, merged tool style
written at create, lands on Connect ?created=1.
Store: totalTools()/savedTotalTools() so system_mcp headers count the
fixed catalog.

122 jest tests across 6 suites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
13 Playwright tests against a live instance (curation and exposure
round-trips verified via API, create flow landing on ?created=1, preview
exclusions, settings honesty, system_mcp variant, legacy-editor guard),
with snapshot/restore discipline that leaves the instance byte-identical.

Fixes found by testing: the route shim and editor shell now re-initialize
on every resolver emission (Angular reuses routed components on
/ai/mcp/9 -> /ai/mcp/21, which previously kept showing the prior
service's editor); tabs drop per-service UI state via ngOnChanges; the
breadcrumb builder strips query strings so ?created=1 no longer corrupts
the page title; create-page URL-preview spacing; rail hint clipping.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Model: registered_redirect_uris survives saves verbatim (no fallback into
redirect_uris); lazy_mode uses the real auto|on|off daemon contract with
legacy-value tolerance; write-tool counts follow Appendix A per style and
include write-capable custom tools (readOnly is false while any is
enabled; Make read-only disables them); disabled_tools ownership resolves
by exact {service}_{verb} so sibling names (db / db_backup) never claim
each other's keys; system_mcp bare tool names are never 'orphans'; store
derivations memoized behind a version counter.

Tools: trackBy + identity-stable row arrays (mat-menus no longer torn
down by the next change-detection pass — regression spec included);
access chips recolored so Read-only reads as the safe state; bulk
'Copy curation from…'; rail gains Copy tool list, Manage roles link and
the lazy Why explainer; custom-tool dialog guards dismissal.

Connect/Settings/Create: probe claims 'auth enforced' only on a real
401/403 challenge; zero-tools warning on Connect; single checklist
grammar; redirect-URI jump prompt; catalog-delivery options store
on/off; style-switch reassurance ('Your tool selections are preserved');
clone preserves a null tool_style as prefixed.

Shared: indeterminate checkboxes take the DF purple; custom-tool header
blobs exempt from case transforms; unsaved-changes canDeactivate guard
across editor and create; endpoint header deduplicated against the
Connect hero card.

165 jest tests, 13/13 live e2e green. Also fixes the instance-side
root-owned Laravel cache file that made rapid admin logins 401/500.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… server-backed catalog size

Settings: "Require role access" (Authentication) and "Allow writes"
(Serving, hidden for system_mcp) switches, saved through the existing
whole-service PUT. allow_writes=false now drops the daemon's write verbs
and write-capable custom tools from every count, the rail, preview and
copy-tool-list; the rail reads "writes are off" instead of offering
Make read-only. New services are created with require_role_access=true
and allow_writes=true (read-only stays compiled into disabled_tools).

Header: /_internal/ai/mcp-health chip (ok / warn / error) with the first
non-ok check's message; the endpoint URL uses APP_URL from the app_url
check, with a note when it differs from the page origin.

Catalog size: the flat 81 tokens/tool + 8k-token model is replaced by
the daemon's byte model (32 KiB LAZY_THRESHOLD_BYTES, bytes/4 tokens,
5-tool facade incl. fetch_more). Numbers come from the server for the
saved config (admin: tools/list over JSON-RPC; role/app:
mcp-catalog via store.setPreviewIdentity), and fall back to the
calibrated client simulation while the form is dirty or the call fails.

Refs #526
…nd API keys (#525)

Ports the inline access editor from feat/mcp-exposure onto the redesigned
MCP editor: roles that can use the server (from /_internal/ai/mcp-access),
one-click Grant, an access editor dialog (create / add / edit; per-service
none / read / read-write; Read on all; filter above 6; limit to tables;
live summary of the role changes), optional API key creation whose key the
Connect snippets then fill instead of YOUR_API_KEY. Respects allow_writes.
…he daemon

The UI treated all six all_* tools as database aggregators. The daemon
registers the five database ones at 2+ databases and all_list_files only at
2+ file services, so a databases-only server showed one tool more than it
serves (logistics_mcp: 25 vs server 24).
…tor changes its level

A row restricted to API callers (requestor_mask 1) was silently widened to
API+script (3) on any level change. Also pin the writes switch as
connection-affecting in the store spec.
mcp-service and mcp-redesign-flows no longer depend on service ids 9/21/6 or
names mcp_full/sysmcp_demo/db/db2/files/logs. Each file creates two SQLite
databases, a local file service, an mcp server (API-key auth, custom tool
env_info) and a system_mcp server under its own prefix in beforeAll and
deletes them in afterAll.

- Endpoint URLs are expected from APP_URL (mcp-health) like the editor,
  falling back to the page origin.
- Restore check ignores custom tools' created_at/updated_at (re-stamped on
  every save).
- workers: 1, as the config comment already intended: suites create/delete
  services and assert against the instance-wide service list.

Verified: 13/13 twice in a row on df-dev (APP_URL differs from the page
origin there), no e2e_* services left behind.
- Tools tab: each exposed service row now carries one cell per tool, in
  columns aligned under a per-kind header with rotated tool names, a switch
  per column (that tool in every exposed database) and per group (Read,
  Schema, Write, Procs). Green = served read, orange = served write/execute,
  hollow = off, hatched = blocked by allow_writes. Legend below. Drill-in,
  access chip and menus unchanged.
- Header: APP_URL and other health problems render as df-alert banners like
  the rest of the admin; the APP_URL copy explains which address clients
  must use instead of the raw health string.
- Tabs: mat-tab-nav-bar with bolder labels and an active tint.
- Every hard-coded colour in adf-mcp now uses the DF theme tokens (rgba
  alphas via color-mix), so the editor works in dark and phosphor themes;
  cards were white-on-white in dark mode before.
nicdavidson and others added 6 commits September 22, 2026 14:20
MCP editor redesign (Kevin's UI) + roles/keys, health, tool grid, server-backed counts
The MCP editor assumed merged tool_style applied to databases only, which was
true of the daemon until file services gained merged registration. With that
support in place the editor disagrees with the server: on a service exposing
three databases and three file services it reports 47 tools while the daemon
advertises 35, and the tool grid still labels the file rows logs_list_files
when a client is served a bare list_files.

Five places carried the assumption:

  - effectiveTools() summed file verbs per service unconditionally, so the
    Tools tab over-counted by (services - 1) x 6. It now branches on style the
    way the database count already does.
  - the write math counted file write verbs as per-service instances in both
    styles; merged now counts the distinct verb set, matching databases.
  - the tool grid resolved the emitted name with style for databases and a
    hardcoded 'prefixed' for file services.
  - the merged caption, which explains that turning a verb off narrows the
    tool's allowed services rather than removing it, was gated to databases.
  - the preview pane listed file tools under per-service names always, and the
    custom-tool dialog reserved only prefixed file names, so a custom tool
    could collide with a merged file verb without being flagged.

disabled_tools keys stay in the prefixed {service}_{verb} form in both styles,
so the store's write path is unchanged; this is presentation and arithmetic.

Note for review: the Appendix A write-tool test asserted file services were
per-service instances in BOTH styles. That invariant is what changed, so the
test now asserts 3 merged and 6 prefixed for two file services.
"list -> open the MCP server lands on Connect with URL, probe and live count"
fails on develop with Expected: 22, Received: 6.

The header chip renders as soon as the editor does, showing the count the
store can compute before the backend-services fetch has landed — globals and
custom tools only. The test read it once, with textContent(), and compared
that first paint against the settled model, so it raced the fetch and lost.
The Tools tab tests do not hit this because openToolsTab() waits for
.mcp-tools-loading to clear first.

Read the chip through expect.poll so the assertion retries until the catalog
arrives, and assert the model is non-trivial separately rather than inferring
it from the racing read. numberFrom() is left alone for the callers that read
values which are settled by the time they run.
…unt-race

fix(e2e): poll the live tool count instead of reading it once
…e-tools-ui

Feat/mcp merged file tools UI
@thekevinm
thekevinm merged commit b898bb3 into main Sep 24, 2026
1 check passed
@thekevinm
thekevinm deleted the develop branch September 24, 2026 17:36
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.

3 participants