# How TUUI Implements MCP Bundle (.mcpb) Support Using the @anthropic-ai/mcpb SDK

> Discover how TUUI implements MCP Bundle support leveraging the @anthropic-ai/mcpb SDK. Learn to unpack, validate, and convert .mcpb files into server configurations.

- Repository: [AIQL/tuui](https://github.com/ai-ql/tuui)
- Tags: how-to-guide
- Published: 2026-02-23

---

**TUUI implements MCP Bundle support by treating .mcpb files as DXT bundles that are unpacked, validated against Zod schemas, and converted into MCP server configurations using the @anthropic-ai/mcpb SDK's `unpackExtension` and `getMcpConfigForManifest` functions.**

TUUI (The Universal User Interface) is an Electron-based application that extends its capabilities through Model Context Protocol (MCP) servers. When users import an MCP Bundle with the `.mcpb` extension, TUUI leverages the official **@anthropic-ai/mcpb** SDK to safely extract, validate, and initialize the bundled server configuration.

## Overview of the MCP Bundle Pipeline

The implementation follows a seven-stage pipeline that bridges the renderer process (UI) with the main process (Node.js backend):

1. **File ingestion** via `msgFileTransferRequest` IPC channel
2. **Asset path generation** using `Constants.getDxtSource`
3. **Bundle unpacking** through the SDK's `unpackExtension` function
4. **Manifest validation** with Zod schemas (`McpbManifestSchema.safeParse`)
5. **Server config extraction** via `getMcpConfigForManifest`
6. **Client initialization** in `initClients` for metadata type `'metadata__mcpb_manifest'`
7. **UI exposure** through the preload script's `window.dxtManifest` API

## File Ingestion and Asset Management

When a user selects a `.mcpb` file in the renderer, the binary data transfers to the main process through a dedicated IPC channel.

### Receiving the Bundle

In [`src/main/IPCs.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/IPCs.ts), the `msgFileTransferRequest` handler receives the file buffer and delegates to the DXT utilities:

```typescript
// src/main/IPCs.ts
ipcMain.on('msgFileTransferRequest',
  async (event, { name, data }: IpcFileTransferRequest) => {
    const buffer = Buffer.from(data)
    const saveOption = Constants.getDxtSource(name)
    const filePath = saveOption.mcpbPath
    const dirPath = saveOption.outputDir
    
    if (!existsSync(dirPath)) mkdirSync(dirPath, { recursive: true })
    writeFileSync(filePath, buffer, { encoding: null })
    
    await unpackDxt(saveOption)   // SDK unpack
    event.reply('msgFileTransferResponse', { 
      name, 
      success: true, 
      path: dirPath 
    })
})

```

### Deterministic Asset Paths

The `Constants.getDxtSource` function in [`src/main/utils/Constants.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/utils/Constants.ts) generates predictable storage locations for each bundle:

```typescript
// src/main/utils/Constants.ts
static getDxtSource(
  filename: string,
  requiredExtension: string = '.mcpb'
): { mcpbPath: string; outputDir: string } {
  if (!filename.endsWith(requiredExtension)) {
    throw new Error(`File extension name must be: ${requiredExtension}`)
  }
  const dirName = filename.slice(0, -requiredExtension.length)
  const dirPath = join(this.ASSETS_PATH.mcpb, dirName, '/')
  return {
    mcpbPath: join(dirPath, filename),
    outputDir: dirPath
  }
}

```

This ensures each `.mcpb` file unpacks into `src/main/assets/mcpb/{bundleName}/`, preventing collisions and enabling reliable cleanup.

## Unpacking and Validating .mcpb Files

The [`src/main/mcp/dxt.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/mcp/dxt.ts) module serves as the primary interface to the **@anthropic-ai/mcpb** SDK, handling extraction and schema validation.

### Bundle Unpacking

The `unpackDxt` function wraps the SDK's `unpackExtension` method:

```typescript
// src/main/mcp/dxt.ts
export async function unpackDxt(dxtUnpackOption: {
  mcpbPath: string
  outputDir: string
}): Promise<boolean> {
  return unpackExtension(dxtUnpackOption)   // SDK function
}

```

This extracts the zip-like `.mcpb` archive to the designated output directory.

### Manifest Validation

After unpacking, `getManifest` loads and validates [`manifest.json`](https://github.com/ai-ql/tuui/blob/main/manifest.json) against the SDK's Zod schema:

```typescript
// src/main/mcp/dxt.ts
export function getManifest(inputPath: string): McpDxtErrors | McpbManifestAny {
  const manifestPath = /* resolve to manifest.json … */
  const manifestContent = readFileSync(manifestPath, 'utf-8')
  const manifestData = JSON.parse(manifestContent)
  const result = McpbVersion.McpbManifestSchema.safeParse(manifestData)

  if (result.success) return result.data
  else return { errors: … }               // convert Zod errors
}

```

Using `safeParse` ensures invalid manifests fail gracefully with detailed error messages rather than crashing the process.

## Extracting MCP Server Configuration

Once validated, the manifest converts into a runtime MCP server configuration through `getMcpConfigForDxt`:

```typescript
// src/main/mcp/dxt.ts
export async function getMcpConfigForDxt(
  basePath: string,
  baseManifest: McpbManifestAny,
  userConfig: McpbUserConfigValues
): Promise<McpServerConfig> {
  const logger: Logger = { log, warn, error }
  const mcpConfig = await getMcpConfigForManifest({
    manifest: baseManifest,
    extensionPath: basePath,
    systemDirs: mockSystemDirs,
    userConfig,
    pathSeparator: sep,
    logger
  })
  if (!mcpConfig) throw new Error(logMessages.join('\n'))
  return mcpConfig
}

```

This function bridges the SDK's abstract configuration model with TUUI's concrete `McpServerConfig` type, handling path resolution and user-defined overrides.

## Initializing the MCP Client

The [`src/main/mcp/init.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/mcp/init.ts) module integrates DXT bundles into TUUI's standard client initialization flow.

### Detecting Bundle Metadata

During `initClients`, TUUI checks for metadata objects with type `'metadata__mcpb_manifest'`:

```typescript
// src/main/mcp/init.ts
if (object.type === 'metadata__mcpb_manifest') {
  const stdioConfig = await getMcpConfigForDxt(
    Constants.getPosixPath(path.join(Constants.ASSETS_PATH.mcpb, name)),
    object.config,
    object.user_config
  )
  return initSingleClient(name, stdioConfig, callback)
}

```

This treats the extracted bundle configuration identically to standard stdio-based MCP servers, ensuring consistent behavior across all server types.

## Exposing Bundle Metadata to the UI

TUUI exposes DXT manifest data to the Vue-based renderer through a carefully isolated preload script.

### Preload Script Bridge

In [`src/preload/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/preload/index.ts), the `traverseManifest` function retrieves manifests via IPC and exposes them to the window object:

```typescript
// src/preload/index.ts
async function traverseManifest(): Promise<DXTAPI> {
  const manifests = await ipcRenderer.invoke('list-manifests')
  return manifests.result || {}
}

const dxt = {
  get: traverseManifest,
  refresh: async () => { /* trigger reload */ }
}

contextBridge.exposeInMainWorld('dxtManifest', dxt)

```

This creates a secure bridge allowing the UI to read bundle metadata without direct filesystem access.

### Renderer Store Access

The Vue store in [`src/renderer/store/mcp.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/mcp.ts) provides a typed interface for components:

```typescript
// src/renderer/store/mcp.ts
export function getDxtManifest(): DXTAPI | undefined {
  return window.dxtManifest?.get()
}

```

Components can now call `getDxtManifest()` to display bundle information or trigger refreshes after new uploads.

## Complete Code Example: Loading a .mcpb Bundle from the UI

Here is a complete renderer-side implementation demonstrating the full upload flow:

```typescript
// Renderer (e.g., a Vue component)
async function uploadMcpb(file: File) {
  const arrayBuffer = await file.arrayBuffer()
  
  // Send binary data to main process
  ipcRenderer.send('msgFileTransferRequest', {
    name: file.name,               // must end with .mcpb
    data: new Uint8Array(arrayBuffer)
  })

  // Listen for the result
  ipcRenderer.once('msgFileTransferResponse', (event, resp) => {
    if (resp.success) {
      console.log('Bundle saved to', resp.path)
      // Refresh the DXT list so UI sees the new manifest
      window.dxtManifest.refresh()
    } else {
      console.error('Upload failed:', resp.reason)
    }
  })
}

```

This component handles the binary transfer, awaits confirmation from the main process, and updates the UI state to reflect the newly available MCP server configuration.

## Summary

TUUI implements MCP Bundle support through a robust, SDK-backed pipeline:

- **Asset Management**: `Constants.getDxtSource` generates deterministic paths in `src/main/assets/mcpb/` for each bundle.
- **IPC Transfer**: The `msgFileTransferRequest` channel securely moves binary data from renderer to main process.
- **SDK Integration**: `unpackExtension` extracts bundles while `getMcpConfigForManifest` converts manifests into runtime configs.
- **Validation**: Zod schemas from `@anthropic-ai/mcpb` ensure manifest integrity before client initialization.
- **Client Boot**: `initClients` treats validated bundles identically to stdio servers via `initSingleClient`.
- **UI Bridge**: The preload script exposes `window.dxtManifest` for Vue components to access bundle metadata.

## Frequently Asked Questions

### How does TUUI validate the integrity of an .mcpb file?

TUUI validates .mcpb files using the **@anthropic-ai/mcpb** SDK's Zod schema validation. After unpacking the bundle with `unpackExtension`, the `getManifest` function in [`src/main/mcp/dxt.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/mcp/dxt.ts) parses [`manifest.json`](https://github.com/ai-ql/tuui/blob/main/manifest.json) and validates it against `McpbVersion.McpbManifestSchema.safeParse()`. This ensures the manifest conforms to the official MCP Bundle specification before TUUI attempts to initialize the server.

### What happens if the .mcpb file contains an invalid manifest?

If validation fails during the `getManifest` call, the function returns a `McpDxtErrors` object containing detailed Zod error messages rather than the manifest data. This error propagates through the initialization pipeline, preventing `getMcpConfigForDxt` from attempting to create a server configuration. The UI can then display specific validation errors to help users diagnose malformed bundles.

### Can users configure MCP Bundle servers after installation?

Yes, TUUI supports user configuration overrides through the `userConfig` parameter in `getMcpConfigForDxt`. When initializing a bundle-based client in [`src/main/mcp/init.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/mcp/init.ts), TUUI passes `object.user_config` to the SDK's `getMcpConfigForManifest` function. This allows users to customize environment variables, command-line arguments, and other runtime settings without modifying the bundled manifest itself.

### How does the renderer process access bundle metadata without filesystem access?

TUUI implements a secure context bridge in [`src/preload/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/preload/index.ts) that exposes a controlled API via `contextBridge.exposeInMainWorld('dxtManifest', dxt)`. The `traverseManifest` function uses `ipcRenderer.invoke('list-manifests')` to request data from the main process, which then returns serialized manifest data. Vue components in the renderer access this through `window.dxtManifest.get()` via the helper in [`src/renderer/store/mcp.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/mcp.ts), maintaining Electron's security model by preventing direct filesystem access from the renderer.