Skip to content

Commit 10a814f

Browse files
committed
fix(mcp): distinguish Claude Desktop and Claude Code CLI configurations
- Add USER_ID env var (required by openmemory-mcp) - Claude Code CLI uses ~/.claude.json - Claude Desktop uses platform-specific paths - Fix Ollama model validation (exact bge-m3 match) - Fix MCP server verification timeout logic - Fix Windows APPDATA fallback to homedir() - Unify error messages to Chinese
1 parent 522b047 commit 10a814f

3 files changed

Lines changed: 39 additions & 17 deletions

File tree

cli/src/commands/install.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ interface OllamaTagsResponse {
7474
// Only commands and skills directories - no config files (AGENTS.md, CLAUDE.md, etc.)
7575
const IDE_CONFIGS: Record<string, IdeConfig> = {
7676
augment: { commandsDir: '.augment/commands', skillsDir: '.augment/skills' },
77-
claude: { commandsDir: '.claude/commands', skillsDir: '.claude/skills' },
77+
claude: { commandsDir: '.claude/commands', skillsDir: '.claude/skills' }, // Claude Code CLI
78+
'claude-desktop': { commandsDir: '.claude/commands', skillsDir: '.claude/skills' }, // Claude Desktop (same dirs)
7879
cursor: { commandsDir: '.cursor/commands', skillsDir: '.cursor/skills' },
7980
gemini: { commandsDir: '.gemini/commands', skillsDir: '.gemini/skills' },
8081
common: { commandsDir: '.agents/commands', skillsDir: '.agents/skills' },
@@ -681,7 +682,8 @@ async function phase2_initProject(options: InstallOptions): Promise<string> {
681682
message: '选择 IDE 类型 (空格选择,回车确认):',
682683
choices: [
683684
{ name: 'Augment', value: 'augment', checked: true },
684-
{ name: 'Claude Code', value: 'claude' },
685+
{ name: 'Claude Code (CLI)', value: 'claude' },
686+
{ name: 'Claude Desktop', value: 'claude-desktop' },
685687
{ name: 'Cursor', value: 'cursor' },
686688
{ name: 'Gemini', value: 'gemini' },
687689
{ name: '通用 (AGENTS.md)', value: 'common' },

cli/src/lib/mcp-config.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const OPENMEMORY_MCP_CONFIG: McpServerConfig = {
3535
command: 'npx',
3636
args: ['-y', 'openmemory-mcp'],
3737
env: {
38+
USER_ID: 'default', // Required: identifies the user for memory storage
3839
MEM0_EMBEDDING_MODEL: 'bge-m3',
3940
MEM0_EMBEDDING_PROVIDER: 'ollama',
4041
OLLAMA_HOST: 'http://localhost:11434',
@@ -56,20 +57,25 @@ export const IDE_MCP_CONFIGS: Record<string, IdeConfigInfo> = {
5657
getConfigPath: () => join(homedir(), '.augment', 'settings.json'),
5758
configKey: 'mcpServers',
5859
},
59-
claude: {
60+
'claude-desktop': {
6061
name: 'Claude Desktop',
6162
getConfigPath: () => {
6263
const p = platform();
6364
if (p === 'darwin') {
6465
return join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
6566
} else if (p === 'win32') {
66-
return join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json');
67+
return join(process.env.APPDATA || homedir(), 'Claude', 'claude_desktop_config.json');
6768
}
6869
// Linux
6970
return join(homedir(), '.config', 'claude', 'claude_desktop_config.json');
7071
},
7172
configKey: 'mcpServers',
7273
},
74+
claude: {
75+
name: 'Claude Code (CLI)',
76+
getConfigPath: () => join(homedir(), '.claude.json'),
77+
configKey: 'mcpServers',
78+
},
7379
cursor: {
7480
name: 'Cursor',
7581
getConfigPath: () => join(homedir(), '.cursor', 'mcp.json'),
@@ -80,7 +86,7 @@ export const IDE_MCP_CONFIGS: Record<string, IdeConfigInfo> = {
8086
getConfigPath: () => {
8187
const p = platform();
8288
if (p === 'win32') {
83-
return join(process.env.APPDATA || '', 'gemini', 'settings', 'gemini_mcp_settings.json');
89+
return join(process.env.APPDATA || homedir(), 'gemini', 'settings', 'gemini_mcp_settings.json');
8490
}
8591
return join(homedir(), '.config', 'gemini', 'settings', 'gemini_mcp_settings.json');
8692
},
@@ -127,7 +133,7 @@ export function configureMcpForIde(ide: string, force: boolean = false): McpConf
127133
return {
128134
success: false,
129135
path: '',
130-
error: `Unknown IDE: ${ide}`,
136+
error: `未知的 IDE: ${ide}`,
131137
};
132138
}
133139

@@ -289,7 +295,7 @@ async function verifyQdrant(): Promise<boolean> {
289295
}
290296

291297
/**
292-
* Verify that Ollama is accessible and has the required model
298+
* Verify that Ollama is accessible and has the required embedding model (bge-m3)
293299
*/
294300
async function verifyOllama(): Promise<boolean> {
295301
try {
@@ -298,8 +304,9 @@ async function verifyOllama(): Promise<boolean> {
298304

299305
const data = await response.json() as { models?: Array<{ name: string }> };
300306
const models = data.models || [];
307+
// Check for exact bge-m3 model match (with or without tag suffix)
301308
return models.some((m: { name: string }) =>
302-
m.name.includes('bge-m3') || m.name.includes('nomic-embed')
309+
m.name === 'bge-m3' || m.name === 'bge-m3:latest' || m.name.startsWith('bge-m3:')
303310
);
304311
} catch {
305312
return false;
@@ -308,10 +315,12 @@ async function verifyOllama(): Promise<boolean> {
308315

309316
/**
310317
* Verify that MCP server can start and respond
318+
* @param timeoutMs - Timeout in milliseconds (default: 10000)
311319
*/
312-
async function verifyMcpServer(): Promise<boolean> {
320+
async function verifyMcpServer(timeoutMs: number = 10000): Promise<boolean> {
313321
return new Promise((resolve) => {
314322
let resolved = false;
323+
let hasReceivedOutput = false;
315324

316325
// Start the MCP server process
317326
const proc: ChildProcess = spawn('npx', ['-y', 'openmemory-mcp'], {
@@ -322,14 +331,22 @@ async function verifyMcpServer(): Promise<boolean> {
322331
stdio: ['pipe', 'pipe', 'pipe'],
323332
});
324333

334+
const cleanup = () => {
335+
try {
336+
proc.kill('SIGTERM');
337+
} catch {
338+
// Process may already be dead
339+
}
340+
};
341+
325342
const timeout = setTimeout(() => {
326343
if (!resolved) {
327344
resolved = true;
328-
proc.kill();
329-
// If the process started without immediate error, consider it responsive
330-
resolve(true);
345+
cleanup();
346+
// Only consider success if we received some output before timeout
347+
resolve(hasReceivedOutput);
331348
}
332-
}, 5000);
349+
}, timeoutMs);
333350

334351
proc.on('error', () => {
335352
if (!resolved) {
@@ -346,18 +363,19 @@ async function verifyMcpServer(): Promise<boolean> {
346363
if (!resolved) {
347364
resolved = true;
348365
clearTimeout(timeout);
349-
proc.kill();
366+
cleanup();
350367
resolve(false);
351368
}
352369
}
353370
});
354371

355372
// If stdout receives any data, it means MCP is working
356373
proc.stdout?.on('data', () => {
374+
hasReceivedOutput = true;
357375
if (!resolved) {
358376
resolved = true;
359377
clearTimeout(timeout);
360-
proc.kill();
378+
cleanup();
361379
resolve(true);
362380
}
363381
});

cli/tests/mcp-config.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ describe('mcp-config', () => {
4444
it('should return list of supported IDEs', () => {
4545
const ides = getSupportedIdes();
4646
expect(ides).toContain('augment');
47-
expect(ides).toContain('claude');
47+
expect(ides).toContain('claude'); // Claude Code CLI
48+
expect(ides).toContain('claude-desktop'); // Claude Desktop app
4849
expect(ides).toContain('cursor');
4950
expect(ides).toContain('gemini');
5051
});
@@ -55,6 +56,7 @@ describe('mcp-config', () => {
5556
const config = getMcpServerConfig();
5657
expect(config.command).toBe('npx');
5758
expect(config.args).toContain('openmemory-mcp');
59+
expect(config.env.USER_ID).toBe('default'); // Required field
5860
expect(config.env.MEM0_EMBEDDING_MODEL).toBe('bge-m3');
5961
expect(config.env.MEM0_EMBEDDING_PROVIDER).toBe('ollama');
6062
});
@@ -64,7 +66,7 @@ describe('mcp-config', () => {
6466
it('should return error for unknown IDE', () => {
6567
const result = configureMcpForIde('unknown_ide');
6668
expect(result.success).toBe(false);
67-
expect(result.error).toContain('Unknown IDE');
69+
expect(result.error).toContain('未知的 IDE');
6870
});
6971

7072
it('should create new config file for augment', () => {

0 commit comments

Comments
 (0)