feat: Add CCW MCP server and tools integration

- Introduced `ccw-mcp` command for running CCW tools as an MCP server.
- Updated `package.json` to include new MCP dependencies and scripts.
- Enhanced CLI with new options for `codex_lens` tool.
- Implemented MCP server logic to expose CCW tools via Model Context Protocol.
- Added new tools and updated existing ones for better functionality and documentation.
- Created quick start and full documentation for MCP server usage.
- Added tests for MCP server functionality to ensure reliability.
This commit is contained in:
catlog22
2025-12-13 09:14:57 +08:00
parent 15122b9ebb
commit d4e59770d0
20 changed files with 1829 additions and 200 deletions

View File

@@ -383,6 +383,30 @@ async function searchCode(params) {
return result;
}
/**
* Search code and return only file paths
* @param {Object} params - Search parameters
* @returns {Promise<Object>}
*/
async function searchFiles(params) {
const { query, path = '.', limit = 20 } = params;
const args = ['search', query, '--files-only', '--limit', limit.toString(), '--json'];
const result = await executeCodexLens(args, { cwd: path });
if (result.success) {
try {
result.files = JSON.parse(result.output);
delete result.output;
} catch {
// Keep raw output if JSON parse fails
}
}
return result;
}
/**
* Extract symbols from a file
* @param {Object} params - Parameters
@@ -474,6 +498,9 @@ async function execute(params) {
case 'search':
return searchCode(rest);
case 'search_files':
return searchFiles(rest);
case 'symbol':
return extractSymbols(rest);
@@ -497,7 +524,7 @@ async function execute(params) {
return checkVenvStatus();
default:
throw new Error(`Unknown action: ${action}. Valid actions: init, search, symbol, status, update, bootstrap, check`);
throw new Error(`Unknown action: ${action}. Valid actions: init, search, search_files, symbol, status, update, bootstrap, check`);
}
}
@@ -506,38 +533,30 @@ async function execute(params) {
*/
export const codexLensTool = {
name: 'codex_lens',
description: `Code indexing and semantic search via CodexLens Python package.
description: `Code indexing and search.
Actions:
- init: Initialize index for a directory
- search: Search code (text or semantic mode)
- symbol: Extract symbols from a file
- status: Get index status
- update: Incrementally update specific files (add/modify/remove)
- bootstrap: Force re-install CodexLens venv
- check: Check venv readiness
Features:
- Automatic venv bootstrap at ~/.codexlens/venv
- SQLite FTS5 full-text search
- Tree-sitter symbol extraction
- Incremental updates for changed files
- Optional semantic search with embeddings`,
Usage:
codex_lens(action="init", path=".") # Index directory
codex_lens(action="search", query="func", path=".") # Search code
codex_lens(action="search_files", query="x") # Search, return paths only
codex_lens(action="symbol", file="f.py") # Extract symbols
codex_lens(action="status") # Index status
codex_lens(action="update", files=["a.js"]) # Update specific files`,
parameters: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['init', 'search', 'symbol', 'status', 'update', 'bootstrap', 'check'],
enum: ['init', 'search', 'search_files', 'symbol', 'status', 'update', 'bootstrap', 'check'],
description: 'Action to perform'
},
path: {
type: 'string',
description: 'Target path (for init, search, status, update)'
description: 'Target path (for init, search, search_files, status, update)'
},
query: {
type: 'string',
description: 'Search query (for search action)'
description: 'Search query (for search and search_files actions)'
},
mode: {
type: 'string',
@@ -561,7 +580,7 @@ Features:
},
limit: {
type: 'number',
description: 'Maximum results (for search action)',
description: 'Maximum results (for search and search_files actions)',
default: 20
},
format: {

View File

@@ -391,14 +391,13 @@ async function execute(params) {
*/
export const editFileTool = {
name: 'edit_file',
description: `Edit file with two modes:
- update: Replace oldText with newText (default). Supports multiple edits via 'edits' array.
- line: Position-driven line operations (insert_before, insert_after, replace, delete)
description: `Edit file by text replacement or line operations.
Features:
- dryRun: Preview changes without modifying file (returns diff)
- Auto line ending adaptation (CRLF/LF)
- Fuzzy matching for whitespace differences`,
Usage:
edit_file(path="f.js", oldText="old", newText="new")
edit_file(path="f.js", mode="line", operation="insert_after", line=10, text="new line")
Options: dryRun=true (preview diff), replaceAll=true (replace all occurrences)`,
parameters: {
type: 'object',
properties: {

View File

@@ -722,28 +722,15 @@ async function execute(params) {
export const sessionManagerTool = {
name: 'session_manager',
description: `Workflow session lifecycle management tool.
Operations:
- init: Create new session with directory structure
- list: List sessions (active, archived, or both)
- read: Read file content by content_type
- write: Write content to file by content_type
- update: Update existing JSON file (shallow merge)
- archive: Move session from active to archives
- mkdir: Create directories within session
- delete: Delete a file within session
- stats: Get session statistics (tasks, summaries, plan)
Content Types:
session, plan, task, summary, process, chat, brainstorm,
review-dim, review-iter, review-fix, todo, context
description: `Workflow session management.
Usage:
ccw tool exec session_manager '{"operation":"list"}'
ccw tool exec session_manager '{"operation":"init","session_id":"WFS-test"}'
ccw tool exec session_manager '{"operation":"read","session_id":"WFS-test","content_type":"session"}'
ccw tool exec session_manager '{"operation":"stats","session_id":"WFS-test"}'`,
session_manager(operation="init", type="workflow", description="...")
session_manager(operation="list", location="active|archived|both")
session_manager(operation="read", sessionId="WFS-xxx", contentType="plan|task|summary")
session_manager(operation="write", sessionId="WFS-xxx", contentType="plan", content={...})
session_manager(operation="archive", sessionId="WFS-xxx")
session_manager(operation="stats", sessionId="WFS-xxx")`,
parameters: {
type: 'object',

View File

@@ -577,19 +577,14 @@ async function execute(params) {
*/
export const smartSearchTool = {
name: 'smart_search',
description: `Unified search with intelligent mode selection.
description: `Intelligent code search with multiple modes.
Modes:
- auto: Classify intent and recommend optimal search mode (default)
- exact: Precise literal matching via ripgrep
- fuzzy: Approximate matching with typo tolerance
- semantic: Natural language understanding via LLM/embeddings
- graph: Dependency relationship traversal
Usage:
smart_search(query="function main", path=".") # Auto-select mode
smart_search(query="def init", mode="exact") # Exact match
smart_search(query="authentication logic", mode="semantic") # NL search
Features:
- Multi-backend search coordination
- Result fusion with RRF ranking
- Configurable result limits and context`,
Modes: auto (default), exact, fuzzy, semantic, graph`,
parameters: {
type: 'object',
properties: {

View File

@@ -110,14 +110,10 @@ async function execute(params) {
*/
export const writeFileTool = {
name: 'write_file',
description: `Create a new file or overwrite an existing file with content.
description: `Write content to file. Auto-creates parent directories.
Features:
- Creates parent directories automatically (configurable)
- Optional backup before overwrite
- Supports text content with proper encoding
Use with caution as it will overwrite existing files without warning unless backup is enabled.`,
Usage: write_file(path="file.js", content="code here")
Options: backup=true (backup before overwrite), encoding="utf8"`,
parameters: {
type: 'object',
properties: {