MCP Registry Discovery in TUUI: How It Works and Integrates with the UI
TUUI discovers MCP servers by querying the public MCP Registry API at registry.modelcontextprotocol.io, then renders the results through a Vue-based card component wrapped in a dialog interface.
The ai-ql/tuui repository implements a lightweight discovery mechanism that connects to the official MCP Registry to fetch available Model Context Protocol servers. This article explains how the RegistryCard.vue component handles API communication, pagination, and UI integration within the TUUI application.
How TUUI Discovers MCP Servers via the Registry
Querying the MCP Registry API
The discovery flow begins in src/renderer/components/common/RegistryCard.vue, where the fetchJson() function constructs a targeted request to the registry endpoint:
// RegistryCard.vue – lines 49-55
const baseUrl = 'https://registry.modelcontextprotocol.io/v0/servers'
const url = new URL(baseUrl)
if (search) url.searchParams.append('search', search)
url.searchParams.append('limit', queryLimit)
url.searchParams.append('version', 'latest')
if (cursor) url.searchParams.append('cursor', cursor)
The function appends four key query parameters to the base URL:
search– Filters servers by user-entered keywords (optional)limit– Controls pagination size (defaults to5)version=latest– Forces the registry to return current server definitionscursor– Pagination token for fetching subsequent result pages
After constructing the URL, the component uses the native fetch API to execute the GET request and parse the JSON response:
// RegistryCard.vue – lines 56-60
const res = await fetch(url.toString())
if (!res.ok) throw new Error(`HTTP error! Status: ${res.status}`)
return await res.json()
Handling Pagination and State
RegistryCard.vue maintains three reactive state variables to manage the discovery workflow:
loadingServers– Boolean indicator for UI loading statesqueryHistory– Map object that caches raw API responses (McpRegistryType) keyed by search stringlastQuery– Computed property accessing the most recent result set for rendering
When users request additional results, the getNext() function extracts metadata.nextCursor from the cached response and initiates a follow-up request:
// getNext() – lines 33-42
async function getNext() {
const search = lastQueryString.value
const nextCursor = lastQuery.value.metadata?.nextCursor
if (!nextCursor) return
const json = await fetchJson(search, nextCursor)
if (json?.servers?.length) {
queryHistory.value[search].servers.push(...json.servers)
queryHistory.value[search].metadata = json.metadata
}
}
Integrating Registry Data into the TUUI Interface
Rendering Server Cards with RegistryCard.vue
The RegistryCard component transforms raw registry data into interactive UI elements. It iterates over lastQuery.servers to display each server's metadata, including name, version, description, and repository links.
The helper function getPackageUrl() resolves external package URLs based on registry type:
// getPackageUrl() – lines 66-84
function getPackageUrl(registry: McpRegistryPackage) {
switch (registry.registryType) {
case 'mcpb': return registry.identifier
case 'npm':
if (!registry.registryBaseUrl || registry.registryBaseUrl.includes('npmjs.org')) {
return `https://www.npmjs.com/package/${registry.identifier}`
}
// … additional cases for oci, pypi, etc.
default: return registry.registryBaseUrl ?? undefined
}
}
Dialog Wrapper in McpRegistryPage.vue
The McpRegistryPage.vue component located at src/renderer/components/pages/McpRegistryPage.vue provides the container for the discovery interface. It wraps RegistryCard inside a Vuetify v-dialog component, handling open and close interactions while delegating all data fetching to the card component:
<!-- McpRegistryPage.vue – lines 34-44 -->
<v-dialog v-model="internalDialog" …>
<RegistryCard>
<v-btn … @click="closeDialog"></v-btn>
</RegistryCard>
</v-dialog>
This architecture separates concerns: the page manages dialog state, while RegistryCard encapsulates the MCP Registry discovery logic and presentation.
Type Safety and Registry Types
Type definitions in src/renderer/types/registry.ts ensure type safety across the discovery workflow. The interfaces model the registry API response structure:
McpRegistryPackage– Defines package metadata includingregistryType,identifier, andregistryBaseUrlMcpRegistryServer– Represents individual server entries with name, version, description, and package referencesMcpRegistryType– Top-level response object containingserversarray andmetadata(includingnextCursorfor pagination)
These TypeScript definitions enable IntelliSense throughout RegistryCard.vue and prevent runtime errors when accessing nested registry properties.
Summary
- TUUI queries the public MCP Registry at
registry.modelcontextprotocol.io/v0/serversusing thefetchJson()function inRegistryCard.vue - Query parameters include
search,limit,version=latest, andcursorfor filtering and pagination - State management uses reactive variables (
queryHistory,lastQuery,loadingServers) to cache results and track loading states - UI integration occurs through
RegistryCard.vuefor data rendering andMcpRegistryPage.vueas a dialog wrapper - Type safety is enforced via interfaces in
src/renderer/types/registry.tsthat model the registry API schema
Frequently Asked Questions
How does TUUI handle pagination when searching the MCP Registry?
TUUI implements cursor-based pagination through the getNext() function in RegistryCard.vue. After the initial search, the component checks lastQuery.value.metadata.nextCursor from the registry response. If a cursor exists, it appends this token to the cursor query parameter and fetches the next page, concatenating new results to the existing queryHistory array.
What registry types does TUUI support for package resolution?
According to the getPackageUrl() function in RegistryCard.vue, TUUI handles multiple registry types defined in the McpRegistryPackage interface. The switch statement explicitly handles mcpb (returning the identifier directly), npm (constructing npmjs.org URLs), and falls back to registryBaseUrl for other types like OCI or PyPI containers.
Where are the TypeScript definitions for MCP Registry responses located?
The type definitions reside in src/renderer/types/registry.ts. This file exports three primary interfaces: McpRegistryType (the root response object containing servers and metadata), McpRegistryServer (individual server entries), and McpRegistryPackage (package distribution details). These types provide compile-time safety for the JSON payloads returned by registry.modelcontextprotocol.io.
Can users search for specific MCP servers by name in TUUI?
Yes, the discovery interface supports keyword filtering through the search query parameter. When users enter text in the search field and press Enter or click the search button, RegistryCard.vue calls getServers(queryString), which passes the search term to fetchJson(). The registry API filters results server-side and returns matching entries based on the provided keyword.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →