diff --git a/.changeset/fix-mcp-adapters-and-descriptions.md b/.changeset/fix-mcp-adapters-and-descriptions.md new file mode 100644 index 0000000..08836a1 --- /dev/null +++ b/.changeset/fix-mcp-adapters-and-descriptions.md @@ -0,0 +1,23 @@ +--- +"@lytics/dev-agent": patch +"@lytics/dev-agent-cli": patch +"@lytics/dev-agent-mcp": patch +--- + +Fix MCP server to include all 9 adapters and improve tool descriptions for better AI tool adoption + +**Bug Fix:** +- CLI's `mcp start` command now registers all 9 adapters (was missing HealthAdapter, RefsAdapter, MapAdapter, HistoryAdapter) +- Updated tool list in CLI output and install messages to show all 9 tools + +**Tool Description Improvements:** +- `dev_search`: Added "USE THIS FIRST" trigger, comparison to grep for conceptual queries +- `dev_map`: Clarified it shows component counts and exports, better than list_dir +- `dev_explore`: Clarified workflow - use after dev_search for "similar" and "relationships" actions +- `dev_refs`: Added guidance to use for specific symbols, use dev_search for conceptual queries +- `dev_history`: Added "WHY" trigger, clarified semantic search over commits +- `dev_plan`: Emphasized "ALL context in one call" value prop for GitHub issues +- `dev_gh`: Clarified semantic search by meaning, not just keywords + +These description improvements help AI tools (Claude, Cursor) choose the right dev-agent tool for each task. + diff --git a/.gitignore b/.gitignore index e477bb5..b8143ee 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ Thumbs.db # Temporary files and invalid paths temp/ *-github/*.tgz + +# Work in progress packages (not ready for commit) +packages/benchmark/ diff --git a/packages/cli/src/commands/mcp.ts b/packages/cli/src/commands/mcp.ts index 8c419c3..cc3a3f5 100644 --- a/packages/cli/src/commands/mcp.ts +++ b/packages/cli/src/commands/mcp.ts @@ -6,12 +6,23 @@ import { spawn } from 'node:child_process'; import * as fs from 'node:fs/promises'; import * as path from 'node:path'; -import { getStorageFilePaths, getStoragePath, RepositoryIndexer } from '@lytics/dev-agent-core'; +import { + GitIndexer, + getStorageFilePaths, + getStoragePath, + LocalGitExtractor, + RepositoryIndexer, + VectorStorage, +} from '@lytics/dev-agent-core'; import { ExploreAdapter, GitHubAdapter, + HealthAdapter, + HistoryAdapter, + MapAdapter, MCPServer, PlanAdapter, + RefsAdapter, SearchAdapter, StatusAdapter, } from '@lytics/dev-agent-mcp'; @@ -101,13 +112,6 @@ export const mcpCommand = new Command('mcp') defaultSection: 'summary', }); - const planAdapter = new PlanAdapter({ - repositoryIndexer: indexer, - repositoryPath, - defaultFormat: 'compact', - timeout: 60000, - }); - const exploreAdapter = new ExploreAdapter({ repositoryPath, repositoryIndexer: indexer, @@ -124,7 +128,53 @@ export const mcpCommand = new Command('mcp') defaultFormat: 'compact', }); - // Create MCP server + const healthAdapter = new HealthAdapter({ + repositoryPath, + vectorStorePath: vectors, + githubStatePath: getStorageFilePaths(storagePath).githubState, + }); + + const refsAdapter = new RefsAdapter({ + repositoryIndexer: indexer, + defaultLimit: 20, + }); + + const mapAdapter = new MapAdapter({ + repositoryIndexer: indexer, + repositoryPath, + defaultDepth: 2, + defaultTokenBudget: 2000, + }); + + // Create git extractor and indexer (needed by plan and history adapters) + const gitExtractor = new LocalGitExtractor(repositoryPath); + const gitVectorStorage = new VectorStorage({ + storePath: `${vectors}-git`, + }); + await gitVectorStorage.initialize(); + + const gitIndexer = new GitIndexer({ + extractor: gitExtractor, + vectorStorage: gitVectorStorage, + }); + + const historyAdapter = new HistoryAdapter({ + gitIndexer, + gitExtractor, + defaultLimit: 10, + defaultTokenBudget: 2000, + }); + + // Update plan adapter to include git indexer + const planAdapterWithGit = new PlanAdapter({ + repositoryIndexer: indexer, + gitIndexer, + repositoryPath, + defaultFormat: 'compact', + timeout: 60000, + }); + + // Create MCP server with all 9 adapters const server = new MCPServer({ serverInfo: { name: 'dev-agent', @@ -135,7 +185,17 @@ export const mcpCommand = new Command('mcp') logLevel: logLevel as 'debug' | 'info' | 'warn' | 'error', }, transport: options.transport === 'stdio' ? 'stdio' : undefined, - adapters: [searchAdapter, statusAdapter, planAdapter, exploreAdapter, githubAdapter], + adapters: [ + searchAdapter, + statusAdapter, + planAdapterWithGit, + exploreAdapter, + githubAdapter, + healthAdapter, + refsAdapter, + mapAdapter, + historyAdapter, + ], coordinator, }); @@ -144,6 +204,7 @@ export const mcpCommand = new Command('mcp') logger.info('Shutting down MCP server...'); await server.stop(); await indexer.close(); + await gitVectorStorage.close(); if (githubAdapter.githubIndexer) { await githubAdapter.githubIndexer.close(); } @@ -157,7 +218,9 @@ export const mcpCommand = new Command('mcp') await server.start(); logger.info(chalk.green('MCP server started successfully!')); - logger.info('Available tools: dev_search, dev_status, dev_plan, dev_explore, dev_gh'); + logger.info( + 'Available tools: dev_search, dev_status, dev_plan, dev_explore, dev_gh, dev_health, dev_refs, dev_map, dev_history' + ); if (options.transport === 'stdio') { logger.info('Server running on stdio transport (for AI tools)'); @@ -223,6 +286,10 @@ export const mcpCommand = new Command('mcp') logger.log(` ${chalk.cyan('dev_plan')} - Generate development plans`); logger.log(` ${chalk.cyan('dev_explore')} - Explore code patterns`); logger.log(` ${chalk.cyan('dev_gh')} - Search GitHub issues/PRs`); + logger.log(` ${chalk.cyan('dev_health')} - Server health checks`); + logger.log(` ${chalk.cyan('dev_refs')} - Find symbol references`); + logger.log(` ${chalk.cyan('dev_map')} - Generate codebase map`); + logger.log(` ${chalk.cyan('dev_history')} - Search git history`); logger.log(''); logger.log(`Repository: ${chalk.yellow(repositoryPath)}`); logger.log(`Storage: ${chalk.yellow(storagePath)}`); @@ -275,6 +342,10 @@ export const mcpCommand = new Command('mcp') logger.log(` ${chalk.cyan('dev_plan')} - Generate development plans`); logger.log(` ${chalk.cyan('dev_explore')} - Explore code patterns`); logger.log(` ${chalk.cyan('dev_gh')} - Search GitHub issues/PRs`); + logger.log(` ${chalk.cyan('dev_health')} - Server health checks`); + logger.log(` ${chalk.cyan('dev_refs')} - Find symbol references`); + logger.log(` ${chalk.cyan('dev_map')} - Generate codebase map`); + logger.log(` ${chalk.cyan('dev_history')} - Search git history`); logger.log(''); logger.log(`Repository: ${chalk.yellow(repositoryPath)}`); logger.log(`Storage: ${chalk.yellow(storagePath)}`); diff --git a/packages/mcp-server/src/adapters/__tests__/explore-adapter.test.ts b/packages/mcp-server/src/adapters/__tests__/explore-adapter.test.ts index 2c4f47e..6195887 100644 --- a/packages/mcp-server/src/adapters/__tests__/explore-adapter.test.ts +++ b/packages/mcp-server/src/adapters/__tests__/explore-adapter.test.ts @@ -43,9 +43,9 @@ describe('ExploreAdapter', () => { const definition = adapter.getToolDefinition(); expect(definition.name).toBe('dev_explore'); - expect(definition.description).toContain('semantic search'); + expect(definition.description).toContain('similar'); expect(definition.inputSchema.required).toEqual(['action', 'query']); - expect(definition.inputSchema.properties.action.enum).toEqual([ + expect(definition.inputSchema.properties?.action.enum).toEqual([ 'pattern', 'similar', 'relationships', diff --git a/packages/mcp-server/src/adapters/__tests__/history-adapter.test.ts b/packages/mcp-server/src/adapters/__tests__/history-adapter.test.ts index c1b410c..7984c8c 100644 --- a/packages/mcp-server/src/adapters/__tests__/history-adapter.test.ts +++ b/packages/mcp-server/src/adapters/__tests__/history-adapter.test.ts @@ -85,7 +85,7 @@ describe('HistoryAdapter', () => { const definition = adapter.getToolDefinition(); expect(definition.name).toBe('dev_history'); - expect(definition.description).toContain('git commit history'); + expect(definition.description).toContain('commits'); expect(definition.inputSchema.properties).toHaveProperty('query'); expect(definition.inputSchema.properties).toHaveProperty('file'); expect(definition.inputSchema.properties).toHaveProperty('limit'); diff --git a/packages/mcp-server/src/adapters/__tests__/map-adapter.test.ts b/packages/mcp-server/src/adapters/__tests__/map-adapter.test.ts index 52453e8..7c45eb9 100644 --- a/packages/mcp-server/src/adapters/__tests__/map-adapter.test.ts +++ b/packages/mcp-server/src/adapters/__tests__/map-adapter.test.ts @@ -91,7 +91,7 @@ describe('MapAdapter', () => { const def = adapter.getToolDefinition(); expect(def.name).toBe('dev_map'); - expect(def.description).toContain('codebase structure'); + expect(def.description).toContain('structural overview'); expect(def.inputSchema.type).toBe('object'); expect(def.inputSchema.properties).toHaveProperty('depth'); expect(def.inputSchema.properties).toHaveProperty('focus'); diff --git a/packages/mcp-server/src/adapters/__tests__/refs-adapter.test.ts b/packages/mcp-server/src/adapters/__tests__/refs-adapter.test.ts index f1e92dc..ad9abfc 100644 --- a/packages/mcp-server/src/adapters/__tests__/refs-adapter.test.ts +++ b/packages/mcp-server/src/adapters/__tests__/refs-adapter.test.ts @@ -100,7 +100,7 @@ describe('RefsAdapter', () => { const def = adapter.getToolDefinition(); expect(def.name).toBe('dev_refs'); - expect(def.description).toContain('call relationships'); + expect(def.description).toContain('calls'); expect(def.inputSchema.type).toBe('object'); expect(def.inputSchema.properties).toHaveProperty('name'); expect(def.inputSchema.properties).toHaveProperty('direction'); diff --git a/packages/mcp-server/src/adapters/built-in/explore-adapter.ts b/packages/mcp-server/src/adapters/built-in/explore-adapter.ts index 27d521e..8dc8ef2 100644 --- a/packages/mcp-server/src/adapters/built-in/explore-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/explore-adapter.ts @@ -72,7 +72,8 @@ export class ExploreAdapter extends ToolAdapter { return { name: 'dev_explore', description: - 'Explore code patterns and relationships using semantic search. Supports pattern search, similar code detection, and relationship mapping.', + 'After finding code with dev_search, use this for deeper analysis: "similar" finds other code that looks like a given file, ' + + '"relationships" maps a file\'s imports and what depends on it. (Also has "pattern" which works like dev_search.)', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/adapters/built-in/github-adapter.ts b/packages/mcp-server/src/adapters/built-in/github-adapter.ts index c869945..c1372fa 100644 --- a/packages/mcp-server/src/adapters/built-in/github-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/github-adapter.ts @@ -168,7 +168,9 @@ export class GitHubAdapter extends ToolAdapter { return { name: 'dev_gh', description: - 'Search GitHub issues and pull requests using semantic search. Supports filtering by type, state, labels, and more.', + 'Search GitHub issues/PRs by MEANING, not just keywords - finds relevant issues even without exact terms. ' + + 'Actions: "search" (semantic query), "context" (full details for issue #), "related" (find similar issues). ' + + 'Use when exploring project history or finding past discussions about a topic.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/adapters/built-in/history-adapter.ts b/packages/mcp-server/src/adapters/built-in/history-adapter.ts index 3bdd0fc..65d77de 100644 --- a/packages/mcp-server/src/adapters/built-in/history-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/history-adapter.ts @@ -72,7 +72,8 @@ export class HistoryAdapter extends ToolAdapter { return { name: 'dev_history', description: - 'Search git commit history semantically or get history for a specific file. Use this to understand what changed and why.', + 'Understand WHY code looks the way it does. Search commits by concept ("auth refactor", "bug fix") or get file history. ' + + 'Use after finding code with dev_search to understand its evolution.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/adapters/built-in/map-adapter.ts b/packages/mcp-server/src/adapters/built-in/map-adapter.ts index f394b34..4831ae3 100644 --- a/packages/mcp-server/src/adapters/built-in/map-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/map-adapter.ts @@ -77,7 +77,8 @@ export class MapAdapter extends ToolAdapter { return { name: 'dev_map', description: - 'Get a high-level overview of the codebase structure. Shows directories, component counts, and exported symbols.', + 'Get a structural overview showing WHAT IS IN each directory - not just file names but component counts (classes, functions, interfaces) ' + + 'and key exports. Better than list_dir when you need to understand code organization. Optionally shows git change frequency.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/adapters/built-in/plan-adapter.ts b/packages/mcp-server/src/adapters/built-in/plan-adapter.ts index 9be0364..9e7516f 100644 --- a/packages/mcp-server/src/adapters/built-in/plan-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/plan-adapter.ts @@ -83,7 +83,8 @@ export class PlanAdapter extends ToolAdapter { return { name: 'dev_plan', description: - 'Assemble context for implementing a GitHub issue. Returns issue details, relevant code snippets, and codebase patterns for LLM consumption.', + 'When implementing a GitHub issue, use this to get ALL context in one call: issue details, relevant code, similar patterns, ' + + 'and related commits. Saves multiple tool calls vs searching manually.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/adapters/built-in/refs-adapter.ts b/packages/mcp-server/src/adapters/built-in/refs-adapter.ts index 6ad9302..b728e47 100644 --- a/packages/mcp-server/src/adapters/built-in/refs-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/refs-adapter.ts @@ -73,7 +73,8 @@ export class RefsAdapter extends ToolAdapter { return { name: 'dev_refs', description: - 'Find call relationships for a function or method. Shows what calls it (callers) and what it calls (callees).', + 'Find who calls a function and what it calls. Use when you have a SPECIFIC symbol name and need to trace dependencies. ' + + 'For conceptual queries like "where is auth used", use dev_search instead.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/adapters/built-in/search-adapter.ts b/packages/mcp-server/src/adapters/built-in/search-adapter.ts index c272b50..0080965 100644 --- a/packages/mcp-server/src/adapters/built-in/search-adapter.ts +++ b/packages/mcp-server/src/adapters/built-in/search-adapter.ts @@ -64,7 +64,9 @@ export class SearchAdapter extends ToolAdapter { return { name: 'dev_search', description: - 'Semantic search for code components (functions, classes, interfaces) in the indexed repository', + 'USE THIS FIRST for code exploration. Semantic search finds code by meaning, not just keywords. ' + + 'Better than grep for conceptual queries like "authentication flow", "error handling", "database connections". ' + + 'Returns ranked results with context snippets.', inputSchema: { type: 'object', properties: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 054fe6d..811f47f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,6 +39,22 @@ importers: specifier: ^4.0.3 version: 4.0.3(@types/node@24.10.1) + packages/benchmark: + dependencies: + chalk: + specifier: ^5.6.2 + version: 5.6.2 + commander: + specifier: ^12.1.0 + version: 12.1.0 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.19.1 + typescript: + specifier: ^5.3.3 + version: 5.9.3 + packages/cli: dependencies: '@lytics/dev-agent-core':