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 optional metadata, tools, prompts, and resources fields.
  • ToolType – Specifies the OpenAI-style function call shape (name, description, parameters).
  • MCPAPI – A Record<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 like servers[mySrv].tools.list.
  • listServerTools() – Aggregates available tools into an array of FunctionType objects ready for OpenAI-style function calling.
  • callTool(name, args) – Resolves a tool via getTool, then invokes tools.call with 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() – Uses useMcpStore().getSelected to identify the active server, then calls its prompts.list method.
  • fetchAllPrompts() – Iterates over all servers from getServers() and aggregates prompt lists.
  • fetchSelect(params) – Constructs a GetPromptRequest, invokes the server's prompts.get, and converts the resulting ChatCompletionPromptMessage into the UI's internal ChatCompletionRequestContent via mcpStore.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 useMcpStore automatically merges remote MCP servers with local Stdio processes, normalizing them into a unified MCPAPI map.
  • Generic invocation: Helper methods like getServerFunction, callTool, and listServerTools allow UI components to invoke any MCP primitive without knowing the underlying RPC shape.
  • Type safety: The McpObject, ToolType, and MCPAPI interfaces 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →