Skip to main content
Glama

find_symbol

Read-onlyIdempotent

Locate function, class, variable, and type definitions within project code to quickly find symbol implementations and references.

Instructions

함수 찾아|클래스 어디|변수 위치|find function|where is|locate - Find symbol definitions

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
symbolNameYesName of the symbol to find
projectPathYesProject directory path
symbolTypeNoType of symbol to search for

Implementation Reference

  • Main execution logic for the 'find_symbol' tool. Parses TypeScript files using ts-morph and Python files using PythonParser, finds matching symbols by name and type, collects locations, sorts by exact match, and returns formatted results.
    export async function findSymbol(args: { 
      symbolName: string; 
      projectPath: string; 
      symbolType?: string 
    }): Promise<ToolResult> {
      const { symbolName, projectPath, symbolType = 'all' } = args;
      
      try {
        // Use cached project for performance
        const projectCache = ProjectCache.getInstance();
        const project = projectCache.getOrCreate(projectPath);
    
        const symbols: SymbolInfo[] = [];
    
        // 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 (const pyFile of pythonFiles) {
          try {
            const content = await readFile(pyFile, 'utf-8');
            const pythonSymbols = await PythonParser.findSymbols(content);
    
            for (const pySymbol of pythonSymbols) {
              if (pySymbol.name.includes(symbolName) &&
                  (symbolType === 'all' || symbolType === pySymbol.kind)) {
                symbols.push({
                  name: pySymbol.name,
                  kind: pySymbol.kind,
                  filePath: pyFile,
                  line: pySymbol.line,
                  column: pySymbol.column,
                  preview: pySymbol.docstring?.substring(0, 100) || `${pySymbol.kind} ${pySymbol.name}`
                });
              }
            }
          } catch (error) {
            // Skip files that can't be parsed
            console.error(`Error parsing Python file ${pyFile}:`, error);
          }
        }
    
        // Search through all source 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 matching symbols based on type
          sourceFile.forEachDescendant((node) => {
            const nodeSymbol = extractSymbolInfo(node, symbolName, symbolType);
            if (nodeSymbol) {
              const start = node.getStartLinePos();
              const pos = sourceFile.getLineAndColumnAtPos(start);
              
              symbols.push({
                name: nodeSymbol.name,
                kind: nodeSymbol.kind,
                filePath: filePath,
                line: pos.line,
                column: pos.column,
                preview: node.getText().substring(0, 100)
              });
            }
          });
        }
        
        // Sort by relevance (exact matches first)
        symbols.sort((a, b) => {
          const aExact = a.name === symbolName ? 0 : 1;
          const bExact = b.name === symbolName ? 0 : 1;
          return aExact - bExact;
        });
        
        return {
          content: [{
            type: 'text',
            text: `Found ${symbols.length} symbols:\n${symbols.slice(0, 20).map(s =>
              `${s.name} (${s.kind}) - ${s.filePath}:${s.line}`
            ).join('\n')}`
          }]
        };
      } catch (error) {
        return {
          content: [{ 
            type: 'text', 
            text: `Error finding symbol: ${error instanceof Error ? error.message : 'Unknown error'}` 
          }]
        };
      }
    }
  • ToolDefinition object defining the input schema, description, and annotations for the 'find_symbol' tool.
    export const findSymbolDefinition: ToolDefinition = {
      name: 'find_symbol',
      description: '함수 찾아|클래스 어디|변수 위치|find function|where is|locate - Find symbol definitions',
      inputSchema: {
        type: 'object',
        properties: {
          symbolName: { type: 'string', description: 'Name of the symbol to find' },
          projectPath: { type: 'string', description: 'Project directory path' },
          symbolType: {
            type: 'string',
            enum: ['all', 'function', 'class', 'interface', 'variable', 'type'],
            description: 'Type of symbol to search for'
          }
        },
        required: ['symbolName', 'projectPath']
      },
      annotations: {
        title: 'Find Symbol',
        audience: ['user', 'assistant'],
        readOnlyHint: true,
        destructiveHint: false,
        idempotentHint: true,
        openWorldHint: false
      }
    };
  • src/index.ts:177-181 (registration)
    Registration of the 'find_symbol' handler in the toolHandlers map used for dynamic tool dispatch.
    // Code Analysis
    'find_symbol': findSymbol,
    'find_references': findReferences,
    'analyze_dependency_graph': analyzeDependencyGraph,
  • src/index.ts:110-112 (registration)
    Inclusion of the findSymbolDefinition (schema) in the tools array provided via ListToolsRequest.
    // Code Analysis - Semantic (2)
    findSymbolDefinition,
    findReferencesDefinition,
  • Helper function that inspects TypeScript AST nodes to identify and classify symbols matching the search criteria.
    function extractSymbolInfo(
      node: Node, 
      symbolName: string, 
      symbolType: string
    ): { name: string; kind: string } | null {
      const kind = node.getKind();
      
      // Function declarations and expressions
      if (symbolType === 'all' || symbolType === 'function') {
        if (Node.isFunctionDeclaration(node) || Node.isMethodDeclaration(node)) {
          const name = node.getName();
          if (name && name.includes(symbolName)) {
            return { name, kind: 'function' };
          }
        }
        if (Node.isVariableDeclaration(node)) {
          const name = node.getName();
          const initializer = node.getInitializer();
          if (name && name.includes(symbolName) && 
              (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer))) {
            return { name, kind: 'function' };
          }
        }
      }
      
      // Class declarations
      if (symbolType === 'all' || symbolType === 'class') {
        if (Node.isClassDeclaration(node)) {
          const name = node.getName();
          if (name && name.includes(symbolName)) {
            return { name, kind: 'class' };
          }
        }
      }
      
      // Interface declarations
      if (symbolType === 'all' || symbolType === 'interface') {
        if (Node.isInterfaceDeclaration(node)) {
          const name = node.getName();
          if (name && name.includes(symbolName)) {
            return { name, kind: 'interface' };
          }
        }
      }
      
      // Type aliases
      if (symbolType === 'all' || symbolType === 'type') {
        if (Node.isTypeAliasDeclaration(node)) {
          const name = node.getName();
          if (name && name.includes(symbolName)) {
            return { name, kind: 'type' };
          }
        }
      }
      
      // Variables
      if (symbolType === 'all' || symbolType === 'variable') {
        if (Node.isVariableDeclaration(node)) {
          const name = node.getName();
          const initializer = node.getInitializer();
          if (name && name.includes(symbolName) && 
              !Node.isArrowFunction(initializer) && !Node.isFunctionExpression(initializer)) {
            return { name, kind: 'variable' };
          }
        }
      }
      
      return null;
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint=true, destructiveHint=false, idempotentHint=true, and openWorldHint=false, covering safety and idempotency. The description adds minimal behavioral context beyond this - it implies a search operation but doesn't describe what happens with multiple matches, error conditions, or performance characteristics. No contradiction with annotations exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single run-on string with pipe separators and dashes, lacking proper sentence structure. While it's brief, the formatting makes it harder to parse than a well-structured sentence. The information is front-loaded but presented in a disorganized manner that reduces clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with good annotations (read-only, idempotent) and full schema coverage, the description provides basic purpose but lacks important context. Without an output schema, it doesn't describe what results look like (locations, line numbers, confidence scores). The description doesn't address scope limitations or how it interacts with the project structure beyond the projectPath parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with all parameters well-documented in the schema itself. The description doesn't add any meaningful parameter semantics beyond what's in the schema - it mentions symbol types (function, class, variable) which are already covered by the symbolType enum, but provides no additional context about how parameters interact or special considerations.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool finds symbol definitions with specific examples (function, class, variable) and synonyms (find, locate, where is). It distinguishes from some siblings like 'find_references' by focusing on definitions rather than references. However, it doesn't explicitly contrast with all similar tools like 'search_memories_advanced' which might also search for symbols.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention sibling tools like 'find_references' (for finding references rather than definitions) or 'search_memories_advanced' (which might search across different contexts). There are no explicit when/when-not instructions or prerequisites stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/su-record/hi-ai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server