How TUUI Implements MCP Bundle (.mcpb) Support Using the @anthropic-ai/mcpb SDK
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):
- File ingestion via
msgFileTransferRequestIPC channel - Asset path generation using
Constants.getDxtSource - Bundle unpacking through the SDK's
unpackExtensionfunction - Manifest validation with Zod schemas (
McpbManifestSchema.safeParse) - Server config extraction via
getMcpConfigForManifest - Client initialization in
initClientsfor metadata type'metadata__mcpb_manifest' - UI exposure through the preload script's
window.dxtManifestAPI
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, the msgFileTransferRequest handler receives the file buffer and delegates to the DXT utilities:
// 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 generates predictable storage locations for each bundle:
// 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 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:
// 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 against the SDK's Zod schema:
// 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:
// 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 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':
// 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, the traverseManifest function retrieves manifests via IPC and exposes them to the window object:
// 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 provides a typed interface for components:
// 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:
// 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.getDxtSourcegenerates deterministic paths insrc/main/assets/mcpb/for each bundle. - IPC Transfer: The
msgFileTransferRequestchannel securely moves binary data from renderer to main process. - SDK Integration:
unpackExtensionextracts bundles whilegetMcpConfigForManifestconverts manifests into runtime configs. - Validation: Zod schemas from
@anthropic-ai/mcpbensure manifest integrity before client initialization. - Client Boot:
initClientstreats validated bundles identically to stdio servers viainitSingleClient. - UI Bridge: The preload script exposes
window.dxtManifestfor 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 parses 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, 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 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, maintaining Electron's security model by preventing direct filesystem access from the renderer.
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 →