feat: surface catalog entries in header search - #26
Open
gandhipratik203 wants to merge 1 commit into
Open
Conversation
The header quick-search never returned MCP server catalog entries because it never requested them. Add catalog as a searchable entity type, route its results to the catalog page, and label the group with the existing sidebar string. No change is needed on the catalog page: it already reads ?search= from the URL on load, so a result click deep-links into a filtered grid. Inert until IBM/mcp-context-forge#6212 adds catalog to the backend's supported entity types. Unrecognised types are dropped server-side, so this cannot affect search before then. Closes #20 Signed-off-by: Pratik Gandhi <gandhipratik203@gmail.com>
marekdano
approved these changes
Aug 14, 2026
marekdano
left a comment
Contributor
There was a problem hiding this comment.
@gandhipratik203 - thanks for the PR
It looks good! LGTM 🚀
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The header quick-search never returned MCP server catalog entries because it never asked for them. This adds
catalogas a searchable entity type, routes its results to the catalog page, and labels the group using the existing sidebar string.Closes #20.
Changes
src/api/search.ts"catalog"added to theSearchEntityTypeunionsrc/components/layout/HeaderQuickNav.tsx"catalog"added toBASE_SEARCH_ENTITY_TYPES,ENTITY_ROUTE(/app/server-catalog) andENTITY_LABEL_KEY(navigation.serverCatalog)Three lines of source. Both
Record<SearchEntityType, string>maps are exhaustive, so the compiler required the route and label entries as soon as the union grew.No i18n work —
navigation.serverCatalogalready exists in en-US, es-ES and pt-BR.No change to
ServerCatalog.tsx—buildDestinationalready appends?selected=…&search=…, and the catalog page readssearchfrom the URL on load, so a result click deep-links into a filtered grid.Inert until the backend lands
Depends on IBM/mcp-context-forge#6212, which adds
catalogtosupported_entity_typesinperform_unified_search.It cannot regress current search. The gateway filters requested entity types against a whitelist (
mcpgateway/admin.py:11618) and silently drops unrecognised ones; the only 400 is when every requested type is invalid (line 11631). This request always carries the seven existing valid types alongsidecatalog, so until #6212 ships the extra type is dropped server-side and search behaves exactly as it does today. When the backend lands, catalog results start appearing with no further frontend deploy.Verified against the backend PR
IBM/mcp-context-forge#6245 (
fix(search): include opt-in catalog results) implements #6212. Checked this branch against its diff — all three assumptions hold and no frontend change is needed:catalogsupported_entity_typesgains"catalog"; results land ingrouped_results["catalog"]{id, name, description}[{"id": server.id, "name": server.name, "description": server.description} for server in catalog_response.servers]groups[]asentity_type: "catalog"groupsis assembled generically fromgrouped_results, same envelope as every other typeThree further behaviours from that PR, none needing frontend handling:
servers.read(allow_admin_bypass=False). On denial_safe_entity_searchcatches 401/403 and returns an empty payload, so the group is simply absent rather than erroring. Worth knowing when testing: a user without that permission sees no catalog results, and that is not a bug in this change.default_entity_typesand must be requested explicitly — which is exactly what this PR does, leaving/admin/searchand other clients untouched.MIN_QUERY_LENGTH = 2, so an empty query is never sent.Test results
HeaderQuickNav.test.tsx: 28 passed, up from 26./app/server-catalog?selected=<id>&search=<query>.entityTypesrequest now includescatalog, which doubles as proof the type is actually requested.npm run lint,npm run format:check: clean.Typecheck:
tsc --noEmit -p tsconfig.app.jsonclean. Confirmed the exhaustiveness claim rather than assuming it — temporarily removing theENTITY_ROUTEentry producesTS2741: Property 'catalog' is missing ... but required in type 'Record<SearchEntityType, string>', so the compiler enforces the route and label entries.Real-browser verification (Playwright against the dev bundle,
/v1/searchmocked with the exact payload #6245 emits) — 10/10 checks:entity_types=servers,gateways,tools,resources,prompts,agents,teams,catalog— catalog is requested, and the seven existing types still ride along./app/server-catalog?selected=cloudflare-docs&search=cloudflare.Still unverified against a live gateway — #6245 is open, not merged. Once it lands this needs a five-minute check with the real backend.
Manual verification
Manual test steps
Setup
Two terminals:
Terminal B opens a Chrome for Testing window with
/auth/session,/v1/searchand/v1/catalogmocked. Ctrl-C in terminal B to close. Do everything in that window, in the tab it opens.The Home page shows an "Error loading dashboard sources" banner - the dashboard's endpoints aren't mocked, unrelated to search.
Steps
1. Click the magnifier in the top header bar (or press Cmd/Ctrl+K).
Expect: the search field expands.
2. Type
cloudflare.Expect: two groups - MCP SERVERS (count 1) and SERVER CATALOG (count 2), each row showing a name and description.
3. Look at terminal B.
Expect:
search "cloudflare" entity_types=servers,gateways,tools,resources,prompts,agents,teams,catalog,users.usersappears because the mock user is a platform admin.4. Press the down arrow several times.
Expect: the highlight moves through the MCP SERVERS row and into both SERVER CATALOG rows; Enter opens the highlighted one.
5. Click Cloudflare Docs.
Expect: URL becomes
/app/server-catalog?selected=cloudflare-docs&search=cloudflare.6. Look at the catalog page.
Expect: toolbar search pre-filled with
cloudflare; grid filtered to Cloudflare Docs and Cloudflare Radar; the other three seeded servers gone.7. Optional - search
zzz.Expect: a clean "no results" state, not an empty dropdown or an error.
Teardown
Ctrl-C both terminals. If :5173 is stuck:
lsof -ti:5173 | xargs kill.Manual test results
Run against
feat/20-header-search-catalogat65f3067, branched frommainatb42f5e8.cloudflareentity_types=...,teams,catalog,users- catalog requested, existing types intact/app/server-catalog?selected=cloudflare-docs&search=cloudflarezzzTwo observations, neither blocking:
selectedis unused by the catalog page, which only readssearch. Deliberate per the issue, which treats the?search=deep link as sufficient. Opening the details dialog for the selected entry would be a follow-up.mainatb42f5e8with a gateways-only search and no catalog involved. Worth filing separately.Scope of this verification: search responses are mocked, so this covers frontend wiring only - request, grouping, labelling, keyboard nav, routing, deep-link handoff. It does not verify that the real backend returns catalog entries; IBM/mcp-context-forge#6245 is still open.
Mock script (quicknav-manual.mjs)
Save at the repo root. Requires
@playwright/test, already a dev dependency; runnpx playwright install chromiumif the browser is missing.