dxt.ts
1 import { 2 unpackExtension, 3 getMcpConfigForManifest, 4 v0_3 as McpbVersion, 5 McpbManifestAny, 6 McpbUserConfigValues, 7 Logger 8 } from '@anthropic-ai/mcpb' 9 10 import type { McpDxtErrors } from '@/types/mcp' 11 12 import { existsSync, readFileSync, statSync } from 'fs' 13 import { join, resolve, sep } from 'path' 14 15 export type McpServerConfig = McpbManifestAny['server']['mcp_config'] 16 17 const mockSystemDirs = { 18 home: '/home/user', 19 data: '/data' 20 } 21 22 export async function getMcpConfigForDxt( 23 basePath: string, 24 baseManifest: McpbManifestAny, 25 userConfig: McpbUserConfigValues 26 ): Promise<McpServerConfig> { 27 const logMessages: string[] = [] 28 const logger: Logger = { 29 log: (...args: unknown[]) => logMessages.push(args.join(' ')), 30 warn: (...args: unknown[]) => logMessages.push(args.join(' ')), 31 error: (...args: unknown[]) => logMessages.push(args.join(' ')) 32 } 33 34 const mcpConfig = await getMcpConfigForManifest({ 35 manifest: baseManifest, 36 extensionPath: basePath, 37 systemDirs: mockSystemDirs, 38 userConfig: userConfig, 39 pathSeparator: sep, 40 logger 41 }) 42 43 if (mcpConfig === undefined) { 44 throw new Error(logMessages.join('\n')) 45 } else { 46 return mcpConfig 47 } 48 } 49 export async function unpackDxt(dxtUnpackOption: { 50 mcpbPath: string 51 outputDir: string 52 }): Promise<boolean> { 53 return unpackExtension(dxtUnpackOption) 54 } 55 56 export function getManifest(inputPath: string): McpDxtErrors | McpbManifestAny { 57 try { 58 const resolvedPath = resolve(inputPath) 59 let manifestPath = resolvedPath 60 61 // If input is a directory, look for manifest.json inside it 62 if (existsSync(resolvedPath) && statSync(resolvedPath).isDirectory()) { 63 manifestPath = join(resolvedPath, 'manifest.json') 64 } 65 66 const manifestContent = readFileSync(manifestPath, 'utf-8') 67 const manifestData = JSON.parse(manifestContent) 68 69 const result = McpbVersion.McpbManifestSchema.safeParse(manifestData) 70 71 if (result.success) { 72 console.log('Manifest is valid!') 73 return result.data 74 } else { 75 console.log('ERROR: Manifest validation failed:\n') 76 const errors = result.error.issues.map((issue) => { 77 const path = issue.path.join('.') 78 console.log(` - ${path ? `${path}: ` : ''}${issue.message}`) 79 return { 80 field: path, 81 message: issue.message 82 } 83 }) 84 return { errors: errors } 85 } 86 } catch (error) { 87 const dxtError = { 88 field: 'manifest', 89 message: error instanceof Error ? error.message : String(error) 90 } 91 92 console.error(dxtError.message) 93 return { errors: [dxtError] } 94 } 95 }