Skip to content

feat(ui): MCP tool refresh button#3802

Open
gcgoncalves wants to merge 2 commits intomainfrom
3765-mcp-refresh-button
Open

feat(ui): MCP tool refresh button#3802
gcgoncalves wants to merge 2 commits intomainfrom
3765-mcp-refresh-button

Conversation

@gcgoncalves
Copy link
Collaborator

✨ Feature / Enhancement PR

🔗 Epic / Issue

Closes #3765


🚀 Summary (1-2 sentences)

Adds buttons for refreshing an MCP server's tools

Screenshot 2026-03-20 at 22 29 34 Screenshot 2026-03-20 at 23 24 53 Screenshot 2026-03-20 at 23 25 18

🧪 Checks

  • make lint passes
  • make test passes
  • CHANGELOG updated (if user-facing)

📓 Notes (optional)

Piggybacks (partially) #3519, to prevent an overclutered actions section

flowchart TD
    A[Client] -->|POST /gateway/gateway_id/refresh/tools| B(MCPGateway)
    B -->|/tools/list| C[MCP]
    B -->|Response - HTMX| A
Loading

@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch from d9e97a1 to 0ef3f89 Compare March 23, 2026 15:35
@gcgoncalves gcgoncalves marked this pull request as ready for review March 23, 2026 15:35
@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch 3 times, most recently from 42e28fd to 0f7bf73 Compare March 23, 2026 15:43
@gcgoncalves gcgoncalves changed the title [FEATURE][UI]: MCP tool refresh button feat(ui): MCP tool refresh button Mar 23, 2026
@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch 2 times, most recently from 1cc8717 to 5850a18 Compare March 24, 2026 09:27
@marekdano
Copy link
Collaborator

Reviewing - there is an issue with the tooltip for the Refresh from MCPs button, which is behind the Edit modal
Screenshot 2026-03-24 at 12 01 47

@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch from b80501d to 0fa8ac1 Compare March 24, 2026 13:27
@gcgoncalves
Copy link
Collaborator Author

Reviewing - there is an issue with the tooltip for the Refresh from MCPs button, which is behind the Edit modal

Addressed.

Screenshot 2026-03-24 at 13 28 45

Copy link
Collaborator

@marekdano marekdano left a comment

Choose a reason for hiding this comment

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

Summary:
This PR successfully implements the refresh tools feature and overflow menu, but has some implementation concerns that should be addressed before merging.

Issues to Address

Medium Priority:

  1. Fragile relationship loading check (mcpgateway/services/gateway_service.py:4160)
tools_rel = gateway.__dict__.get("tools")
gateway_dict["tool_count"] = len(tools_rel) if tools_rel is not None else 0
  • Using dict.get() is SQLAlchemy-internal and fragile
  • If selectinload is removed elsewhere, tool counts silently become 0 with no error
  • Fix: Use inspect(gateway).attrs["tools"].loaded_value (official SQLAlchemy API) or add a clear comment explaining why dict is used
  1. Test scoping inconsistency (tests/playwright/test_gateways.py:545)
activate_btn = first_row.locator('button:text-is("Activate")')
deactivate_btn = first_row.locator('button:has-text("Deactivate")')
  • After refactor, these buttons are inside dropdown but test still scopes to first_row
  • Fix: Change to dropdown.locator() for consistency with other assertions in same test

Low Priority / Polish:

  1. Defensive check could be clearer (mcpgateway/static/admin.js:~146)
  • typeof getSelectedGatewayIds === "function" check silently returns [] if function missing
  • Consider logging warning if function doesn't exist
  1. UX improvement opportunity
  • When all delta counts are 0, showing "0 added, 0 updated, 0 removed" is technically correct but could be friendlier
  • Consider "No changes detected" message for better UX (can be follow-up)
  1. Keyboard navigation gap
  • Overflow menu lacks Escape key to close and arrow key navigation
  • Minor a11y gap (can be follow-up issue)

What's Good

✅ Smart label toggling based on tool_count
✅ Proper eager loading with selectinload(DbGateway.tools)
✅ Good error handling in JavaScript
✅ Comprehensive test updates
✅ Proper accessibility attributes (role, aria-expanded)
✅ Well-written CHANGELOG
✅ No security concerns

@gcgoncalves
Copy link
Collaborator Author

Summary: This PR successfully implements the refresh tools feature and overflow menu, but has some implementation concerns that should be addressed before merging.
...

@marekdano Addressed.

@gcgoncalves gcgoncalves requested a review from marekdano March 24, 2026 14:12
Copy link
Collaborator

@vishu-bh vishu-bh left a comment

Choose a reason for hiding this comment

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

Change introduces a browser-triggered mutation on a non-admin API route (POST /gateways/{gateway_id}/tools/refresh) while the existing CSRF protection is scoped to admin_router. The new UI path calls the route with cookie credentials from mcpgateway/static/admin.js (mcpgateway/static/admin.js#L20848), but the route itself lives in mcpgateway/main.py (mcpgateway/main.py#L6573) rather than under the admin router where enforce_admin_csrf is applied (mcpgateway/admin.py (mcpgateway/admin.py#L1570)).

Under the default SameSite=Lax cookie setting this is probably not a classic arbitrary cross-site POST issue, but it still bypasses the app’s explicit CSRF boundary and becomes relevant in same-site cross-origin deployments or when COOKIE_SAMESITE=none is used. Would it make sense to add a small cookie-auth CSRF check on this route, while still allowing bearer-token API callers, so the admin UI action stays aligned with the existing CSRF model?

@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch 2 times, most recently from e2ac8c9 to c818a57 Compare March 24, 2026 14:44
@vishu-bh
Copy link
Collaborator

Also noticed a cosmetic behaviour for the action button in table.

Screen.Recording.2026-03-24.at.14.41.37.mov

@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch from c818a57 to 737b8ee Compare March 24, 2026 15:04
@gcgoncalves
Copy link
Collaborator Author

Also noticed a cosmetic behaviour for the action button in table.

Screen.Recording.2026-03-24.at.14.41.37.mov

@vishu-bh Addressed.

Screen.Recording.2026-03-24.at.15.03.34.mov

@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch from 737b8ee to 8f37574 Compare March 24, 2026 15:05
@gcgoncalves gcgoncalves requested a review from vishu-bh March 24, 2026 15:05
@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch from 8f37574 to 9475ebb Compare March 24, 2026 16:36
Closes #3765
Closes #3519

Adds a Fetch/Refresh Tools action to the gateways table for all gateway
auth types, not just OAuth. The label reads "Fetch Tools" on first use
(no tools registered yet) and switches to "Refresh Tools" once tools
exist, using the existing POST /gateways/{id}/tools/refresh endpoint.
On success, a toast shows the delta counts (added / updated / removed)
and the table reloads via HTMX.

A matching "Refresh from MCPs" button is added to the virtual server
edit form so users can pull the latest tools from selected gateways
without leaving the modal.

To support the contextual label, tool_count is added to GatewayRead
(serialised as toolCount) and DbGateway.tools is eagerly loaded in
the gateways partial query to avoid N+1 queries.

As a piggyback improvement, the stacked action buttons in the gateways
table are replaced with an Alpine.js overflow menu (...), housing all
actions including the new refresh button.

Signed-off-by: Gabriel Costa <gabrielcg@proton.me>
Signed-off-by: Gabriel Costa <gabrielcg@proton.me>
@gcgoncalves gcgoncalves force-pushed the 3765-mcp-refresh-button branch from 9475ebb to 8f533f3 Compare March 24, 2026 16:53
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.

[FEATURE][UI]: MCP tool refresh button

3 participants