Skip to main content
Glama

find_symbol

Locate function, class, or variable definitions in code projects to quickly find symbol implementations and understand code structure.

Instructions

find function|where is class|variable location|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

  • The main handler function that executes the 'find_symbol' tool. It searches for symbols in both TypeScript (using ts-morph) and Python files (using PythonParser), collects matching symbols, sorts by relevance, 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'}` 
          }]
        };
      }
    }
  • The ToolDefinition object for 'find_symbol', including name, description, input schema with parameters symbolName, projectPath, and optional symbolType.
    export const findSymbolDefinition: ToolDefinition = {
      name: 'find_symbol',
      description: 'find function|where is class|variable location|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']
      }
    };
  • src/index.ts:610-611 (registration)
    Registration in the executeToolCall switch statement that dispatches calls to the 'find_symbol' handler function.
    case 'find_symbol':
      return await findSymbol(args as any) as CallToolResult;
  • src/index.ts:109-109 (registration)
    Inclusion of findSymbolDefinition in the tools array, registering the tool for listing via MCP ListToolsRequest.
    findSymbolDefinition,
  • Helper function extractSymbolInfo that inspects TypeScript nodes to determine if they match the symbol query based on kind (function, class, etc.). Used in the main handler.
    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') && Node.isClassDeclaration(node)) {
            const name = node.getName();
            if (name && name.includes(symbolName)) {
              return { name, kind: 'class' };
            }
      }
      
      // Interface declarations
      if ((symbolType === 'all' || symbolType === 'interface') && Node.isInterfaceDeclaration(node)) {
            const name = node.getName();
            if (name && name.includes(symbolName)) {
              return { name, kind: 'interface' };
            }
      }
      
      // Type aliases
      if ((symbolType === 'all' || symbolType === 'type') && 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;
    }
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. The description only repeats the tool's purpose without explaining how it behaves—such as whether it searches recursively, returns multiple matches, handles partial names, or provides error messages. This leaves significant behavioral gaps for a tool with 3 parameters.

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 repetitive and poorly structured, with redundant phrases like 'find function|where is class|variable location|find function|where is|locate'. It lacks front-loading of key information and wastes space on synonyms instead of providing useful content, making it inefficient despite its brevity.

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

Completeness2/5

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

Given the tool's complexity (3 parameters, no annotations, no output schema), the description is incomplete. It fails to explain what the tool returns, how results are formatted, or any behavioral nuances, leaving the agent with insufficient context to use the tool effectively beyond basic parameter input.

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?

The schema description coverage is 100%, with clear descriptions for all parameters, including an enum for 'symbolType'. The description adds no additional meaning beyond what the schema provides, so it meets the baseline score of 3 for high schema coverage without compensating value.

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

Purpose2/5

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

The description is a tautology that essentially restates the tool name 'find_symbol' with synonyms like 'find function', 'where is class', 'variable location', and 'locate'. It doesn't specify what the tool actually does beyond the name, nor does it distinguish this tool from its sibling 'find_references' which appears to serve a related purpose.

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

Usage Guidelines1/5

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

There is no guidance on when to use this tool versus alternatives. The description provides no context about appropriate use cases, prerequisites, or comparisons to sibling tools like 'find_references', leaving the agent with no usage direction.

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/ssdeanx/ssd-ai'

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