Skip to content

feat(ui): unified admin search with tags + global search#2868

Merged
crivetimihai merged 15 commits intomainfrom
2109-unified-search
Feb 16, 2026
Merged

feat(ui): unified admin search with tags + global search#2868
crivetimihai merged 15 commits intomainfrom
2109-unified-search

Conversation

@crivetimihai
Copy link
Copy Markdown
Member

@crivetimihai crivetimihai commented Feb 12, 2026

Summary

Implements a unified, consistent search experience across the MCP Gateway Admin UI, including tag-based filtering, server-side panel search, and a global cross-entity
search modal (Ctrl/Cmd+K).

Key Changes

  • Standardized search behavior and payloads across admin search endpoints
  • Unified response shape includes items, count, entity_type, query, filters_applied, while preserving legacy keys (tools, gateways, etc.) for backwards compatibility.
  • Added tag filtering support via tags query param using comma=OR and plus=AND semantics.
  • Server-side search for main Admin UI panels (no more “current page only” client filtering)
  • Panels now reload via HTMX against their /admin/*/partial endpoints with debounced search.
  • Search and tag filters persist via namespaced URL params (_q,
    _tags) and are preserved through pagination and “include inactive” toggles.
  • Global search (Ctrl/Cmd+K)
  • New GET /admin/search endpoint aggregates results across:
    • servers, gateways, tools, resources, prompts, agents, plus teams and users.
  • Supports entity_types filtering and limit_per_type (alias for per-entity limit).
  • Admin header now includes a Search button and modal; click or Ctrl/Cmd+K to open, Esc to close, Enter opens the first result.
  • Clicking results navigates to the correct tab and opens the relevant details/edit modal.
  • Teams search response standardized
  • /admin/teams/search now returns a wrapped payload (consistent with other search endpoints) and supports matching on name, slug, and description.
  • Minor docs
  • Roadmap entry quote normalization (existing file change included in this PR).
  • Tag Filter Syntax

    • tags=prod,staging matches items with prod OR staging
    • tags=prod+api matches items with BOTH prod AND api
    • Tags-only search is supported (empty q + non-empty tags)

    Tests / Verification

    • make flake8
    • make pylint
    • make lint-web
    • pytest -q tests/unit/mcpgateway/test_admin.py tests/unit/mcpgateway/test_admin_module.py
    • npx vitest run

    Notes

    • API change: /admin/teams/search no longer returns a bare array; it now returns a wrapped unified payload.

    Closes #2076
    Closes #2109

    Also closes #2965 found during testing.

@crivetimihai crivetimihai self-assigned this Feb 12, 2026
@crivetimihai crivetimihai added ui User Interface ica ICA related issues labels Feb 12, 2026
@crivetimihai crivetimihai added this to the Release 1.0.0-GA milestone Feb 12, 2026
@madhav165
Copy link
Copy Markdown
Collaborator

Tested it locally, works as expected. For servers with lots of tools with similar names, returns 8 tools, 8 prompts, 8 resources.

One suggestion from review - consider adding timeout to multiple async calls made for search so slow endpoints don't block the UI.

Implement a unified, consistent search experience across the Admin UI:

- Standardize search endpoints with unified response shape (items, count,
  entity_type, query, filters_applied) while preserving legacy keys
- Add tag filtering via comma=OR and plus=AND semantics with bounds
  (max 20 groups, 10 terms per group)
- Server-side panel search for all entity panels via HTMX partial reloads
  with debounced input and namespaced URL params for shareability
- Global search modal (Ctrl/Cmd+K) aggregating results across servers,
  gateways, tools, resources, prompts, agents, teams, and users
- Escape SQL LIKE wildcards in all search filters to prevent injection
- Consistent search field coverage between search and partial endpoints

Closes #2076
Closes #2109

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…ti-app tests

Guard setup_metrics() against re-registration errors when multiple
FastAPI apps are instantiated in the same process (e.g., test suites).
Uses best-effort registry lookup via _get_registry_collector() to
reuse existing collectors instead of crashing on ValueError.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add _get_user_team_ids helper with caching support. The unified search
endpoint pre-fetches team IDs once and injects them into the user context,
avoiding 6 redundant database lookups (one per entity type).

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai marked this pull request as ready for review February 15, 2026 20:22
…search waits

SQLAlchemy .contains() does not add an ESCAPE clause, so escaped
wildcards (\_) are treated as literal two-character sequences on SQLite.
Replace all .contains(_escape_like(...)) calls with _like_contains()
which generates .like(..., escape='\\') for correct behaviour on all
database backends.

Update Playwright page objects and tests to wait for the HTMX partial
responses now that search is server-side instead of client-side.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai merged commit adf8131 into main Feb 16, 2026
54 checks passed
@crivetimihai crivetimihai deleted the 2109-unified-search branch February 16, 2026 10:14
Copy link
Copy Markdown
Collaborator

@jonpspri jonpspri left a comment

Choose a reason for hiding this comment

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

This is a solid, well-tested feature PR that significantly improves the admin search experience. The main concerns are:

  • inconsistent admin_search_teams response shape
  • remaining inline oninput handler in the template
  • sequential entity queries in unified search

I will file an issue for follow-up on these items.

None of these are blockers. The security improvements (LIKE escaping, XSS prevention, token team scoping) are all correct and well-tested.

@IuliaGaitan
Copy link
Copy Markdown
Collaborator

Test on local environment.

Test Case ID Scenario Description Search Scope Input Data Expected Result Actual Result Status
Single Entity Searches
TC-001 Search servers only S "deactivate-test-server" Server results only Matches expected
TC-002 Search gateways only G "github-com" Gateway results only Matches expected
TC-003 Search tools only T "issue comment" Tool results only Matches expected
TC-004 Search resources only R "resouce" Resource results only Matches expected
TC-005 Search prompts only P "prompt" Prompt results only Matches expected
TC-006 Search agents only A "agent_007" Agent results only Matches expected
TC-007 Search agents-to-agents + tools T+ A2A "test-agent" A2A results only Matches expected
TC-008 Search teams only Tm "Iulia" Team results only Matches expected
TC-009 Search roots only Ro "Resource" Root results only No matches shown 🔴
TC-010 Search users only U "inactive" Users results only No matches shown 🔴
Selected Combination Searches
TC-011 Tools + Gateways T+G "github" Tools & Gateway results Matches expected
TC-012 Tools + Gateways + Resources G+T+R "gtihub" Gateways & Tool & Resources results Matches expected
TC-013 Tools + Gateways + Resources + Roots G+T+R+Ro "gtihub" Gateways & Tool & Resources & Roots results No matches 🔴
TC-014 Teams + Users G+P "Iulia" Teams & Users results No matches 🔴
TC-015 Tools + Resources T+R "report" Tool & Resource results Matches expected
TC-016 Tools + Agents-to-Agents T+A2A "test-agent" Tool & A2A results Matches expected
TC-017 Resources + Prompts R+P "training" Resource & Prompt results Matches expected
TC-018 Prompts + Teams P+Tm "project kickoff" Prompt & Team results Matches expected
TC-019 Teams + Roots Tm+Ro "root access" Team & Root results Matches expected
TC-020 Gateways + Tools + Agents G+T+A "deploy" All 3 return results Matches expected
TC-021 Tools + Resources + Prompts T+R+P "AI" All 3 return results Matches expected
TC-022 Gateways + Resources + Agents S+G+R+A "status" All 4 return results Matches expected
TC-023 Gateways + Tools + Resources + Prompts + Agents S+T+R+P+A "update" All 5 return results Matches expected
TC-024 All entities S+G+T+R+P+A+A2A+Tm+Ro+U "version" Results from all categories No matches 🔴
Edge Cases
TC-025 Empty search query All "" Show error or "Please enter a search term" No message shwon 🔴
TC-026 Search with no matching results All "xyz12345" "No results found" message Matches expected
TC-027 Search with partial match All "serv" All matching items containing "serv" returned Matches expected
TC-028 Search with case sensitivity test All "Server" vs "server" Both return same results Matches expected
TC-029 Search with special characters All "!2026!" Proper handling, no crash Matches expected
TC-030 Search with permission restrictions All "admin" Restricted results hidden Matches expected
TC-031 Search with deactivated gateways G "github" Only activated gateways return results Matches expected
TC-032 Search with deactivated A2A agents A2A "test-agent" Only online A2A agents return results Matches expected

vishu-bh pushed a commit that referenced this pull request Feb 18, 2026
* feat(ui): unified admin search with tags + global search

Implement a unified, consistent search experience across the Admin UI:

- Standardize search endpoints with unified response shape (items, count,
  entity_type, query, filters_applied) while preserving legacy keys
- Add tag filtering via comma=OR and plus=AND semantics with bounds
  (max 20 groups, 10 terms per group)
- Server-side panel search for all entity panels via HTMX partial reloads
  with debounced input and namespaced URL params for shareability
- Global search modal (Ctrl/Cmd+K) aggregating results across servers,
  gateways, tools, resources, prompts, agents, teams, and users
- Escape SQL LIKE wildcards in all search filters to prevent injection
- Consistent search field coverage between search and partial endpoints

Closes #2076
Closes #2109

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(metrics): prevent duplicate Prometheus metric registration in multi-app tests

Guard setup_metrics() against re-registration errors when multiple
FastAPI apps are instantiated in the same process (e.g., test suites).
Uses best-effort registry lookup via _get_registry_collector() to
reuse existing collectors instead of crashing on ValueError.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): eliminate redundant get_user_teams calls in unified search

Add _get_user_team_ids helper with caching support. The unified search
endpoint pre-fetches team IDs once and injects them into the user context,
avoiding 6 redundant database lookups (one per entity type).

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): use ESCAPE clause for LIKE queries and update Playwright search waits

SQLAlchemy .contains() does not add an ESCAPE clause, so escaped
wildcards (\_) are treated as literal two-character sequences on SQLite.
Replace all .contains(_escape_like(...)) calls with _like_contains()
which generates .like(..., escape='\\') for correct behaviour on all
database backends.

Update Playwright page objects and tests to wait for the HTMX partial
responses now that search is server-side instead of client-side.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* format

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(tests): use networkidle wait for HTMX search in Playwright tests

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): format replaceChild call for Prettier compliance

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Code review

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Code review

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Code review

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Test networkwait fix

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Linting and permissions updates

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Linting and permissions updates

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Linting and test updates + fix UI logout issue

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* flake8

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Vishu Bhatnagar <vishu.bhatnagar@ibm.com>
cafalchio pushed a commit that referenced this pull request Feb 26, 2026
* feat(ui): unified admin search with tags + global search

Implement a unified, consistent search experience across the Admin UI:

- Standardize search endpoints with unified response shape (items, count,
  entity_type, query, filters_applied) while preserving legacy keys
- Add tag filtering via comma=OR and plus=AND semantics with bounds
  (max 20 groups, 10 terms per group)
- Server-side panel search for all entity panels via HTMX partial reloads
  with debounced input and namespaced URL params for shareability
- Global search modal (Ctrl/Cmd+K) aggregating results across servers,
  gateways, tools, resources, prompts, agents, teams, and users
- Escape SQL LIKE wildcards in all search filters to prevent injection
- Consistent search field coverage between search and partial endpoints

Closes #2076
Closes #2109

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(metrics): prevent duplicate Prometheus metric registration in multi-app tests

Guard setup_metrics() against re-registration errors when multiple
FastAPI apps are instantiated in the same process (e.g., test suites).
Uses best-effort registry lookup via _get_registry_collector() to
reuse existing collectors instead of crashing on ValueError.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): eliminate redundant get_user_teams calls in unified search

Add _get_user_team_ids helper with caching support. The unified search
endpoint pre-fetches team IDs once and injects them into the user context,
avoiding 6 redundant database lookups (one per entity type).

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): use ESCAPE clause for LIKE queries and update Playwright search waits

SQLAlchemy .contains() does not add an ESCAPE clause, so escaped
wildcards (\_) are treated as literal two-character sequences on SQLite.
Replace all .contains(_escape_like(...)) calls with _like_contains()
which generates .like(..., escape='\\') for correct behaviour on all
database backends.

Update Playwright page objects and tests to wait for the HTMX partial
responses now that search is server-side instead of client-side.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* format

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(tests): use networkidle wait for HTMX search in Playwright tests

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(admin): format replaceChild call for Prettier compliance

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Code review

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Code review

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Code review

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Test networkwait fix

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Linting and permissions updates

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Linting and permissions updates

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* Linting and test updates + fix UI logout issue

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* flake8

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ica ICA related issues ui User Interface

Projects

None yet

4 participants