From ae648a7895d2e04d44ab233e63968e2e9fa09f43 Mon Sep 17 00:00:00 2001 From: Khaliq Date: Fri, 20 Mar 2026 11:28:55 +0100 Subject: [PATCH] fix mcp install for codex --- .../__tests__/install-file-locations.test.ts | 56 +++++++++++++++++++ packages/cli/src/commands/install.ts | 10 +++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/__tests__/install-file-locations.test.ts b/packages/cli/src/__tests__/install-file-locations.test.ts index b7bf5b21..4c34ff2b 100644 --- a/packages/cli/src/__tests__/install-file-locations.test.ts +++ b/packages/cli/src/__tests__/install-file-locations.test.ts @@ -944,6 +944,62 @@ Follow TypeScript best practices. expect(mcpConfig.mcpServers['test-server'].command).toBe('npx'); }); + it('installs MCP server to .codex/config.toml when --as codex is used (as + editor)', async () => { + // This tests the real CLI path: --as codex sets both as: 'codex' and editor: 'codex' + const mockPackage = { + id: '@test/mcp-as-codex', + name: '@test/mcp-as-codex', + format: 'mcp', + subtype: 'server', + tags: ['mcp'], + total_downloads: 5, + verified: false, + latest_version: { + version: '1.0.0', + tarball_url: 'https://example.com/package.tar.gz', + }, + }; + + mockClient.getPackage.mockResolvedValue(mockPackage); + mockClient.downloadPackage.mockResolvedValue(await createMCPTarball(mcpServerJson)); + + // The CLI passes both as and editor when --as codex is used + await handleInstall('@test/mcp-as-codex', { as: 'codex', editor: 'codex' }); + + // Should write to .codex/config.toml, NOT to AGENTS.md + const codexConfig = await fs.readFile(path.join(testDir, '.codex', 'config.toml'), 'utf-8'); + expect(codexConfig).toContain('[mcp_servers.test-server]'); + expect(codexConfig).toContain('command = "npx"'); + + // Should NOT have saved any AGENTS.md content + expect(saveFile).not.toHaveBeenCalledWith(expect.stringContaining('AGENTS.md'), expect.any(String)); + }); + + it('installs MCP tool to .cursor/mcp.json when --as cursor is used (as + editor)', async () => { + const mockPackage = { + id: '@test/mcp-as-cursor', + name: '@test/mcp-as-cursor', + format: 'mcp', + subtype: 'tool', + tags: ['mcp'], + total_downloads: 5, + verified: false, + latest_version: { + version: '1.0.0', + tarball_url: 'https://example.com/package.tar.gz', + }, + }; + + mockClient.getPackage.mockResolvedValue(mockPackage); + mockClient.downloadPackage.mockResolvedValue(await createMCPTarball(mcpServerJson)); + + await handleInstall('@test/mcp-as-cursor', { as: 'cursor', editor: 'cursor' }); + + const cursorConfig = JSON.parse(await fs.readFile(path.join(testDir, '.cursor', 'mcp.json'), 'utf-8')); + expect(cursorConfig.mcpServers['test-server']).toBeDefined(); + expect(cursorConfig.mcpServers['test-server'].command).toBe('npx'); + }); + it('preserves MCP format even when auto-detection would pick agents.md', async () => { // Create .agents.md directory to trigger auto-detection await fs.mkdir(path.join(testDir, '.agents.md'), { recursive: true }); diff --git a/packages/cli/src/commands/install.ts b/packages/cli/src/commands/install.ts index 4819b25e..99d09a03 100644 --- a/packages/cli/src/commands/install.ts +++ b/packages/cli/src/commands/install.ts @@ -667,7 +667,9 @@ export async function handleInstall( // Client-side format conversion (if --as flag is specified) // Skip conversion for snippets - they're raw content that doesn't need format conversion - if (options.as && format && format !== pkg.format && effectiveSubtype !== 'snippet') { + // Skip conversion for MCP server packages targeting an MCP editor — they use the dedicated MCP install path + const isMCPToEditor = isMCPServerPackage && MCP_EDITORS.includes(format as MCPEditor); + if (options.as && format && format !== pkg.format && effectiveSubtype !== 'snippet' && !isMCPToEditor) { console.log(` 🔄 Converting from ${pkg.format} to ${format}...`); // Find the main file to convert @@ -999,8 +1001,10 @@ export async function handleInstall( destPath = '.claude/'; fileCount = installedFiles.length; } - // Special handling for MCP server packages (install server configs to .mcp.json) - else if (effectiveFormat === 'mcp' && (effectiveSubtype === 'server' || effectiveSubtype === 'tool')) { + // Special handling for MCP server packages (install server configs to .mcp.json or editor config) + // Match when: native MCP format, OR source is MCP and --as targets an MCP editor (e.g., --as codex) + else if ((effectiveFormat === 'mcp' && (effectiveSubtype === 'server' || effectiveSubtype === 'tool')) || + (isMCPServerPackage && (pkg.subtype === 'server' || pkg.subtype === 'tool') && isMCPToEditor)) { console.log(` 🔧 Installing MCP Server...`); // Find and parse the MCP server config file