( source: string, pluginPath: string, pluginId: string, onProgress?: ProgressCallback, providedUserConfig?: UserConfigValues, forceConfigDialog?: boolean, )
| 696 | * @returns Success with MCP config, or needs-config status with schema |
| 697 | */ |
| 698 | export async function loadMcpbFile( |
| 699 | source: string, |
| 700 | pluginPath: string, |
| 701 | pluginId: string, |
| 702 | onProgress?: ProgressCallback, |
| 703 | providedUserConfig?: UserConfigValues, |
| 704 | forceConfigDialog?: boolean, |
| 705 | ): Promise<McpbLoadResult | McpbNeedsConfigResult> { |
| 706 | const fs = getFsImplementation() |
| 707 | const cacheDir = getMcpbCacheDir(pluginPath) |
| 708 | await fs.mkdir(cacheDir) |
| 709 | |
| 710 | logForDebugging(`Loading MCPB from source: ${source}`) |
| 711 | |
| 712 | // Check cache first |
| 713 | const metadata = await loadCacheMetadata(cacheDir, source) |
| 714 | if (metadata && !(await checkMcpbChanged(source, pluginPath))) { |
| 715 | logForDebugging( |
| 716 | `Using cached MCPB from ${metadata.extractedPath} (hash: ${metadata.contentHash})`, |
| 717 | ) |
| 718 | |
| 719 | // Load manifest from cache |
| 720 | const manifestPath = join(metadata.extractedPath, 'manifest.json') |
| 721 | let manifestContent: string |
| 722 | try { |
| 723 | manifestContent = await fs.readFile(manifestPath, { encoding: 'utf-8' }) |
| 724 | } catch (error) { |
| 725 | if (isENOENT(error)) { |
| 726 | const err = new Error(`Cached manifest not found: ${manifestPath}`) |
| 727 | logError(err) |
| 728 | throw err |
| 729 | } |
| 730 | throw error |
| 731 | } |
| 732 | |
| 733 | const manifestData = new TextEncoder().encode(manifestContent) |
| 734 | const manifest = await parseAndValidateManifestFromBytes(manifestData) |
| 735 | |
| 736 | // Check for user_config requirement |
| 737 | if (manifest.user_config && Object.keys(manifest.user_config).length > 0) { |
| 738 | // Server name from DXT manifest |
| 739 | const serverName = manifest.name |
| 740 | |
| 741 | // Try to load existing config from settings.json or use provided config |
| 742 | const savedConfig = loadMcpServerUserConfig(pluginId, serverName) |
| 743 | const userConfig = providedUserConfig || savedConfig || {} |
| 744 | |
| 745 | // Validate we have all required fields |
| 746 | const validation = validateUserConfig(userConfig, manifest.user_config) |
| 747 | |
| 748 | // Return needs-config if: forced (reconfiguration) OR validation failed |
| 749 | if (forceConfigDialog || !validation.valid) { |
| 750 | return { |
| 751 | status: 'needs-config', |
| 752 | manifest, |
| 753 | extractedPath: metadata.extractedPath, |
| 754 | contentHash: metadata.contentHash, |
| 755 | configSchema: manifest.user_config, |
no test coverage detected