source dump of claude code
at main 152 lines 4.1 kB view raw
1import { readdir, readFile, stat } from 'fs/promises' 2import { homedir } from 'os' 3import { join } from 'path' 4import { 5 type McpServerConfig, 6 McpStdioServerConfigSchema, 7} from '../services/mcp/types.js' 8import { getErrnoCode } from './errors.js' 9import { safeParseJSON } from './json.js' 10import { logError } from './log.js' 11import { getPlatform, SUPPORTED_PLATFORMS } from './platform.js' 12 13export async function getClaudeDesktopConfigPath(): Promise<string> { 14 const platform = getPlatform() 15 16 if (!SUPPORTED_PLATFORMS.includes(platform)) { 17 throw new Error( 18 `Unsupported platform: ${platform} - Claude Desktop integration only works on macOS and WSL.`, 19 ) 20 } 21 22 if (platform === 'macos') { 23 return join( 24 homedir(), 25 'Library', 26 'Application Support', 27 'Claude', 28 'claude_desktop_config.json', 29 ) 30 } 31 32 // First, try using USERPROFILE environment variable if available 33 const windowsHome = process.env.USERPROFILE 34 ? process.env.USERPROFILE.replace(/\\/g, '/') // Convert Windows backslashes to forward slashes 35 : null 36 37 if (windowsHome) { 38 // Remove drive letter and convert to WSL path format 39 const wslPath = windowsHome.replace(/^[A-Z]:/, '') 40 const configPath = `/mnt/c${wslPath}/AppData/Roaming/Claude/claude_desktop_config.json` 41 42 // Check if the file exists 43 try { 44 await stat(configPath) 45 return configPath 46 } catch { 47 // File doesn't exist, continue 48 } 49 } 50 51 // Alternative approach - try to construct path based on typical Windows user location 52 try { 53 // List the /mnt/c/Users directory to find potential user directories 54 const usersDir = '/mnt/c/Users' 55 56 try { 57 const userDirs = await readdir(usersDir, { withFileTypes: true }) 58 59 // Look for Claude Desktop config in each user directory 60 for (const user of userDirs) { 61 if ( 62 user.name === 'Public' || 63 user.name === 'Default' || 64 user.name === 'Default User' || 65 user.name === 'All Users' 66 ) { 67 continue // Skip system directories 68 } 69 70 const potentialConfigPath = join( 71 usersDir, 72 user.name, 73 'AppData', 74 'Roaming', 75 'Claude', 76 'claude_desktop_config.json', 77 ) 78 79 try { 80 await stat(potentialConfigPath) 81 return potentialConfigPath 82 } catch { 83 // File doesn't exist, continue 84 } 85 } 86 } catch { 87 // usersDir doesn't exist or can't be read 88 } 89 } catch (dirError) { 90 logError(dirError) 91 } 92 93 throw new Error( 94 'Could not find Claude Desktop config file in Windows. Make sure Claude Desktop is installed on Windows.', 95 ) 96} 97 98export async function readClaudeDesktopMcpServers(): Promise< 99 Record<string, McpServerConfig> 100> { 101 if (!SUPPORTED_PLATFORMS.includes(getPlatform())) { 102 throw new Error( 103 'Unsupported platform - Claude Desktop integration only works on macOS and WSL.', 104 ) 105 } 106 try { 107 const configPath = await getClaudeDesktopConfigPath() 108 109 let configContent: string 110 try { 111 configContent = await readFile(configPath, { encoding: 'utf8' }) 112 } catch (e: unknown) { 113 const code = getErrnoCode(e) 114 if (code === 'ENOENT') { 115 return {} 116 } 117 throw e 118 } 119 120 const config = safeParseJSON(configContent) 121 122 if (!config || typeof config !== 'object') { 123 return {} 124 } 125 126 const mcpServers = (config as Record<string, unknown>).mcpServers 127 if (!mcpServers || typeof mcpServers !== 'object') { 128 return {} 129 } 130 131 const servers: Record<string, McpServerConfig> = {} 132 133 for (const [name, serverConfig] of Object.entries( 134 mcpServers as Record<string, unknown>, 135 )) { 136 if (!serverConfig || typeof serverConfig !== 'object') { 137 continue 138 } 139 140 const result = McpStdioServerConfigSchema().safeParse(serverConfig) 141 142 if (result.success) { 143 servers[name] = result.data 144 } 145 } 146 147 return servers 148 } catch (error) { 149 logError(error) 150 return {} 151 } 152}