()
| 1627 | // Build McpServerStatus[] for control responses. Shared by mcp_status and |
| 1628 | // reload_plugins handlers. Reads closure state: sdkClients, dynamicMcpState. |
| 1629 | function buildMcpServerStatuses(): McpServerStatus[] { |
| 1630 | const currentAppState = getAppState() |
| 1631 | const currentMcpClients = currentAppState.mcp.clients |
| 1632 | const allMcpTools = uniqBy( |
| 1633 | [...currentAppState.mcp.tools, ...dynamicMcpState.tools], |
| 1634 | 'name', |
| 1635 | ) |
| 1636 | const existingNames = new Set([ |
| 1637 | ...currentMcpClients.map(c => c.name), |
| 1638 | ...sdkClients.map(c => c.name), |
| 1639 | ]) |
| 1640 | return [ |
| 1641 | ...currentMcpClients, |
| 1642 | ...sdkClients, |
| 1643 | ...dynamicMcpState.clients.filter(c => !existingNames.has(c.name)), |
| 1644 | ].map(connection => { |
| 1645 | let config |
| 1646 | if ( |
| 1647 | connection.config.type === 'sse' || |
| 1648 | connection.config.type === 'http' |
| 1649 | ) { |
| 1650 | config = { |
| 1651 | type: connection.config.type, |
| 1652 | url: connection.config.url, |
| 1653 | headers: connection.config.headers, |
| 1654 | oauth: connection.config.oauth, |
| 1655 | } |
| 1656 | } else if (connection.config.type === 'managed-proxy') { |
| 1657 | config = { |
| 1658 | type: 'managed-proxy' as const, |
| 1659 | url: connection.config.url, |
| 1660 | id: connection.config.id, |
| 1661 | } |
| 1662 | } else if ( |
| 1663 | connection.config.type === 'stdio' || |
| 1664 | connection.config.type === undefined |
| 1665 | ) { |
| 1666 | config = { |
| 1667 | type: 'stdio' as const, |
| 1668 | command: connection.config.command, |
| 1669 | args: connection.config.args, |
| 1670 | } |
| 1671 | } |
| 1672 | const serverTools = |
| 1673 | connection.type === 'connected' |
| 1674 | ? filterToolsByServer(allMcpTools, connection.name).map(tool => ({ |
| 1675 | name: tool.mcpInfo?.toolName ?? tool.name, |
| 1676 | annotations: { |
| 1677 | readOnly: tool.isReadOnly({}) || undefined, |
| 1678 | destructive: tool.isDestructive?.({}) || undefined, |
| 1679 | openWorld: tool.isOpenWorld?.({}) || undefined, |
| 1680 | }, |
| 1681 | })) |
| 1682 | : undefined |
| 1683 | // Capabilities passthrough with allowlist pre-filter. The IDE reads |
| 1684 | // experimental['claude/channel'] to decide whether to show the |
| 1685 | // Enable-channel prompt — only echo it if channel_enable would |
| 1686 | // actually pass the allowlist. Not a security boundary (the |
no test coverage detected