Skip to main content
Glama

find_references

Locate all references to a symbol in Godot projects using LSP or text search to track code usage and dependencies.

Instructions

Find all references to a symbol at a given position. LSP-only (returns error without LSP). Falls back to text search.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fileYesPath to the file containing the symbol
lineYesLine number (1-based)
characterNoCharacter offset (0-based)

Implementation Reference

  • Handler for find_references tool. Uses LSP for accurate reference finding or falls back to basic regex-based text search if LSP is unavailable.
    name: "find_references",
    description:
      "Find all references to a symbol at a given position. LSP-only (returns error without LSP). Falls back to text search.",
    schema: {
      file: z.string().describe("Path to the file containing the symbol"),
      line: z.number().int().min(1).describe("Line number (1-based)"),
      character: z
        .number()
        .int()
        .min(0)
        .optional()
        .default(0)
        .describe("Character offset (0-based)"),
    },
    handler: async (ctx) => {
      const { file, line, character = 0 } = ctx.args;
      validatePath(file);
      const lsp = getLspClient();
      const cache = getLspCache();
    
      if (lsp?.connected) {
        const uri = `file://${file}`;
        const lspLine = line - 1; // Convert 1-based to 0-based
        const cacheKey = `${uri}:${lspLine}:${character}`;
    
        // Check cache first
        if (cache) {
          const cached = cache.getReferences(cacheKey);
          if (cached) {
            return makeTextResponse({
              data: cached.map((l) => ({
                file: l.uri.replace("file://", ""),
                line: l.range.start.line + 1,
                character: l.range.start.character,
              })),
              totalCount: cached.length,
              metadata: { source: "lsp-cache" },
            });
          }
        }
    
        try {
          const locations = await lsp.findReferences(uri, lspLine, character);
    
          // Cache the result
          if (cache) {
            cache.setReferences(cacheKey, locations);
          }
    
          return makeTextResponse({
            data: locations.map((l) => ({
              file: l.uri.replace("file://", ""),
              line: l.range.start.line + 1,
              character: l.range.start.character,
            })),
            totalCount: locations.length,
            metadata: { source: "lsp" },
          });
        } catch (err) {
          return makeTextResponse({
            error: `LSP error: ${(err as Error).message}`,
            data: null,
            metadata: { source: "lsp" },
          });
        }
      }
    
      // Fallback: grep-style text search for the symbol name
      try {
        const source = readFileSync(file, "utf-8");
        const lines = source.split("\n");
        const targetLine = lines[line - 1] ?? "";
        // Extract symbol name at position
        const wordMatch = targetLine.slice(character).match(/^(\w+)/);
        const symbolName = wordMatch?.[1];
    
        if (!symbolName) {
          return makeTextResponse({
            error: "Could not determine symbol name at position",
            data: null,
          });
        }
    
        // Search all scripts for this symbol name
        const refs: Array<{
          file: string;
          line: number;
          context: string;
        }> = [];
    
        for (const [scriptPath, _script] of await index.scriptIndex.all()) {
          try {
            const scriptSource = readFileSync(scriptPath, "utf-8");
            const scriptLines = scriptSource.split("\n");
            for (let i = 0; i < scriptLines.length; i++) {
              if (scriptLines[i].includes(symbolName)) {
                refs.push({
                  file: scriptPath,
                  line: i + 1,
                  context: scriptLines[i].trim(),
                });
              }
            }
          } catch {
            // Skip unreadable files
          }
        }
    
        return makeTextResponse({
          data: refs,
          totalCount: refs.length,
          metadata: { source: "fallback", note: "Text search only. LSP unavailable." },
        });
      } catch (err) {
        return makeTextResponse({
          error: `Failed: ${(err as Error).message}`,
          data: null,
        });
      }
    },

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/woohq/godette-mcp'

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