# How the Browse Connectors Modal Helps Users Discover MCP Integrations in y-gui

> Discover MCP integrations in y-gui with the browse connectors modal. Easily add new integrations to your local configuration using the curated card interface.

- Repository: [luohy15/y-gui](https://github.com/luohy15/y-gui)
- Tags: how-to-guide
- Published: 2026-03-06

---

**The browse connectors modal queries the y-gui backend at `/api/browse-connectors` to surface available MCP servers, rendering them in a curated card interface where users can add integrations to their local configuration with a single click.**

The y-gui repository (`luohy15/y-gui`) provides a React-based frontend for managing MCP (Model Context Protocol) connections through an intuitive settings panel. The **browse connectors modal** serves as the primary discovery mechanism, bridging the gap between public connector registries and local instance configuration by fetching and displaying available integrations that can be instantly activated without manual JSON editing.

## Triggering the Discovery Interface

Users initiate the discovery flow from the main connectors view. In [`ConnectorSection.tsx`](https://github.com/luohy15/y-gui/blob/main/ConnectorSection.tsx), the component maintains a local `isBrowseModalOpen` state that is toggled when the user clicks the **Browse Connectors** button. When this state becomes `true`, the component renders the `BrowseConnectorsModal` and passes a callback handler for adding servers.

```tsx
<button
  onClick={() => setIsBrowseModalOpen(true)}
  className={`px-3 py-1.5 sm:px-4 sm:py-2 ${isDarkMode ? 'bg-gray-600 hover:bg-gray-700' : 'bg-gray-600 hover:bg-gray-700'} text-white rounded-md text-sm sm:text-base`}
>
  Browse Connectors
</button>

```

*Located in [`frontend/src/components/Settings/ConnectorSection.tsx`](https://github.com/luohy15/y-gui/blob/main/frontend/src/components/Settings/ConnectorSection.tsx) (lines 25‑33).*

## Fetching Available MCP Integrations

When the modal mounts or the `isOpen` prop changes to `true`, a `useEffect` hook triggers the `fetchServers` function. This utility uses the shared `useApi` hook to perform an authenticated GET request to the `/api/browse-connectors` endpoint, retrieving a list of publicly available connector descriptors.

```tsx
useEffect(() => {
  if (isOpen) {
    fetchServers();               // ← runs when modal becomes visible
  }
}, [isOpen]);

const fetchServers = async () => {
  setLoading(true);
  try {
    const response = await api.get('/api/browse-connectors');
    setServers(response.data?.servers || []);
  } finally {
    setLoading(false);
  }
};

```

*From [`frontend/src/components/Settings/BrowseConnectorsModal.tsx`](https://github.com/luohy15/y-gui/blob/main/frontend/src/components/Settings/BrowseConnectorsModal.tsx) (lines 38‑55).*

The backend route is defined in [`backend/src/api/mcp-server.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/api/mcp-server.ts). It currently returns a static array of server objects—including fields like `name`, `author_name`, `description`, and `server_url`—but can be easily swapped to query an external registry without modifying the frontend logic.

```typescript
router.get('/api/browse-connectors', async (req, res) => {
  const servers = [
    {
      uuid: '1',
      name: 'OpenAI',
      author_name: 'OpenAI',
      title: 'OpenAI GPT',
      description: 'Connect to OpenAI GPT models',
      server_key: 'openai',
      config_name: 'openai',
      server_url: 'https://api.openai.com/v1',
      is_openapi: true,
    },
    // ... additional entries
  ];
  res.json(jsonResponse({ servers }));
});

```

*Located in [`backend/src/api/mcp-server.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/api/mcp-server.ts) (lines 103‑121).*

## Rendering the Connector Catalog

Once the data arrives, the modal maps over the `servers` array and renders each integration as a discrete card. Each card displays the connector’s **title**, **author**, and **description**, alongside an **Add** button that initiates the installation flow. This presentation layer decouples the discovery UI from the persistence logic, keeping the modal focused solely on selection.

The rendering logic iterates over the state populated by `fetchServers`:

```tsx
{servers.map((server) => (
  <div key={server.uuid} className="...">
    <h3>{server.title}</h3>
    <p>{server.description}</p>
    <span>{server.author_name}</span>
    <button onClick={() => handleAddServer(server)}>Add</button>
  </div>
))}

```

*Adapted from the rendering loop in [`BrowseConnectorsModal.tsx`](https://github.com/luohy15/y-gui/blob/main/BrowseConnectorsModal.tsx) (lines 19‑53).*

## Adding Connectors to Your Configuration

When a user clicks **Add**, the `handleAddServer` function transforms the API response into the internal `McpServer` type required by y-gui’s state management. It constructs an object with `name`, `url`, `status`, and `is_default` fields, then invokes the `onAddServer` callback passed down from `ConnectorSection`.

```tsx
const handleAddServer = async (serverFromAPI: ServerFromAPI) => {
  setAddingServer(serverFromAPI.name);
  const mcpServer: McpServer = {
    name: serverFromAPI.config_name || serverFromAPI.name,
    url: serverFromAPI.server_url,
    status: 'disconnected',
    is_default: false,
  };
  await onAddServer(mcpServer);   // passes to ConnectorSection
  onClose();                      // closes modal
  setAddingServer(null);
};

```

*From [`frontend/src/components/Settings/BrowseConnectorsModal.tsx`](https://github.com/luohy15/y-gui/blob/main/frontend/src/components/Settings/BrowseConnectorsModal.tsx) (lines 58‑71).*

## Persisting New Connections

The `ConnectorSection` component implements `handleAddServerFromBrowse` to receive the new `McpServer` object. It POSTs the payload to `/api/mcp-server`, displays a success toast via `setStatusMessage`, and triggers `mutateConnectors()` to revalidate the local cache. This SWR mutation ensures the UI refreshes immediately, showing the newly added connector in the main list without a page reload.

```tsx
const handleAddServerFromBrowse = async (server: McpServer) => {
  await api.post('/api/mcp-server', server);
  setStatusMessage({ type: 'success', text: `Connector "${server.name}" added successfully` });
  mutateConnectors();             // refresh list
};

```

*Located in [`frontend/src/components/Settings/ConnectorSection.tsx`](https://github.com/luohy15/y-gui/blob/main/frontend/src/components/Settings/ConnectorSection.tsx) (lines 84‑95).*

## Summary

- The **browse connectors modal** is triggered via `setIsBrowseModalOpen` in [`ConnectorSection.tsx`](https://github.com/luohy15/y-gui/blob/main/ConnectorSection.tsx), rendering only when the user explicitly requests discovery.
- It fetches the catalog from the `/api/browse-connectors` endpoint defined in [`backend/src/api/mcp-server.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/api/mcp-server.ts), which can be backed by a static list or external registry.
- The modal displays server metadata—title, author, and description—in a card-based layout generated by mapping the `servers` state.
- The `handleAddServer` function transforms API-specific fields into the canonical `McpServer` interface before passing the object upward.
- Persistence occurs in `ConnectorSection` through `handleAddServerFromBrowse`, which POSTs to `/api/mcp-server` and calls `mutateConnectors()` to update the UI.

## Frequently Asked Questions

### What endpoint powers the connector discovery feature?

The modal queries `/api/browse-connectors`, a REST endpoint mounted in [`backend/src/api/mcp-server.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/api/mcp-server.ts). This route returns a JSON payload containing an array of available server descriptors, which the frontend consumes to populate the discovery list.

### How does the modal transform external connector data into local configuration objects?

The `handleAddServer` function in [`BrowseConnectorsModal.tsx`](https://github.com/luohy15/y-gui/blob/main/BrowseConnectorsModal.tsx) maps fields from the API response—such as `config_name` and `server_url`—into the `McpServer` interface, setting default values for `status` (`'disconnected'`) and `is_default` (`false`) before invoking the parent’s add handler.

### Where is the new connector persisted after a user clicks Add?

The `handleAddServerFromBrowse` method in [`ConnectorSection.tsx`](https://github.com/luohy15/y-gui/blob/main/ConnectorSection.tsx) receives the transformed `McpServer` object and sends it to the backend via `POST /api/mcp-server`. After a successful response, it calls `mutateConnectors()` to refresh the SWR cache and update the visible connector list.

### Can the backend serve dynamic connector lists instead of static data?

Yes. The current implementation in [`backend/src/api/mcp-server.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/api/mcp-server.ts) uses a hardcoded array for demonstration, but the route handler can be modified to query a database or external registry service. Because the frontend expects only the standard `{ servers: [...] }` envelope, no changes are required in [`BrowseConnectorsModal.tsx`](https://github.com/luohy15/y-gui/blob/main/BrowseConnectorsModal.tsx) to support dynamic sources.