( plugin: LoadedPlugin, errors: PluginError[] = [], )
| 587 | * the proper environment variables and scope applied |
| 588 | */ |
| 589 | export async function getPluginMcpServers( |
| 590 | plugin: LoadedPlugin, |
| 591 | errors: PluginError[] = [], |
| 592 | ): Promise<Record<string, ScopedMcpServerConfig> | undefined> { |
| 593 | if (!plugin.enabled) { |
| 594 | return undefined |
| 595 | } |
| 596 | |
| 597 | // Use cached servers if available |
| 598 | const servers = |
| 599 | plugin.mcpServers || (await loadPluginMcpServers(plugin, errors)) |
| 600 | if (!servers) { |
| 601 | return undefined |
| 602 | } |
| 603 | |
| 604 | // Resolve environment variables. Same per-server try/catch as |
| 605 | // extractMcpServersFromPlugins above: a partial saved channel config |
| 606 | // (plugin update added a required field) would make |
| 607 | // substituteUserConfigVariables throw inside resolvePluginMcpEnvironment, |
| 608 | // and this function runs inside Promise.all at config.ts:911 — one |
| 609 | // uncaught throw crashes all plugin MCP loading. |
| 610 | const resolvedServers: Record<string, McpServerConfig> = {} |
| 611 | for (const [name, config] of Object.entries(servers)) { |
| 612 | const userConfig = buildMcpUserConfig(plugin, name) |
| 613 | try { |
| 614 | resolvedServers[name] = resolvePluginMcpEnvironment( |
| 615 | config, |
| 616 | plugin, |
| 617 | userConfig, |
| 618 | errors, |
| 619 | plugin.name, |
| 620 | name, |
| 621 | ) |
| 622 | } catch (err) { |
| 623 | errors?.push({ |
| 624 | type: 'generic-error', |
| 625 | source: name, |
| 626 | plugin: plugin.name, |
| 627 | error: errorMessage(err), |
| 628 | }) |
| 629 | } |
| 630 | } |
| 631 | |
| 632 | // Add plugin scope |
| 633 | return addPluginScopeToServers(resolvedServers, plugin.name, plugin.source) |
| 634 | } |
| 635 |
no test coverage detected