Skip to main content
Glama
t09tanaka

TypeScript Rename Helper

by t09tanaka

planRenameSymbol

Plan TypeScript symbol renaming by computing file edits for renaming identifiers, variables, functions, and classes across your codebase without modifying files.

Instructions

Compute edits to rename a TypeScript symbol at a specific position. Returns edit plans without modifying the filesystem.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectRootYesAbsolute or relative path to the project root
filePathYesAbsolute path or path relative to projectRoot of the file containing the symbol
lineYes0-based line number of the symbol
characterYes0-based character position of the symbol
newNameYesThe new name for the symbol
findInStringsNoWhether to find occurrences in strings (default: false)
findInCommentsNoWhether to find occurrences in comments (default: false)

Implementation Reference

  • The primary handler function implementing the planRenameSymbol tool logic using TypeScript LanguageService to compute rename edits.
    export function planRenameSymbol( params: PlanRenameSymbolParams ): PlanRenameSymbolResult { // 1. projectRoot を絶対パスに正規化 const absProjectRoot = path.resolve(params.projectRoot); // 2. createTsService で service を取得 let service: ts.LanguageService; try { const tsServiceResult = createTsService(absProjectRoot); service = tsServiceResult.service; } catch (error) { return { canRename: false, reason: error instanceof Error ? error.message : "Failed to create TS service", }; } // 3. filePath を絶対パスに正規化 const absFilePath = path.isAbsolute(params.filePath) ? params.filePath : path.resolve(absProjectRoot, params.filePath); // 4. ファイル内容を読み込み if (!fs.existsSync(absFilePath)) { return { canRename: false, reason: `File not found: ${absFilePath}`, }; } const fileText = fs.readFileSync(absFilePath, "utf8"); const sourceFile = ts.createSourceFile( absFilePath, fileText, ts.ScriptTarget.Latest, true ); // 5. ts.getPositionOfLineAndCharacter で位置を計算 const pos = ts.getPositionOfLineAndCharacter( sourceFile, params.line, params.character ); // 6. service.getRenameInfo() でリネーム可否を確認 const renameInfo = service.getRenameInfo(absFilePath, pos); if (!renameInfo.canRename) { return { canRename: false, reason: renameInfo.localizedErrorMessage ?? "Cannot rename this symbol", }; } // 7. service.findRenameLocations() でリネーム箇所を取得 const locations = service.findRenameLocations( absFilePath, pos, params.findInStrings ?? false, params.findInComments ?? false, false // providePrefixAndSuffixTextForRename ) ?? []; // 8. 各 location を TextEdit に変換し、fileName ごとにまとめる const editsByFile = new Map<string, TextEdit[]>(); for (const location of locations) { const fileName = location.fileName; // ファイルのテキストを読み込む if (!fs.existsSync(fileName)) { continue; } const locationFileText = fs.readFileSync(fileName, "utf8"); const locationSourceFile = ts.createSourceFile( fileName, locationFileText, ts.ScriptTarget.Latest, true ); // textSpan を Range に変換 const start = ts.getLineAndCharacterOfPosition( locationSourceFile, location.textSpan.start ); const end = ts.getLineAndCharacterOfPosition( locationSourceFile, location.textSpan.start + location.textSpan.length ); const range: Range = { start: { line: start.line, character: start.character, }, end: { line: end.line, character: end.character, }, }; // TextEdit を構築 const textEdit: TextEdit = { range, newText: params.newName, }; // fileName ごとにまとめる const edits = editsByFile.get(fileName) ?? []; edits.push(textEdit); editsByFile.set(fileName, edits); } // 9. FileTextEdits[] を構築 const fileTextEdits: FileTextEdits[] = Array.from(editsByFile.entries()).map( ([filePath, textEdits]) => ({ filePath, textEdits, }) ); return { canRename: true, edits: fileTextEdits, }; }
  • Type definition for input parameters of planRenameSymbol tool.
    export type PlanRenameSymbolParams = { projectRoot: string; // 絶対 or 相対 filePath: string; // 絶対 or projectRoot からの相対 line: number; // 0-based character: number; // 0-based newName: string; findInStrings?: boolean; // デフォルト false findInComments?: boolean; // デフォルト false };
  • Type definition for output result of planRenameSymbol tool.
    export type PlanRenameSymbolResult = | { canRename: false; reason: string; } | { canRename: true; edits: FileTextEdits[]; };
  • src/index.ts:28-68 (registration)
    MCP tool registration defining name, description, and input schema for planRenameSymbol.
    { name: "planRenameSymbol", description: "Compute edits to rename a TypeScript symbol at a specific position. Returns edit plans without modifying the filesystem.", inputSchema: { type: "object", properties: { projectRoot: { type: "string", description: "Absolute or relative path to the project root", }, filePath: { type: "string", description: "Absolute path or path relative to projectRoot of the file containing the symbol", }, line: { type: "number", description: "0-based line number of the symbol", }, character: { type: "number", description: "0-based character position of the symbol", }, newName: { type: "string", description: "The new name for the symbol", }, findInStrings: { type: "boolean", description: "Whether to find occurrences in strings (default: false)", }, findInComments: { type: "boolean", description: "Whether to find occurrences in comments (default: false)", }, }, required: ["projectRoot", "filePath", "line", "character", "newName"], }, },
  • src/index.ts:151-162 (registration)
    Dispatch handler in MCP server that calls the planRenameSymbol function.
    case "planRenameSymbol": { const params = args as unknown as PlanRenameSymbolParams; const result = planRenameSymbol(params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }

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/t09tanaka/ts-rename-helper-mcp'

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