Add tests and documentation for CodexLens LSP tool

- Introduced a new test script for the CodexLens LSP tool to validate core functionalities including symbol search, find definition, find references, and get hover.
- Created comprehensive documentation for the MCP endpoint design, detailing the architecture, features, and integration with the CCW MCP Manager.
- Developed a detailed implementation plan for transitioning to a real LSP server, outlining phases, architecture, and acceptance criteria.
This commit is contained in:
catlog22
2026-01-19 23:26:35 +08:00
parent eeaefa7208
commit 3fe630f221
24 changed files with 3044 additions and 509 deletions

View File

@@ -1426,6 +1426,34 @@ const RECOMMENDED_MCP_SERVERS = [
const env = values.apiKey ? { EXA_API_KEY: values.apiKey } : undefined;
return buildCrossPlatformMcpConfig('npx', ['-y', 'exa-mcp-server'], { env });
}
},
{
id: 'codex-lens-tools',
nameKey: 'mcp.codexLens.name',
descKey: 'mcp.codexLens.desc',
icon: 'code-2',
category: 'code-intelligence',
fields: [
{
key: 'tools',
labelKey: 'mcp.codexLens.field.tools',
type: 'multi-select',
options: [
{ value: 'symbol.search', label: 'Symbol Search', desc: 'Workspace symbol search' },
{ value: 'symbol.findDefinition', label: 'Find Definition', desc: 'Go to definition' },
{ value: 'symbol.findReferences', label: 'Find References', desc: 'Find all references' },
{ value: 'symbol.getHoverInfo', label: 'Hover Information', desc: 'Rich symbol info' }
],
default: ['symbol.search', 'symbol.findDefinition', 'symbol.findReferences'],
required: true,
descKey: 'mcp.codexLens.field.tools.desc'
}
],
buildConfig: (values) => {
const tools = values.tools || [];
const env = { CODEXLENS_ENABLED_TOOLS: tools.join(',') };
return buildCrossPlatformMcpConfig('npx', ['-y', 'codex-lens-mcp'], { env });
}
}
];
@@ -1503,12 +1531,30 @@ function openRecommendedMcpWizard(mcpId) {
${field.required ? '<span class="text-destructive">*</span>' : ''}
</label>
${field.descKey ? `<p class="text-xs text-muted-foreground">${escapeHtml(t(field.descKey))}</p>` : ''}
<input type="${field.type || 'text'}"
id="wizard-field-${field.key}"
class="w-full px-3 py-2 text-sm bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
placeholder="${escapeHtml(field.placeholder || '')}"
value="${escapeHtml(field.default || '')}"
${field.required ? 'required' : ''}>
${field.type === 'multi-select' ? `
<div id="wizard-field-${field.key}" class="space-y-2 p-2 bg-muted/30 border border-border rounded-lg max-h-48 overflow-y-auto">
${(field.options || []).map(opt => {
const isChecked = (field.default || []).includes(opt.value);
return `
<label class="flex items-center gap-2 p-2 rounded-md hover:bg-accent cursor-pointer transition-colors">
<input type="checkbox"
class="wizard-multi-select-${field.key} rounded border-border text-primary focus:ring-primary"
value="${escapeHtml(opt.value)}"
${isChecked ? 'checked' : ''}>
<span class="text-sm text-foreground">${escapeHtml(opt.label)}</span>
${opt.desc ? `<span class="text-xs text-muted-foreground ml-auto">${escapeHtml(opt.desc)}</span>` : ''}
</label>
`;
}).join('')}
</div>
` : `
<input type="${field.type || 'text'}"
id="wizard-field-${field.key}"
class="w-full px-3 py-2 text-sm bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
placeholder="${escapeHtml(field.placeholder || '')}"
value="${escapeHtml(field.default || '')}"
${field.required ? 'required' : ''}>
`}
</div>
`).join('')}
</div>
@@ -1616,17 +1662,31 @@ async function submitRecommendedMcpWizard(mcpId) {
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.type === 'multi-select') {
// Collect all checked checkboxes for multi-select field
const checkboxes = document.querySelectorAll(`.wizard-multi-select-${field.key}:checked`);
const selectedValues = Array.from(checkboxes).map(cb => cb.value);
if (field.required && !value) {
showRefreshToast(`${t(field.labelKey)} is required`, 'error');
if (input) input.focus();
hasError = true;
break;
if (field.required && selectedValues.length === 0) {
showRefreshToast(`${t(field.labelKey)} - ${t('mcp.wizard.selectAtLeastOne')}`, 'error');
hasError = true;
break;
}
values[field.key] = selectedValues;
} else {
const input = document.getElementById(`wizard-field-${field.key}`);
const value = input ? input.value.trim() : '';
if (field.required && !value) {
showRefreshToast(`${t(field.labelKey)} is required`, 'error');
if (input) input.focus();
hasError = true;
break;
}
values[field.key] = value;
}
values[field.key] = value;
}
if (hasError) return;

View File

@@ -956,6 +956,11 @@ const i18n = {
'mcp.exa.desc': 'AI-powered web search with real-time crawling and content extraction',
'mcp.exa.field.apiKey': 'EXA API Key',
'mcp.exa.field.apiKey.desc': 'Optional - Free tier has rate limits. Get key from exa.ai for higher limits',
'mcp.codexLens.name': 'CodexLens Tools',
'mcp.codexLens.desc': 'Code intelligence tools for symbol search, navigation, and reference finding',
'mcp.codexLens.field.tools': 'Enabled Tools',
'mcp.codexLens.field.tools.desc': 'Select the code intelligence tools to enable for this MCP server',
'mcp.wizard.selectAtLeastOne': 'Please select at least one option',
// MCP CLI Mode
'mcp.cliMode': 'CLI Mode',
@@ -3278,6 +3283,11 @@ const i18n = {
'mcp.exa.desc': 'AI 驱动的网络搜索,支持实时爬取和内容提取',
'mcp.exa.field.apiKey': 'EXA API 密钥',
'mcp.exa.field.apiKey.desc': '可选 - 免费版有速率限制,从 exa.ai 获取密钥可提高配额',
'mcp.codexLens.name': 'CodexLens 工具',
'mcp.codexLens.desc': '代码智能工具,提供符号搜索、代码导航和引用查找功能',
'mcp.codexLens.field.tools': '启用的工具',
'mcp.codexLens.field.tools.desc': '选择要启用的代码智能工具',
'mcp.wizard.selectAtLeastOne': '请至少选择一个选项',
// MCP CLI Mode
'mcp.cliMode': 'CLI 模式',