diff --git a/ccw/src/templates/dashboard-js/components/mcp-manager.js b/ccw/src/templates/dashboard-js/components/mcp-manager.js
index f4bbf1ae..15bfc957 100644
--- a/ccw/src/templates/dashboard-js/components/mcp-manager.js
+++ b/ccw/src/templates/dashboard-js/components/mcp-manager.js
@@ -1201,6 +1201,310 @@ function setPreferredProjectConfigType(type) {
}
}
+// ========== Recommended MCP Servers ==========
+// Pre-configured MCP server definitions for easy installation
+
+const RECOMMENDED_MCP_SERVERS = [
+ {
+ id: 'ace-tool',
+ name: 'ACE Tool',
+ description: 'Augment Context Engine - Semantic code search with real-time codebase indexing',
+ icon: 'search-code',
+ category: 'search',
+ fields: [
+ {
+ key: 'baseUrl',
+ label: 'Base URL',
+ type: 'text',
+ default: 'https://acemcp.heroman.wtf/relay/',
+ placeholder: 'https://acemcp.heroman.wtf/relay/',
+ required: true,
+ description: 'ACE MCP relay server URL'
+ },
+ {
+ key: 'token',
+ label: 'API Token',
+ type: 'password',
+ default: '',
+ placeholder: 'ace_xxxxxxxxxxxxxxxx',
+ required: true,
+ description: 'Your ACE API token (get from ACE dashboard)'
+ }
+ ],
+ buildConfig: (values) => ({
+ command: 'npx',
+ args: [
+ 'ace-tool',
+ '--base-url',
+ values.baseUrl || 'https://acemcp.heroman.wtf/relay/',
+ '--token',
+ values.token
+ ]
+ })
+ },
+ {
+ id: 'chrome-devtools',
+ name: 'Chrome DevTools',
+ description: 'Browser automation and DevTools integration for web development',
+ icon: 'chrome',
+ category: 'browser',
+ fields: [],
+ buildConfig: () => ({
+ type: 'stdio',
+ command: 'npx',
+ args: ['chrome-devtools-mcp@latest'],
+ env: {}
+ })
+ },
+ {
+ id: 'exa',
+ name: 'Exa Search',
+ description: 'AI-powered web search with real-time crawling and content extraction',
+ icon: 'globe-2',
+ category: 'search',
+ fields: [
+ {
+ key: 'apiKey',
+ label: 'EXA API Key',
+ type: 'password',
+ default: '',
+ placeholder: 'your-exa-api-key',
+ required: true,
+ description: 'Get your API key from exa.ai dashboard'
+ }
+ ],
+ buildConfig: (values) => ({
+ command: 'npx',
+ args: ['-y', 'exa-mcp-server'],
+ env: {
+ EXA_API_KEY: values.apiKey
+ }
+ })
+ }
+];
+
+// Get recommended MCP servers list
+function getRecommendedMcpServers() {
+ return RECOMMENDED_MCP_SERVERS;
+}
+
+// Check if a recommended MCP is already installed
+function isRecommendedMcpInstalled(mcpId) {
+ // Check in current project servers
+ const currentPath = projectPath;
+ const projectData = mcpAllProjects[currentPath] || {};
+ const projectServers = projectData.mcpServers || {};
+
+ if (projectServers[mcpId]) return { installed: true, scope: 'project' };
+
+ // Check in global servers
+ if (mcpUserServers && mcpUserServers[mcpId]) return { installed: true, scope: 'global' };
+
+ // Check in Codex servers
+ if (codexMcpServers && codexMcpServers[mcpId]) return { installed: true, scope: 'codex' };
+
+ return { installed: false, scope: null };
+}
+
+// Open recommended MCP install wizard modal
+function openRecommendedMcpWizard(mcpId) {
+ const mcpDef = RECOMMENDED_MCP_SERVERS.find(m => m.id === mcpId);
+ if (!mcpDef) {
+ showRefreshToast(`Unknown MCP: ${mcpId}`, 'error');
+ return;
+ }
+
+ // Create wizard modal
+ const existingModal = document.getElementById('recommendedMcpWizardModal');
+ if (existingModal) {
+ existingModal.remove();
+ }
+
+ const hasFields = mcpDef.fields && mcpDef.fields.length > 0;
+
+ const modal = document.createElement('div');
+ modal.id = 'recommendedMcpWizardModal';
+ modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50';
+ modal.innerHTML = `
+
+
+
+
+
+
+
+
+
${t('mcp.wizard.install')} ${escapeHtml(mcpDef.name)}
+
${escapeHtml(mcpDef.description)}
+
+
+
+
+
+
+
+ ${hasFields ? `
+
+ ${mcpDef.fields.map(field => `
+
+
+ ${field.description ? `
${escapeHtml(field.description)}
` : ''}
+
+
+ `).join('')}
+
+ ` : `
+
+
+
${t('mcp.wizard.noConfig')}
+
+ `}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ document.body.appendChild(modal);
+
+ // Initialize Lucide icons in modal
+ if (typeof lucide !== 'undefined') {
+ lucide.createIcons();
+ }
+
+ // Set default scope to global
+ window.selectedWizardScope = 'global';
+
+ // Focus first input if exists
+ if (hasFields) {
+ const firstInput = modal.querySelector('input');
+ if (firstInput) firstInput.focus();
+ }
+}
+
+// Close recommended MCP wizard modal
+function closeRecommendedMcpWizard() {
+ const modal = document.getElementById('recommendedMcpWizardModal');
+ if (modal) {
+ modal.remove();
+ }
+}
+
+// Select scope in wizard
+function selectWizardScope(scope) {
+ window.selectedWizardScope = scope;
+
+ // Update button states
+ const buttons = document.querySelectorAll('.wizard-scope-btn');
+ buttons.forEach(btn => {
+ if (btn.dataset.scope === scope) {
+ btn.classList.add('bg-primary/10', 'border-primary');
+ } else {
+ btn.classList.remove('bg-primary/10', 'border-primary');
+ }
+ });
+}
+
+// Submit recommended MCP wizard
+async function submitRecommendedMcpWizard(mcpId) {
+ const mcpDef = RECOMMENDED_MCP_SERVERS.find(m => m.id === mcpId);
+ if (!mcpDef) {
+ showRefreshToast(`Unknown MCP: ${mcpId}`, 'error');
+ return;
+ }
+
+ // Collect field values
+ const values = {};
+ let hasError = false;
+
+ for (const field of mcpDef.fields) {
+ const input = document.getElementById(`wizard-field-${field.key}`);
+ const value = input ? input.value.trim() : '';
+
+ if (field.required && !value) {
+ showRefreshToast(`${field.label} is required`, 'error');
+ if (input) input.focus();
+ hasError = true;
+ break;
+ }
+
+ values[field.key] = value;
+ }
+
+ if (hasError) return;
+
+ // Build config
+ const serverConfig = mcpDef.buildConfig(values);
+ const scope = window.selectedWizardScope || 'global';
+
+ try {
+ showRefreshToast(`Installing ${mcpDef.name}...`, 'info');
+
+ if (scope === 'codex') {
+ await addCodexMcpServer(mcpId, serverConfig);
+ } else if (scope === 'global') {
+ await addGlobalMcpServer(mcpId, serverConfig);
+ } else {
+ await copyMcpServerToProject(mcpId, serverConfig);
+ }
+
+ closeRecommendedMcpWizard();
+ showRefreshToast(`${mcpDef.name} installed successfully`, 'success');
+ } catch (err) {
+ console.error(`Failed to install ${mcpDef.name}:`, err);
+ showRefreshToast(`Failed to install ${mcpDef.name}: ${err.message}`, 'error');
+ }
+}
+
// ========== Global Exports for onclick handlers ==========
// Expose functions to global scope to support inline onclick handlers
window.setCliMode = setCliMode;
@@ -1212,3 +1516,9 @@ window.toggleProjectConfigType = toggleProjectConfigType;
window.getPreferredProjectConfigType = getPreferredProjectConfigType;
window.setPreferredProjectConfigType = setPreferredProjectConfigType;
window.setCcwProjectRootToCurrent = setCcwProjectRootToCurrent;
+window.getRecommendedMcpServers = getRecommendedMcpServers;
+window.isRecommendedMcpInstalled = isRecommendedMcpInstalled;
+window.openRecommendedMcpWizard = openRecommendedMcpWizard;
+window.closeRecommendedMcpWizard = closeRecommendedMcpWizard;
+window.selectWizardScope = selectWizardScope;
+window.submitRecommendedMcpWizard = submitRecommendedMcpWizard;
diff --git a/ccw/src/templates/dashboard-js/i18n.js b/ccw/src/templates/dashboard-js/i18n.js
index ea0d4907..83696e81 100644
--- a/ccw/src/templates/dashboard-js/i18n.js
+++ b/ccw/src/templates/dashboard-js/i18n.js
@@ -897,6 +897,18 @@ const i18n = {
'mcp.toProject': 'To Project',
'mcp.toGlobal': 'To Global',
+ // Recommended MCP
+ 'mcp.recommended': 'Recommended MCP',
+ 'mcp.quickSetup': 'Quick Setup',
+ 'mcp.configRequired': 'config required',
+ 'mcp.noConfigNeeded': 'No config needed',
+ 'mcp.reconfigure': 'Configure',
+ 'mcp.wizard.install': 'Install',
+ 'mcp.wizard.noConfig': 'No configuration required. Ready to install!',
+ 'mcp.wizard.installTo': 'Install to',
+ 'mcp.wizard.project': 'Project',
+ 'mcp.wizard.global': 'Global',
+
// MCP CLI Mode
'mcp.cliMode': 'CLI Mode',
'mcp.claudeMode': 'Claude Mode',
@@ -2947,6 +2959,18 @@ const i18n = {
'mcp.noTemplatesDesc': '从现有服务器创建模板或添加新模板',
'mcp.templatesDesc': '浏览并安装预配置的 MCP 服务器模板',
+ // Recommended MCP
+ 'mcp.recommended': '推荐 MCP',
+ 'mcp.quickSetup': '快速安装',
+ 'mcp.configRequired': '需配置',
+ 'mcp.noConfigNeeded': '无需配置',
+ 'mcp.reconfigure': '配置',
+ 'mcp.wizard.install': '安装',
+ 'mcp.wizard.noConfig': '无需配置,可直接安装!',
+ 'mcp.wizard.installTo': '安装到',
+ 'mcp.wizard.project': '项目',
+ 'mcp.wizard.global': '全局',
+
// MCP CLI Mode
'mcp.cliMode': 'CLI 模式',
'mcp.claudeMode': 'Claude 模式',
diff --git a/ccw/src/templates/dashboard-js/views/mcp-manager.js b/ccw/src/templates/dashboard-js/views/mcp-manager.js
index af4302c4..40dfe2d6 100644
--- a/ccw/src/templates/dashboard-js/views/mcp-manager.js
+++ b/ccw/src/templates/dashboard-js/views/mcp-manager.js
@@ -549,6 +549,67 @@ async function renderMcpManager() {
+
+
+
+
+
+
+
${t('mcp.recommended')}
+
+
+ ${t('mcp.quickSetup')}
+
+
+
+
+
+ ${getRecommendedMcpServers().map(mcp => {
+ const installStatus = isRecommendedMcpInstalled(mcp.id);
+ return `
+
+
+
+
+
+
+
+
${escapeHtml(mcp.name)}
+ ${mcp.category}
+
+
+ ${installStatus.installed ? `
+
+
+ ${installStatus.scope}
+
+ ` : ''}
+
+
${escapeHtml(mcp.description)}
+
+ ${mcp.fields.length > 0 ? `
+
+
+ ${mcp.fields.length} ${t('mcp.configRequired')}
+
+ ` : `
+
+
+ ${t('mcp.noConfigNeeded')}
+
+ `}
+
+
+
+ `;
+ }).join('')}
+
+
+