find_references
Locate all references and usages of code symbols within a project to analyze dependencies and understand implementation patterns.
Instructions
where used|references|usages|find usage|references|where used - Find symbol references
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| symbolName | Yes | Name of the symbol to find references for | |
| filePath | No | File path where the symbol is defined | |
| line | No | Line number of the symbol definition | |
| projectPath | Yes | Project directory path |
Implementation Reference
- The core handler function implementing the 'find_references' tool. Uses ts-morph for precise TypeScript references, string matching for Python files, project caching for performance, and collects definitions vs usages.export async function findReferences(args: { symbolName: string; filePath?: string; line?: number; projectPath: string; }): Promise<ToolResult> { const { symbolName, filePath, line, projectPath } = args; try { // Use cached project for performance const projectCache = ProjectCache.getInstance(); const project = projectCache.getOrCreate(projectPath); const allReferences: ReferenceInfo[] = []; // Check for Python files const glob = await import('glob'); const pythonFiles = glob.globSync(path.join(projectPath, '**/*.py'), { ignore: ['**/node_modules/**', '**/.git/**', '**/venv/**', '**/__pycache__/**'] }); // Parse Python files for references for (const pyFile of pythonFiles) { try { const content = await readFile(pyFile, 'utf-8'); const lines = content.split('\n'); lines.forEach((line, index) => { if (line.includes(symbolName)) { const column = line.indexOf(symbolName); allReferences.push({ filePath: pyFile, line: index + 1, column: column, text: line.trim().substring(0, 100), isDefinition: /^(def|class)\s/.test(line.trim()) }); } }); } catch (error) { console.error(`Error parsing Python file ${pyFile}:`, error); } } // If specific file and line provided, use precise reference finding if (filePath && line) { const sourceFile = project.getSourceFile(filePath); if (sourceFile) { const position = sourceFile.compilerNode.getPositionOfLineAndCharacter(line - 1, 0); const node = sourceFile.getDescendantAtPos(position); if (node) { const symbol = node.getSymbol(); if (symbol) { const references = project.getLanguageService().findReferencesAtPosition(sourceFile, position); if (references) { for (const ref of references) { for (const reference of ref.getReferences()) { const refSourceFile = reference.getSourceFile(); const refNode = reference.getNode(); const start = refNode.getStartLinePos(); const pos = refSourceFile.getLineAndColumnAtPos(start); allReferences.push({ filePath: refSourceFile.getFilePath(), line: pos.line, column: pos.column, text: refNode.getParent()?.getText().substring(0, 100) || refNode.getText(), isDefinition: reference.isDefinition() || false }); } } } } } } } else { // Fallback: search by name across all files for (const sourceFile of project.getSourceFiles()) { const filePath = sourceFile.getFilePath(); // Skip node_modules and other irrelevant paths if (filePath.includes('node_modules') || filePath.includes('.git')) { continue; } // Find all identifiers matching the symbol name sourceFile.forEachDescendant((node) => { if (Node.isIdentifier(node) && node.getText() === symbolName) { const start = node.getStartLinePos(); const pos = sourceFile.getLineAndColumnAtPos(start); const parent = node.getParent(); // Determine if this is a definition const isDefinition = isSymbolDefinition(node); allReferences.push({ filePath: filePath, line: pos.line, column: pos.column, text: parent?.getText().substring(0, 100) || node.getText(), isDefinition }); } }); } } const definitions = allReferences.filter(r => r.isDefinition); const usages = allReferences.filter(r => !r.isDefinition); return { content: [{ type: 'text', text: `Found ${allReferences.length} references (${definitions.length} defs, ${usages.length} uses):\n${allReferences.slice(0, 20).map(r => `${r.isDefinition ? 'DEF' : 'USE'}: ${r.filePath}:${r.line}` ).join('\n')}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error finding references: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } }
- ToolDefinition object defining the input schema, description, and metadata for the 'find_references' tool.export const findReferencesDefinition: ToolDefinition = { name: 'find_references', description: 'where used|references|usages|find usage|references|where used - Find symbol references', inputSchema: { type: 'object', properties: { symbolName: { type: 'string', description: 'Name of the symbol to find references for' }, filePath: { type: 'string', description: 'File path where the symbol is defined' }, line: { type: 'number', description: 'Line number of the symbol definition' }, projectPath: { type: 'string', description: 'Project directory path' } }, required: ['symbolName', 'projectPath'] }, annotations: { title: 'Find References', audience: ['user', 'assistant'] } };
- src/index.ts:612-613 (registration)Registration of the find_references tool handler in the main switch statement for tool execution.case 'find_references': return await findReferences(args as any) as CallToolResult;
- src/index.ts:110-110 (registration)Addition of findReferencesDefinition to the tools array for MCP listTools endpoint.findReferencesDefinition,
- Helper function to determine if a node represents a symbol definition (used in fallback search).function isSymbolDefinition(node: Node): boolean { const parent = node.getParent(); if (!parent) return false; // Check if this is a declaration return Node.isFunctionDeclaration(parent) || Node.isClassDeclaration(parent) || Node.isInterfaceDeclaration(parent) || Node.isTypeAliasDeclaration(parent) || Node.isVariableDeclaration(parent) || Node.isMethodDeclaration(parent) || Node.isPropertyDeclaration(parent) || Node.isParameterDeclaration(parent); }