Skip to main content
Glama

Find Symbol

find_symbol
Read-only

Search for code symbols like classes and methods using name path patterns to locate and retrieve information for editing or analysis within codebases.

Instructions

Retrieves information on all symbols/code entities (classes, methods, etc.) based on the given name path pattern. The returned symbol information can be used for edits or further queries. Specify depth > 0 to also retrieve children/descendants (e.g., methods of a class).

A name path is a path in the symbol tree within a source file. For example, the method my_method defined in class MyClass would have the name path MyClass/my_method. If a symbol is overloaded (e.g., in Java), a 0-based index is appended (e.g. "MyClass/my_method[0]") to uniquely identify it.

To search for a symbol, you provide a name path pattern that is used to match against name paths. It can be

  • a simple name (e.g. "method"), which will match any symbol with that name

  • a relative path like "class/method", which will match any symbol with that name path suffix

  • an absolute name path "/class/method" (absolute name path), which requires an exact match of the full name path within the source file. Append an index [i] to match a specific overload only, e.g. "MyClass/my_method[1]". Returns a list of symbols (with locations) matching the name.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
name_path_patternYesThe name path matching pattern (see above).
depthNoDepth up to which descendants shall be retrieved (e.g. use 1 to also retrieve immediate children; for the case where the symbol is a class, this will return its methods). Default 0.
relative_pathNoOptional. Restrict search to this file or directory. If None, searches entire codebase. If a directory is passed, the search will be restricted to the files in that directory. If a file is passed, the search will be restricted to that file. If you have some knowledge about the codebase, you should use this parameter, as it will significantly speed up the search as well as reduce the number of results.
include_bodyNoIf True, include the symbol's source code. Use judiciously.
include_kindsNoOptional. List of LSP symbol kind integers to include. (e.g., 5 for Class, 12 for Function). Valid kinds: 1=file, 2=module, 3=namespace, 4=package, 5=class, 6=method, 7=property, 8=field, 9=constructor, 10=enum, 11=interface, 12=function, 13=variable, 14=constant, 15=string, 16=number, 17=boolean, 18=array, 19=object, 20=key, 21=null, 22=enum member, 23=struct, 24=event, 25=operator, 26=type parameter. If not provided, all kinds are included.
exclude_kindsNoOptional. List of LSP symbol kind integers to exclude. Takes precedence over `include_kinds`. If not provided, no kinds are excluded.
substring_matchingNoIf True, use substring matching for the last element of the pattern, such that "Foo/get" would match "Foo/getValue" and "Foo/getData".
max_answer_charsNoMax characters for the JSON result. If exceeded, no content is returned. -1 means the default value from the config will be used.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The FindSymbolTool class provides the core handler implementation for the 'find_symbol' MCP tool. The 'apply' method executes the tool logic by querying the language server symbol retriever for matching symbols, sanitizing the results, converting to JSON, and applying length limits.
    class FindSymbolTool(Tool, ToolMarkerSymbolicRead):
        """
        Performs a global (or local) search using the language server backend.
        """
    
        # noinspection PyDefaultArgument
        def apply(
            self,
            name_path_pattern: str,
            depth: int = 0,
            relative_path: str = "",
            include_body: bool = False,
            include_kinds: list[int] = [],  # noqa: B006
            exclude_kinds: list[int] = [],  # noqa: B006
            substring_matching: bool = False,
            max_answer_chars: int = -1,
        ) -> str:
            """
            Retrieves information on all symbols/code entities (classes, methods, etc.) based on the given name path pattern.
            The returned symbol information can be used for edits or further queries.
            Specify `depth > 0` to also retrieve children/descendants (e.g., methods of a class).
    
            A name path is a path in the symbol tree *within a source file*.
            For example, the method `my_method` defined in class `MyClass` would have the name path `MyClass/my_method`.
            If a symbol is overloaded (e.g., in Java), a 0-based index is appended (e.g. "MyClass/my_method[0]") to
            uniquely identify it.
    
            To search for a symbol, you provide a name path pattern that is used to match against name paths.
            It can be
             * a simple name (e.g. "method"), which will match any symbol with that name
             * a relative path like "class/method", which will match any symbol with that name path suffix
             * an absolute name path "/class/method" (absolute name path), which requires an exact match of the full name path within the source file.
            Append an index `[i]` to match a specific overload only, e.g. "MyClass/my_method[1]".
    
            :param name_path_pattern: the name path matching pattern (see above)
            :param depth: depth up to which descendants shall be retrieved (e.g. use 1 to also retrieve immediate children;
                for the case where the symbol is a class, this will return its methods).
                Default 0.
            :param relative_path: Optional. Restrict search to this file or directory. If None, searches entire codebase.
                If a directory is passed, the search will be restricted to the files in that directory.
                If a file is passed, the search will be restricted to that file.
                If you have some knowledge about the codebase, you should use this parameter, as it will significantly
                speed up the search as well as reduce the number of results.
            :param include_body: If True, include the symbol's source code. Use judiciously.
            :param include_kinds: Optional. List of LSP symbol kind integers to include. (e.g., 5 for Class, 12 for Function).
                Valid kinds: 1=file, 2=module, 3=namespace, 4=package, 5=class, 6=method, 7=property, 8=field, 9=constructor, 10=enum,
                11=interface, 12=function, 13=variable, 14=constant, 15=string, 16=number, 17=boolean, 18=array, 19=object,
                20=key, 21=null, 22=enum member, 23=struct, 24=event, 25=operator, 26=type parameter.
                If not provided, all kinds are included.
            :param exclude_kinds: Optional. List of LSP symbol kind integers to exclude. Takes precedence over `include_kinds`.
                If not provided, no kinds are excluded.
            :param substring_matching: If True, use substring matching for the last element of the pattern, such that
                "Foo/get" would match "Foo/getValue" and "Foo/getData".
            :param max_answer_chars: Max characters for the JSON result. If exceeded, no content is returned.
                -1 means the default value from the config will be used.
            :return: a list of symbols (with locations) matching the name.
            """
            parsed_include_kinds: Sequence[SymbolKind] | None = [SymbolKind(k) for k in include_kinds] if include_kinds else None
            parsed_exclude_kinds: Sequence[SymbolKind] | None = [SymbolKind(k) for k in exclude_kinds] if exclude_kinds else None
            symbol_retriever = self.create_language_server_symbol_retriever()
            symbols = symbol_retriever.find(
                name_path_pattern,
                include_kinds=parsed_include_kinds,
                exclude_kinds=parsed_exclude_kinds,
                substring_matching=substring_matching,
                within_relative_path=relative_path,
            )
            symbol_dicts = [_sanitize_symbol_dict(s.to_dict(kind=True, location=True, depth=depth, include_body=include_body)) for s in symbols]
            result = self._to_json(symbol_dicts)
            return self._limit_length(result, max_answer_chars)
  • The get_name_from_cls method derives the MCP tool name 'find_symbol' from the class name 'FindSymbolTool' by removing 'Tool' suffix and converting to snake_case.
    def get_name_from_cls(cls) -> str:
        name = cls.__name__
        if name.endswith("Tool"):
            name = name[:-4]
        # convert to snake_case
        name = "".join(["_" + c.lower() if c.isupper() else c for c in name]).lstrip("_")
        return name
  • The ToolRegistry singleton automatically discovers all Tool subclasses in serena.tools packages, computes their names using get_name_from_cls, and registers 'find_symbol' along with all other tools.
    @singleton
    class ToolRegistry:
        def __init__(self) -> None:
            self._tool_dict: dict[str, RegisteredTool] = {}
            for cls in iter_subclasses(Tool):
                if not any(cls.__module__.startswith(pkg) for pkg in tool_packages):
                    continue
                is_optional = issubclass(cls, ToolMarkerOptional)
                name = cls.get_name_from_cls()
                if name in self._tool_dict:
                    raise ValueError(f"Duplicate tool name found: {name}. Tool classes must have unique names.")
                self._tool_dict[name] = RegisteredTool(tool_class=cls, is_optional=is_optional, tool_name=name)
  • Helper function used by FindSymbolTool.apply to sanitize symbol dictionaries before returning as JSON.
    def _sanitize_symbol_dict(symbol_dict: dict[str, Any]) -> dict[str, Any]:
        """
        Sanitize a symbol dictionary inplace by removing unnecessary information.
        """
        # We replace the location entry, which repeats line information already included in body_location
        # and has unnecessary information on column, by just the relative path.
        symbol_dict = copy(symbol_dict)
        s_relative_path = symbol_dict.get("location", {}).get("relative_path")
        if s_relative_path is not None:
            symbol_dict["relative_path"] = s_relative_path
        symbol_dict.pop("location", None)
        # also remove name, name_path should be enough
        symbol_dict.pop("name")
        return symbol_dict
  • During MCP server startup, _set_mcp_tools iterates over exposed tool instances from the agent, creates MCPTool instances using make_mcp_tool (which uses tool.get_name() as the tool name), and registers them in the MCP tool manager by name, including 'find_symbol'.
    def _set_mcp_tools(self, mcp: FastMCP, openai_tool_compatible: bool = False) -> None:
        """Update the tools in the MCP server"""
        if mcp is not None:
            mcp._tool_manager._tools = {}
            for tool in self._iter_tools():
                mcp_tool = self.make_mcp_tool(tool, openai_tool_compatible=openai_tool_compatible)
                mcp._tool_manager._tools[tool.get_name()] = mcp_tool
            log.info(f"Starting MCP server with {len(mcp._tool_manager._tools)} tools: {list(mcp._tool_manager._tools.keys())}")
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the agent knows this is a safe read operation. The description adds valuable behavioral context beyond annotations: it explains that results can be used for edits, describes the matching logic (simple name, relative path, absolute path), mentions overload handling with indices, and notes performance considerations (using relative_path speeds up search). It does not contradict annotations.

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

Conciseness4/5

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

The description is well-structured and front-loaded with the core purpose, followed by detailed explanations of name paths and patterns. While comprehensive, it is appropriately sized for a complex tool with many parameters. Some sentences could be more concise (e.g., the name path explanation is lengthy), but overall it avoids unnecessary repetition.

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

Completeness5/5

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

Given the tool's complexity (8 parameters, 100% schema coverage, annotations, and an output schema), the description is complete. It covers purpose, usage examples, behavioral nuances (like overload handling and performance tips), and does not need to explain return values since an output schema exists. It adequately complements the structured data without gaps.

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%, so the schema already documents all 8 parameters thoroughly. The description adds some semantic context for name_path_pattern (explaining patterns and examples) and depth (linking it to retrieving children), but most parameter details are already in the schema. This meets the baseline of 3 for high schema coverage.

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

Purpose5/5

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

The description clearly states the tool's purpose with specific verbs ('retrieves information on all symbols/code entities') and distinguishes it from siblings by focusing on symbol lookup rather than file operations (find_file), pattern searching (search_for_pattern), or symbol editing (rename_symbol, replace_symbol_body). It explicitly mentions what the returned information can be used for ('for edits or further queries'), which helps differentiate its role.

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool (e.g., 'Specify `depth > 0` to also retrieve children/descendants') and implies alternatives through sibling tool names like find_file or search_for_pattern, but it does not explicitly state when not to use it or name specific alternatives. The guidance on using the relative_path parameter for speed and reduced results offers practical usage advice.

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/oraios/serena'

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