Skip to main content
Glama
SiroSuzume

MCP ts-morph Refactoring Tools

by SiroSuzume

find_references_by_tsmorph

Locate symbol definitions and all references across a TypeScript project using tsconfig.json. Specify file path and symbol position to analyze where a function, variable, or class is used for informed refactoring.

Instructions

[Uses ts-morph] Finds the definition and all references to a symbol at a given position throughout the project.

Analyzes the project based on tsconfig.json to locate the definition and all usages of the symbol (function, variable, class, etc.) specified by its position.

Usage

Use this tool before refactoring to understand the impact of changing a specific symbol. It helps identify where a function is called, where a variable is used, etc.

  1. Specify the absolute path to the project's tsconfig.json.

  2. Specify the absolute path to the file containing the symbol you want to investigate.

  3. Specify the exact position (line and column) of the symbol within the file.

Parameters

  • tsconfigPath (string, required): Absolute path to the project's root tsconfig.json file. Essential for ts-morph to parse the project. Must be an absolute path.

  • targetFilePath (string, required): The absolute path to the file containing the symbol to find references for. Must be an absolute path.

  • position (object, required): The exact position of the symbol to find references for.

    • line (number, required): 1-based line number.

    • column (number, required): 1-based column number.

Result

  • On success: Returns a message containing the definition location (if found) and a list of reference locations (file path, line number, column number, and line text).

  • On failure: Returns a message indicating the error.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
positionYesThe exact position of the symbol.
targetFilePathYesAbsolute path to the file containing the symbol.
tsconfigPathYesAbsolute path to the project's tsconfig.json file.

Implementation Reference

  • The tool handler function that extracts arguments, calls the findSymbolReferences helper, formats definition and references into a markdown-like text response, handles errors, and includes performance metrics.
    async (args) => { const startTime = performance.now(); let message = ""; let isError = false; let duration = "0.00"; // duration を外で宣言・初期化 try { const { tsconfigPath, targetFilePath, position } = args; const { references, definition } = await findSymbolReferences({ tsconfigPath: tsconfigPath, targetFilePath: targetFilePath, position, }); let resultText = ""; if (definition) { resultText += "Definition:\n"; resultText += `- ${definition.filePath}:${definition.line}:${definition.column}\n`; resultText += ` \`\`\`typescript\n ${definition.text}\n \`\`\`\n\n`; } else { resultText += "Definition not found.\n\n"; } if (references.length > 0) { resultText += `References (${references.length} found):\n`; const formattedReferences = references .map( (ref) => `- ${ref.filePath}:${ref.line}:${ref.column}\n \`\`\`typescript\n ${ref.text}\n \`\`\`\``, ) .join("\n\n"); resultText += formattedReferences; } else { resultText += "References not found."; } message = resultText.trim(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); message = `Error during reference search: ${errorMessage}`; isError = true; } finally { const endTime = performance.now(); duration = ((endTime - startTime) / 1000).toFixed(2); // duration を更新 } // finally の外で return する const finalMessage = `${message}\nStatus: ${ isError ? "Failure" : "Success" }\nProcessing time: ${duration} seconds`; return { content: [{ type: "text", text: finalMessage }], isError: isError, }; },
  • Main helper function that uses ts-morph to find the identifier at the given position, retrieve its references and definition, extract locations and line texts, deduplicate definition from references, and sort references.
    export async function findSymbolReferences({ tsconfigPath, targetFilePath, position, }: { tsconfigPath: string; targetFilePath: string; position: { line: number; column: number }; }): Promise<{ references: ReferenceLocation[]; definition: ReferenceLocation | null; }> { const project = initializeProject(tsconfigPath); // targetFilePath は絶対パスである想定 const identifierNode = findIdentifierNode(project, targetFilePath, position); // findReferencesAsNodes() は定義箇所を含まない場合がある const referenceNodes: Node[] = identifierNode.findReferencesAsNodes(); let definitionLocation: ReferenceLocation | null = null; const definitions = identifierNode.getDefinitionNodes(); if (definitions.length > 0) { const defNode = definitions[0]; const defSourceFile = defNode.getSourceFile(); const defStartPos = defNode.getStart(); const { line: defLine, column: defColumn } = defSourceFile.getLineAndColumnAtPos(defStartPos); const lineText = getLineText(defSourceFile, defLine); definitionLocation = { filePath: defSourceFile.getFilePath(), line: defLine, column: defColumn, text: lineText.trim(), }; } const references: ReferenceLocation[] = []; for (const refNode of referenceNodes) { const refSourceFile = refNode.getSourceFile(); const refStartPos = refNode.getStart(); const { line: refLine, column: refColumn } = refSourceFile.getLineAndColumnAtPos(refStartPos); if ( definitionLocation && refLine !== undefined && refColumn !== undefined && refSourceFile.getFilePath() === definitionLocation.filePath && refLine === definitionLocation.line && refColumn === definitionLocation.column ) { continue; // 定義箇所と同じであればスキップ } if (refLine === undefined || refColumn === undefined) continue; const filePath = refSourceFile.getFilePath(); const lineText = getLineText(refSourceFile, refLine); references.push({ filePath, line: refLine, column: refColumn, text: lineText.trim(), }); } references.sort((a, b) => { if (a.filePath !== b.filePath) { return a.filePath.localeCompare(b.filePath); } return a.line - b.line; }); return { references, definition: definitionLocation }; }
  • Input schema for the tool parameters using Zod: tsconfigPath, targetFilePath, and position object with line and column.
    { tsconfigPath: z .string() .describe("Absolute path to the project's tsconfig.json file."), targetFilePath: z .string() .describe("Absolute path to the file containing the symbol."), position: z .object({ line: z.number().describe("1-based line number."), column: z.number().describe("1-based column number."), }) .describe("The exact position of the symbol."), },
  • Registration function that calls server.tool to register 'find_references_by_tsmorph' with its description, input schema, and handler function.
    export function registerFindReferencesTool(server: McpServer): void { server.tool( "find_references_by_tsmorph", `[Uses ts-morph] Finds the definition and all references to a symbol at a given position throughout the project. Analyzes the project based on \`tsconfig.json\` to locate the definition and all usages of the symbol (function, variable, class, etc.) specified by its position. ## Usage Use this tool before refactoring to understand the impact of changing a specific symbol. It helps identify where a function is called, where a variable is used, etc. 1. Specify the **absolute path** to the project's \`tsconfig.json\`. 2. Specify the **absolute path** to the file containing the symbol you want to investigate. 3. Specify the exact **position** (line and column) of the symbol within the file. ## Parameters - tsconfigPath (string, required): Absolute path to the project's root \`tsconfig.json\` file. Essential for ts-morph to parse the project. **Must be an absolute path.** - targetFilePath (string, required): The absolute path to the file containing the symbol to find references for. **Must be an absolute path.** - position (object, required): The exact position of the symbol to find references for. - line (number, required): 1-based line number. - column (number, required): 1-based column number. ## Result - On success: Returns a message containing the definition location (if found) and a list of reference locations (file path, line number, column number, and line text). - On failure: Returns a message indicating the error.`, { tsconfigPath: z .string() .describe("Absolute path to the project's tsconfig.json file."), targetFilePath: z .string() .describe("Absolute path to the file containing the symbol."), position: z .object({ line: z.number().describe("1-based line number."), column: z.number().describe("1-based column number."), }) .describe("The exact position of the symbol."), }, async (args) => { const startTime = performance.now(); let message = ""; let isError = false; let duration = "0.00"; // duration を外で宣言・初期化 try { const { tsconfigPath, targetFilePath, position } = args; const { references, definition } = await findSymbolReferences({ tsconfigPath: tsconfigPath, targetFilePath: targetFilePath, position, }); let resultText = ""; if (definition) { resultText += "Definition:\n"; resultText += `- ${definition.filePath}:${definition.line}:${definition.column}\n`; resultText += ` \`\`\`typescript\n ${definition.text}\n \`\`\`\n\n`; } else { resultText += "Definition not found.\n\n"; } if (references.length > 0) { resultText += `References (${references.length} found):\n`; const formattedReferences = references .map( (ref) => `- ${ref.filePath}:${ref.line}:${ref.column}\n \`\`\`typescript\n ${ref.text}\n \`\`\`\``, ) .join("\n\n"); resultText += formattedReferences; } else { resultText += "References not found."; } message = resultText.trim(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); message = `Error during reference search: ${errorMessage}`; isError = true; } finally { const endTime = performance.now(); duration = ((endTime - startTime) / 1000).toFixed(2); // duration を更新 } // finally の外で return する const finalMessage = `${message}\nStatus: ${ isError ? "Failure" : "Success" }\nProcessing time: ${duration} seconds`; return { content: [{ type: "text", text: finalMessage }], isError: isError, }; }, ); }
  • TypeScript interface defining the structure of reference and definition locations returned by findSymbolReferences.
    export interface ReferenceLocation { filePath: string; line: number; column: number; text: string; }

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/SiroSuzume/mcp-ts-morph'

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