TUUI MCP Architecture: How Tools, Prompts, and Resources Are Handled
TUUI implements a three-layer architecture—type definitions, runtime store, and feature stores—to uniformly handle MCP tools, prompts, and resources across any number of Model Context Protocol servers.
The Model Context Protocol (MCP) integration in TUUI (ai-ql/tuui) provides a type-safe abstraction for discovering and invoking remote capabilities. This architecture for handling MCP tools, prompts, and resources within TUUI separates concerns into distinct layers: static type contracts, dynamic runtime management, and UI-specific feature consumption.
The Three-Layer Architecture Overview
TUUI's MCP stack is organized into three cooperating layers that transform raw server capabilities into rendered UI elements:
| Layer | Responsibility | Core Implementation |
|---|---|---|
| Type definitions | Mirrors the MCP SDK signatures into TypeScript contracts | src/types/mcp.d.ts |
| Runtime store | Discovers servers, merges Stdio metadata, and exposes generic invocation helpers | src/renderer/store/mcp.ts |
| Feature stores | Consumes the generic API to fetch prompts, list tools, or read resources | src/renderer/store/prompt.ts (and inline resource handling in mcp.ts) |
Type Definitions Layer
The foundation resides in src/types/mcp.d.ts, which re-exports simplified, UI-friendly versions of the official MCP SDK types:
McpObject– Defines the optionalmetadata,tools,prompts, andresourcesfields.ToolType– Specifies the OpenAI-style function call shape (name,description,parameters).MCPAPI– ARecord<string, McpObject>map where keys represent server names.
These declarations guarantee that every subsequent layer respects the MCP contract without importing heavy SDK dependencies into the renderer process.
Runtime Store Layer
src/renderer/store/mcp.ts implements the central Pinia store (useMcpStore) that bridges the main-process MCP client with the UI.
Server Discovery and Merging
The store initializes by calling getRawServers(), which reads the window.mcpServers object exposed by the preload script (src/preload/index.ts). It then merges these with locally-run Stdio servers via useStdioStore(), normalizing them into a unified MCPAPI map.
The getAllowedPrimitive(item) helper inspects each server to determine which primitives (tools, resources, prompts) it implements, enabling dynamic UI filtering.
Dynamic Invocation Helpers
The store provides type-safe methods for runtime interaction:
getServerFunction({serverName, primitiveName, methodName})– Dynamically resolves methods likeservers[mySrv].tools.list.listServerTools()– Aggregates available tools into an array ofFunctionTypeobjects ready for OpenAI-style function calling.callTool(name, args)– Resolves a tool viagetTool, then invokestools.callwith JSON-encoded arguments.getAllByServer()– Returns all primitives grouped by server name for bulk operations.
The watchServerUpdate watcher keeps reactive UI checklists synchronized when servers connect or disconnect.
Feature Store Layer
Specialized stores consume the generic MCP API for specific UI features. src/renderer/store/prompt.ts demonstrates this pattern:
fetchPrompts()– UsesuseMcpStore().getSelectedto identify the active server, then calls itsprompts.listmethod.fetchAllPrompts()– Iterates over all servers fromgetServers()and aggregates prompt lists.fetchSelect(params)– Constructs aGetPromptRequest, invokes the server'sprompts.get, and converts the resultingChatCompletionPromptMessageinto the UI's internalChatCompletionRequestContentviamcpStore.convertItem.
This architecture ensures that feature stores remain agnostic of underlying RPC shapes, relying solely on the standardized interface exposed by the MCP store.
Key Implementation Files
| File | Role | Link |
|---|---|---|
src/types/mcp.d.ts |
Central type contract for MCP objects, tools, prompts, resources. | view |
src/renderer/store/mcp.ts |
Pinia store that discovers MCP servers, merges Stdio metadata, and provides generic helpers (listServerTools, callTool, getServerFunction). |
view |
src/renderer/store/prompt.ts |
Feature store that uses useMcpStore to list, fetch, and render prompts. |
view |
src/main/mcp/client.ts |
Implements the preload-side window.mcpServers client that talks to the MCP server (creates the MCPAPI map). |
view |
src/preload/index.ts |
Exposes the MCP client (window.mcpServers) and the DXT manifest to the renderer. |
view |
src/main/mcp/connection.ts & src/main/mcp/config.ts |
Handle low-level connection lifecycle and configuration parsing for MCP servers. | connection, config |
Code Examples
List All Available Tools from the Current Server
import { useMcpStore } from '@/renderer/store/mcp'
async function showTools() {
const store = useMcpStore()
const tools = await store.listServerTools() // ← uses getServerFunction → tools.list
console.table(tools.map(t => t.function))
}
showTools()
Source: listServerTools in [src/renderer/store/mcp.ts](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/mcp.ts).
Call a Tool with JSON Arguments
import { useMcpStore } from '@/renderer/store/mcp'
async function runTool(name: string, args: Record<string, unknown>) {
const store = useMcpStore()
const result = await store.callTool(name, JSON.stringify(args))
console.log('Tool response →', result)
}
runTool('search_web', { query: 'latest AI research' })
Source: callTool in [src/renderer/store/mcp.ts](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/mcp.ts).
Load All Prompts Across Every MCP Server
import { getServers } from '@/renderer/store/mcp'
async function loadAllPrompts() {
const promptStore = await import('@/renderer/store/prompt') // lazy load
const all = await promptStore.usePromptStore().fetchAllPrompts()
console.log(`Fetched ${all.length} prompts from ${Object.keys(getServers()!).length} servers`)
}
loadAllPrompts()
Source: fetchAllPrompts in [src/renderer/store/prompt.ts](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/prompt.ts).
Read a Resource from a Specific Server
import { getServers } from '@/renderer/store/mcp'
async function readResource(server: string, id: string) {
const servers = getServers()
const read = servers?.[server]?.resources?.read
if (typeof read === 'function') {
const res = await read({ method: 'resources/read', params: { name: id } })
console.log('Resource data →', res.resource)
}
}
readResource('my-mcp', 'config.yaml')
Pattern follows the same dynamic lookup used in callTool.
Summary
- Three-layer design: Type definitions (
mcp.d.ts), runtime store (mcp.ts), and feature stores (prompt.ts) create a clean separation between protocol contracts, server management, and UI consumption. - Dynamic discovery: The
useMcpStoreautomatically merges remote MCP servers with local Stdio processes, normalizing them into a unifiedMCPAPImap. - Generic invocation: Helper methods like
getServerFunction,callTool, andlistServerToolsallow UI components to invoke any MCP primitive without knowing the underlying RPC shape. - Type safety: The
McpObject,ToolType, andMCPAPIinterfaces ensure that tools, prompts, and resources are handled consistently across the renderer and main processes.
Frequently Asked Questions
How does TUUI discover available MCP servers at runtime?
TUUI discovers servers through the getRawServers() method in src/renderer/store/mcp.ts, which reads the window.mcpServers object exposed by the preload script. This object is populated by src/main/mcp/client.ts and merged with local Stdio server metadata from useStdioStore(), creating a unified registry of all available MCP capabilities.
What is the difference between the MCP store and the Prompt store?
The MCP store (src/renderer/store/mcp.ts) is a generic runtime layer that handles server discovery, connection management, and dynamic invocation of any MCP primitive (tools, prompts, or resources). The Prompt store (src/renderer/store/prompt.ts) is a feature-specific consumer that uses the MCP store's generic API to implement UI-focused operations like fetchAllPrompts or fetchSelect, converting raw MCP responses into chat-compatible message formats.
How does TUUI handle type safety across MCP tools, prompts, and resources?
Type safety is enforced through the central contract in src/types/mcp.d.ts. This file defines McpObject as the canonical shape for server capabilities, ToolType for OpenAI-compatible function signatures, and MCPAPI as the registry map. The Pinia stores use these types exclusively, ensuring that methods like callTool or getServerFunction operate on validated structures rather than raw JSON.
Can TUUI dynamically invoke MCP methods without hardcoding server-specific logic?
Yes. The getServerFunction method in src/renderer/store/mcp.ts performs dynamic lookup using the pattern servers[serverName][primitiveName][methodName]. This allows the UI to invoke any MCP method—such as tools.list, prompts.get, or resources.read—without importing server-specific SDKs or writing conditional logic for each provider. The store normalizes all responses through helper utilities like convertItem before passing them to UI components.
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 →