Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/fix-mcp-adapters-and-descriptions.md
Original file line number Diff line number Diff line change
@@ -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.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,6 @@ Thumbs.db
# Temporary files and invalid paths
temp/
*-github/*.tgz

# Work in progress packages (not ready for commit)
packages/benchmark/
93 changes: 82 additions & 11 deletions packages/cli/src/commands/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand All @@ -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',
Expand All @@ -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,
});

Expand All @@ -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();
}
Expand All @@ -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)');
Expand Down Expand Up @@ -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)}`);
Expand Down Expand Up @@ -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)}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
3 changes: 2 additions & 1 deletion packages/mcp-server/src/adapters/built-in/explore-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
4 changes: 3 additions & 1 deletion packages/mcp-server/src/adapters/built-in/github-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion packages/mcp-server/src/adapters/built-in/history-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion packages/mcp-server/src/adapters/built-in/map-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion packages/mcp-server/src/adapters/built-in/plan-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
3 changes: 2 additions & 1 deletion packages/mcp-server/src/adapters/built-in/refs-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
4 changes: 3 additions & 1 deletion packages/mcp-server/src/adapters/built-in/search-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.