Skip to content

Support large MCP portal catalogs - #170

Draft
dcartertwo wants to merge 3 commits into
feature/mcp-progressive-discoveryfrom
feature/mcp-portal-large-catalogs
Draft

Support large MCP portal catalogs#170
dcartertwo wants to merge 3 commits into
feature/mcp-progressive-discoveryfrom
feature/mcp-portal-large-catalogs

Conversation

@dcartertwo

Copy link
Copy Markdown
Collaborator

Depends on #169.

A portal can aggregate more metadata than Gadgets can safely retain, and one upstream server can exceed the detailed catalog budget by itself. The connector therefore surveys a compact portal index for server membership and consent labels, while loading detailed definitions only for the selected upstream server.

A grant always names one portal server, either server-wide or as up to 200 named tools. Portal-native session-management tools remain ungrantable, and tools outside the generated preview use the shared progressive discovery path.

The portal must expose direct tools. Default-on Code Mode deployments can opt this client out with ?codemode=off; enforced Code Mode and optimize_context are unsupported. This PR does not enable CF Portal in any deployment.

@github-actions github-actions Bot added mcp/shared Changes to shared MCP integration code gatekeeper Changes to a gatekeeper integration labels Aug 12, 2026
@ask-bonk

ask-bonk Bot commented Aug 12, 2026

Copy link
Copy Markdown

Signature matches. The classification-from-index design correctly resolves the security defect the tests describe (labels derived from annotations, which the index carries, not from whether the detailed fetch reached the tool).

I've completed a thorough review. The change is well-designed and the kernel-adjacent security boundaries hold. Let me summarize findings. I found no actionable defects — the concerns I investigated (truncation fail-safe in the mint path, bounded requestedTools.size, classification-source correctness, dangling imports, auth-transition handling) all check out.

LGTM!

Summary of what I verified:

  • Mint path (getGatekeeperClassFor) — the security-critical resource minting in portal.ts:373-406. Named-tool grants are validated with listMatchingToolIndex(requestedTools.size, ...); requestedTools.size is bounded ≤200 by parseToolScope's MAX_TOOLS_PER_SERVER guard, and any truncation (byte budget or scan limit) causes validateToolScopeAgainstCatalog to throw rather than silently mint an under-validated grant. Server-wide grants for unreported servers require one prefixed-tool proof, and an empty/truncated result fails closed. The listedServers === null branch still proves portal capability via findTool before minting.
  • Classification correctnesstoolGrantOptions derives read-only/needs approval labels from the bounded index's annotations, never from whether the detailed catalog reached the tool. This is the defect the new tests pin down, and it's handled correctly (including vetted/byo parity — the form never claims auto-approval).
  • Auth handlingportalAuthRequiresReconnect's new asymmetry (oauth-configured may prove public; explicit none stays strict) matches the updated tests. #configurationRevision/invalidateConnectionState correctly detect token rotation and clear captured credentials/session state. The allowsOAuthCallback gate correctly drops pending auth state when config no longer permits it.
  • No dangling references — removed helpers (fetchPortalServers, scopeAllows, classifyTool, requireCompleteCatalogForToolSelection) survive only in prose comments; all newly-referenced shared exports exist with matching signatures.
  • Configurator UX — the new "empty" endpoint state and ?codemode=off guidance are consistent between .d.ts, the UI, and the updated tests.

I could not run pnpm build/types:check because dependencies aren't installed in this read-only environment, but static review of all cross-package references was consistent.

github run

@dcartertwo
dcartertwo force-pushed the feature/mcp-portal-large-catalogs branch 2 times, most recently from 28c41bc to be0ac7f Compare August 12, 2026 15:59
@ask-bonk

ask-bonk Bot commented Aug 12, 2026

Copy link
Copy Markdown

All signatures match. I've completed a thorough review. Let me consolidate my findings.

Assessment

The change is well-designed and the kernel-adjacent security boundaries hold. I verified:

Mint path (getGatekeeperClassFor, portal.ts:392-430) — the security-critical resource minting:

  • Named-tool grants: requestedTools.size is bounded ≤200 by parseToolScope's MAX_TOOLS_PER_SERVER guard; listMatchingToolIndex(size, filter) collects only matching entries and validateToolScopeAgainstCatalog throws on any absent tool (and specifically on truncated when a name is missing), so truncation fails closed rather than silently minting.
  • Reported server-wide grants use { tools: [], truncated: false } and resolve via reportedServers.
  • Unreported server-wide grants require one prefixed-tool proof, and an empty result throws "absent from catalog" — fail-closed.
  • The listedServers === null branch still proves portal capability via findTool(PORTAL_LIST_SERVERS_TOOL) before minting.

Classification correctnesstoolGrantOptions derives read-only/needs approval from the bounded index's annotations via classifyAnnotations, never from whether the detailed catalog reached the tool. This is exactly the defect the new tests pin down (with vetted/byo parity — the form never claims auto-approval). Signatures match (IndexedTool.annotations, classifyAnnotations(annotations, trust)).

Auth transitions (account.ts) — the new allowsOAuthFallback/allowsOAuthCallback hooks default open in the base, and the portal narrows them (auth !== "none"; oauth-config + same-endpoint). Both new throw/return paths call restoreSelection/clear pending state consistently with surrounding code. portalAuthRequiresReconnect's new asymmetry (oauth-configured may prove public; explicit none stays strict) matches the updated tests. getConnection's revision check advances generation before super.getConnection re-reads it — consistent.

No dangling references — all newly-referenced shared exports (listMatchingToolIndex, fetchToolIndex, IndexedTool, ToolIndex, isValidToolName, toolBelongsToServer, hexEncode, classifyAnnotations, MAX_TOOLS_PER_SERVER) exist with matching signatures. Removed helpers survive only in prose.

Configurator UX — the new "empty" endpoint state and ?codemode=off guidance are consistent across .d.ts, the UI, and tests. The "up to 200 shown" copy matches the MAX_TOOLS_PER_SERVER slice in toolGrantOptions.

I could not run pnpm build/types:check/pnpm test (read-only environment, dependencies not installed), but static review of all cross-package references and the test expectations was consistent. I found no actionable defects.

LGTM!

github run

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

Labels

gatekeeper Changes to a gatekeeper integration mcp/shared Changes to shared MCP integration code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant