/ src / main / mcp / config.ts
config.ts
  1  import { showNotification } from '../utils//notification'
  2  import fs from 'node:fs'
  3  import path from 'node:path'
  4  import { McpServerConfig } from './types'
  5  import { shell } from 'electron'
  6  import { debounce } from 'lodash'
  7  
  8  let mcpConfig
  9  
 10  let timeoutId
 11  
 12  const DEBOUNCE_DELAY = 500
 13  
 14  function handleFileChange(configPath) {
 15    try {
 16      const parsedConfig = readConfig(configPath)
 17      if (mcpConfig !== parsedConfig) {
 18        console.log(`${configPath} changed`)
 19      }
 20    } catch {}
 21  }
 22  
 23  const debouncedHandleFileChange = debounce(handleFileChange, DEBOUNCE_DELAY)
 24  
 25  function readConfig(configPath: string) {
 26    const fileString = fs.readFileSync(configPath, 'utf8')
 27    if (fileString) {
 28      return JSON.parse(fileString)
 29    } else {
 30      return {}
 31    }
 32  }
 33  
 34  export function loadConfigFile(configPath: string): Record<string, McpServerConfig> {
 35    const resolvedConfigPath = path.isAbsolute(configPath)
 36      ? configPath
 37      : path.resolve(process.cwd(), configPath)
 38  
 39    try {
 40      if (!fs.existsSync(resolvedConfigPath)) {
 41        showNotification({
 42          body: `MCP Config Not Found.`
 43        })
 44        return {}
 45      }
 46      const parsedConfig = readConfig(resolvedConfigPath)
 47      mcpConfig = parsedConfig
 48      fs.watch(resolvedConfigPath, () => {
 49        if (timeoutId) clearTimeout(timeoutId)
 50        timeoutId = setTimeout(() => debouncedHandleFileChange(resolvedConfigPath), DEBOUNCE_DELAY)
 51      })
 52      if (!parsedConfig.mcpServers) {
 53        return {}
 54      } else {
 55        return parsedConfig.mcpServers
 56      }
 57    } catch (err) {
 58      showNotification(
 59        {
 60          body: `MCP Config JSON parse failure`
 61        },
 62  
 63        {
 64          onClick: () => {
 65            shell.showItemInFolder(resolvedConfigPath)
 66          }
 67        }
 68      )
 69      if (err instanceof SyntaxError) {
 70        throw new Error(`Invalid JSON in config file: ${err.message}`)
 71      }
 72      throw err
 73    }
 74  }
 75  
 76  export function loadLlmFile(llmPath: string) {
 77    const resolvedConfigPath = path.isAbsolute(llmPath)
 78      ? llmPath
 79      : path.resolve(process.cwd(), llmPath)
 80    try {
 81      if (!fs.existsSync(resolvedConfigPath)) {
 82        throw new Error(`Config file not found: ${resolvedConfigPath}`)
 83      }
 84      const configContent = fs.readFileSync(resolvedConfigPath, 'utf8')
 85      const parsedConfig = JSON.parse(configContent)
 86      if (!parsedConfig) {
 87        return {}
 88      } else {
 89        return parsedConfig
 90      }
 91    } catch (err) {
 92      showNotification(
 93        {
 94          body: 'LLM Config JSON parse failure'
 95        },
 96  
 97        {
 98          onClick: () => {
 99            shell.showItemInFolder(resolvedConfigPath)
100          }
101        }
102      )
103      if (err instanceof SyntaxError) {
104        throw new Error(`Invalid JSON in llm file: ${err.message}`)
105      }
106      throw err
107    }
108  }