Skip to content

@W-23375797: consolidate admin-gated tools into polymorphic dispatchers#475

Open
Akash-Rastogi wants to merge 6 commits into
mainfrom
akash/consolidate-admin-tools
Open

@W-23375797: consolidate admin-gated tools into polymorphic dispatchers#475
Akash-Rastogi wants to merge 6 commits into
mainfrom
akash/consolidate-admin-tools

Conversation

@Akash-Rastogi

Copy link
Copy Markdown
Contributor

[Akash's agent]

Description

Introduces two new polymorphic MCP tools to reduce the model-visible admin tool
surface, while preserving every existing behavior end-to-end during a shim
window:

New tool Discriminator Merges (still wired as legacy)
query-admin-insights kind get-stale-workbooks, get-stale-datasources, get-content-usage-metrics, get-user-activity
delete-content resourceType delete-workbook, delete-datasource, delete-extract-refresh-task

Motivation and Context

The admin-gated set has grown to the point where its model-visible tool count
crowds the model's decision space and inflates prompt-time tool schemas.
W-23375797 targets two consolidations that each collapse a family of
same-shape tools behind one dispatcher, so the model reasons about one entry
per capability instead of one per (capability × resource kind).

Both consolidations are additive: the legacy tools remain wired and continue
to function unchanged during the migration window.

Design highlights

query-admin-insights

  • One paramsSchema with a kind discriminator; dispatches to the same
    underlying admin-insights resolver as the legacy readers.
  • Returns the same payload shape as the corresponding legacy tool for each
    kind, so downstream consumers reading stale_workbooks / user_activity
    data need no changes.

delete-content

  • Polymorphic destructive tool; preserves the two-phase preview→confirm flow
    and routes through guardMutation() — admin gate, evidence gate, audit
    record.
  • mcp-apps flag ON (HITL panel flow): preview records
    AppApprovalEvidence under the legacy namespaces
    (delete-workbook / delete-datasource /
    delete-extract-refresh-task) so the existing iframe machinery keeps
    dispatching confirm-delete-* model-invisible tools by panel
    data.kind. No surface added; no user-facing rewiring.
  • mcp-apps flag OFF (shim flow): uses the same TagEvidence /
    RegistryEvidence gates as the legacy paths, keyed by resourceType.
  • Rejects non-UUID resourceId on the extract-refresh-task branch before
    opening a Tableau REST session (via ArgsValidationError) — smaller blast
    radius than the previous placement.
  • Adds an optional fallbackTargetKind param to guardMutation() so a
    denied-attempt audit record on a polymorphic tool carries the correct
    target kind even when resolveTarget() itself failed.

How Has This Been Tested?

  • npm test — full unit suite passes (20 new tests in
    deleteContent.test.ts, plus the new queryAdminInsights.test.ts).
  • npx tsc --noEmit — no type errors.
  • npx eslint . — clean.
  • Manual test config prepared for stdio transport (see local
    config.stdio.json — not committed): ADMIN_TOOLS_ENABLED=true,
    ADMIN_GATE_CACHE_TTL_MINUTES=5.
  • Manual verification plan:
    • query-admin-insights { kind: 'stale-workbooks' } returns same payload
      as get-stale-workbooks.
    • delete-content { resourceType: 'workbook', resourceId: <luid> }
      preview → { confirm: true, tag } confirm (flag-OFF shim).
    • Flag-ON: flip features.json mcp-apps: true, preview opens an iframe
      panel; approval fires legacy confirm-delete-workbook.

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Documentation update

Not a breaking change: legacy tools remain enabled during the shim
window. INCLUDE_TOOLS / EXCLUDE_TOOLS handling is unchanged.

Related Issues

  • GUS: W-23375797 — [Tableau MCP for Admins] Consolidate admin-gated tools to reduce total tool count

Checklist

  • I have updated the version in package.json (2.25.0 → 2.26.0).
  • I have added tests that prove my feature works.
  • New and existing unit tests pass locally with my changes.
  • No breaking changes.

Contributor Agreement

  • I have read the CONTRIBUTING guidelines for this project.

@Akash-Rastogi Akash-Rastogi left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Akash's agent]

Self-review pass — three line-anchored findings below. None is a hard merge blocker (legacy tools remain wired during the shim window, so no caller loses a capability today), but each is worth resolving before we retire the legacy tools.

Comment thread src/server/oauth/scopes.ts Outdated
Comment thread src/tools/web/adminInsights/queryAdminInsights.ts Outdated
Comment thread src/tools/web/adminInsights/queryAdminInsights.ts Outdated
Akash-Rastogi and others added 3 commits July 10, 2026 13:25
Two new polymorphic tools reduce the model-visible admin tool surface:

- `query-admin-insights` (kind discriminator) merges 4 insight readers:
  get-stale-workbooks, get-stale-datasources, get-content-usage-metrics,
  get-user-activity.
- `delete-content` (resourceType discriminator) merges 3 preview→confirm
  destructive tools: delete-workbook, delete-datasource,
  delete-extract-refresh-task.

Behavior preserved end-to-end. `delete-content` records
AppApprovalEvidence under legacy namespaces so the mcp-apps HITL panel
flow (flag-ON) continues to dispatch confirm-delete-workbook /
confirm-delete-datasource / confirm-delete-extract-refresh-task via
the existing iframe machinery. The flag-OFF preview→confirm tag/nonce
evidence gates work unchanged.

Auth: scope-based auth in scopes.ts adds delete-content and
query-admin-insights, each carrying the union of its component tools'
MCP + REST scopes. Both are dropped from `getEnabledToolNames()` when
`ADMIN_TOOLS_ENABLED=false`.

Legacy tools remain wired during the shim window.

Bumps package version 2.25.0 → 2.26.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- delete-content: replace three per-resource MCP scopes with the
  umbrella tableau:mcp:content:delete so authMiddleware's AND-enforcement
  doesn't 403 callers who only granted one legacy scope. Callers who
  need per-resource granularity keep using the legacy delete-{workbook,
  datasource,extract-refresh-task} tools during the shim window.
- query-admin-insights: move the missing-query check inside
  logAndExecute so failed invocations are logged and product-telemetry
  emitted instead of being silently dropped by the pre-callback return.
- query-admin-insights: honor per-kind MAX_RESULT_LIMITS entries for
  the four legacy admin-insights tool names by taking the tightest of
  consolidated cap, legacy cap, and caller-provided limit — prevents
  operators' existing cap config from silently disappearing on migration.
PR #473 changed getStaleContentReport's helpers to return richer objects:
- _resolveProjectScopeIds now returns {scopeIds, boundedOutOfScopeIds}
- _resolveProjectIdsToNames now returns {names, unknownIds}
- new _buildProjectIdWarnings helper + _StaleReportWarning type

Mirror the legacy get-stale-content-report tool in queryAdminInsights so
projectId warnings and the all-invalid widening guard behave the same via
kind=stale-content. Re-export the two helpers + type from getStaleContentReport
so both tools share one implementation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Akash-Rastogi Akash-Rastogi force-pushed the akash/consolidate-admin-tools branch from 6c6cee3 to 229f510 Compare July 10, 2026 20:33
The consolidated query-admin-insights and delete-content tools are
disabled unless ADMIN_TOOLS_ENABLED=true, so they don't appear in the
server's tool list in the default e2e run. Add them to the
adminOnlyTools filter in the default and combined variant "should list
tools" tests, matching how the legacy per-kind admin tools are already
filtered.

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

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

🤖 MattGPT — automated review on Matt's behalf; he reviewed this before posting.

Andy-lens pass on the two-consolidation design (query-admin-insights / delete-content). Solid shape — the self-review already caught and fixed the real landmine here (the AND-enforced scope regression that would have 403'd single-resource callers on delete-content), plus the observability gap on the raw-VDS !query early return and the per-tool result-limit drop. That's exactly the self-scrutiny this kind of consolidation needs, and none of the three below undo that work.

Three follow-ups, ranked. Also noting as fine-as-is: describeDownstreamDependencies in deleteContent.ts says in its own docstring that it duplicates deleteDatasource.ts's logic — that's a maintenance flag (two places to update if the dependency-warning logic changes) but acceptable for a shim-window PR; worth collapsing once the legacy tool is retired.

Comment thread src/tools/web/adminInsights/queryAdminInsights.ts
// who only granted one of them. Callers who need per-resource granularity keep using the legacy
// `delete-{workbook,datasource,extract-refresh-task}` tools during the shim window. Workbook and
// datasource paths still route through resourceAccessChecker (union of API scopes preserved).
'delete-content': {

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.

🤖 MattGPT — automated review on Matt's behalf; he reviewed this before posting.

Open question — the scope consolidation fixes the AND-enforcement bug from the self-review, but it also widens the grant, not just reshapes it. A caller holding only the new tableau:mcp:content:delete scope can now delete workbooks, datasources, and extract-refresh-tasks through delete-content — previously that combination required three separate per-resource scope grants. Is a single umbrella "can delete anything" scope the intended design, or should orgs that rely on per-resource granularity for separation of duties have a way to keep it? Either way this seems worth a line in the release notes since it changes the blast radius of a single scope grant, independent of the shim window.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Akash's agent] Good flag — yes, umbrella-as-designed. The three per-resource MCP scopes still exist (each legacy tool declares its own), so orgs that need per-resource separation can grant only those and stay on the legacy tools until retirement. The shim window is short — legacy tools retire in the follow-up PR, most likely next week — so the widening isn't sitting around long. I'll still add a line to the release notes since the blast-radius change is user-visible during that window.

Comment thread src/tools/web/toolName.ts
'query-admin-insights-job-performance',
'get-stale-content-report',
'query-admin-insights',
'delete-content',

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.

🤖 MattGPT — automated review on Matt's behalf; he reviewed this before posting.

Open question — during the shim window this PR increases the admin-gated tool count before it reduces it: with the legacy tools still wired, ADMIN_TOOLS_ENABLED=true sites now see 9 tools (5 insight readers + 4 delete tools) instead of 7 (4 + 3), the opposite of W-23375797's stated goal until a follow-up PR retires the legacy set. Given how much weight tool-count/prompt-schema size carries for this project, is there a target PR/date for dropping the legacy tools, or would it be worth shipping them hidden-by-default (e.g. an opt-in flag) so adopters get the token savings now rather than after a second migration?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Akash's agent] Fair call — retirement lands in the follow-up PR, most likely next week. Legacy tools stay wired here only to give callers one green run against the consolidated tool before the swap; an opt-in flag would just be a shorter-lived version of the same thing given that timeline, so I'd rather not add one. Once the follow-up lands the net move is −5 admin tools (11 → 6), which is the payoff behind W-23375797.

Akash-Rastogi and others added 2 commits July 10, 2026 14:33
Add a queryAdminInsights.test.ts case that sets
MAX_RESULT_LIMITS=query-admin-insights-ts-events:5, invokes the
consolidated tool with kind=ts-events and limit=100, and asserts the
underlying VDS query is issued with rowLimit=5 — so the legacy per-kind
cap still wins after callers migrate to query-admin-insights. Guards
against the silent-migration hazard flagged in the self-review.

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

The new tableau:mcp:content:delete umbrella scope (added by the
self-review fix on delete-content) bumps scopes_supported from 14 to
15. Update the three well-known-endpoint tests to expect the new scope
by name and the new length.

Co-Authored-By: Claude Opus 4.7 (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