TypeScript Rename Helper
by t09tanaka
README.md
# @t09tanaka/ts-rename-helper-mcp
An MCP server that provides TypeScript symbol renaming and file/directory moves for coding agents.
This exists as a **helper bridge**: most current code agents can’t talk to the TypeScript Language Service (LSP) directly, so even a simple rename can be slow and error-prone.
`ts-rename-helper-mcp` gives the agent compiler-grade rename/move plans without touching your filesystem.
> ⚠️ This project is intentionally narrow in scope and may become obsolete once agents can use LSPs directly.
---
## Features
- **Type-safe symbol renaming**
- Uses the TypeScript Language Service to compute all affected locations
- **File move / rename planning**
- Returns edits for updated import paths across the project or workspace
- **Directory move / rename planning**
- Recursively plans file moves and import updates for all files under a directory
- **Global install friendly**
- Can resolve the appropriate `tsconfig.json` from the target file path
- **Monorepo aware**
- Can merge edits from multiple `tsconfig.json` files under a workspace
- **Read-only by design**
- MCP tools only return “edit plans” and suggested file moves
→ actual file writes are left to your editor/agent
---
## Installation
### 1. Install the package
Recommended for most users: global install
```bash
npm i -g @t09tanaka/ts-rename-helper-mcp
```
If you want the version pinned per repository, use a project-local install instead:
Project-local install:
```bash
npm i -D @t09tanaka/ts-rename-helper-mcp
```
```bash
pnpm add -D @t09tanaka/ts-rename-helper-mcp
```
```bash
yarn add -D @t09tanaka/ts-rename-helper-mcp
```
### 2. Add to your MCP client
**Claude Code:**
```bash
claude mcp add ts-rename-helper npx -- @t09tanaka/ts-rename-helper-mcp
```
**OpenAI Codex:**
```bash
codex mcp add ts-rename-helper npx -- @t09tanaka/ts-rename-helper-mcp
```
**Other MCP clients (JSON config):**
```jsonc
{
"mcpServers": {
"ts-rename-helper": {
"command": "npx",
"args": ["@t09tanaka/ts-rename-helper-mcp"]
}
}
}
```
### Requirements
- Node.js 18+
- A TypeScript project with a valid `tsconfig.json`
- For monorepos, `workspaceRoot` is optional but recommended when you want to scan multiple sibling TS projects deterministically
### Recommended usage
- Prefer absolute paths for `filePath`, `oldPath`, `newPath`, `oldDir`, and `newDir`
- For single-project repos, you can often omit `projectRoot`, `workspaceRoot`, and `tsconfigPath`
- For monorepos, pass `workspaceRoot` when you want rename or move results to include sibling TS projects
- If your repo uses non-standard config names such as `tsconfig.app.json`, pass `tsconfigPath` explicitly
### How `tsconfig` is selected
When `tsconfigPath` is not provided, the server resolves the TypeScript project like this:
1. Start from the target file path
2. Walk upward looking for `tsconfig.json`
3. Parse each candidate and choose the nearest one that actually includes the file
4. If `workspaceRoot` is provided, also scan sibling `tsconfig.json` files under that workspace and merge edit results when possible
The bundled server also tries to load the `typescript` package from the resolved project first, and falls back to its own bundled version if needed.
---
## Tools
This MCP server exposes three tools:
1. `planRenameSymbol`
2. `planFileMove`
3. `planDirectoryMove`
All tools are **pure**: they never modify files, they only return structured edit plans.
### 1. `planRenameSymbol`
Compute all edits needed to rename a symbol at a specific position.
**Input**
```jsonc
{
"filePath": "/absolute/path/to/project/src/foo/bar.ts",
"workspaceRoot": "/absolute/path/to/workspace", // optional
"projectRoot": "/absolute/path/to/project", // optional, mainly for relative paths / legacy clients
"tsconfigPath": "/absolute/path/to/project/tsconfig.json", // optional override
"line": 12, // 0-based
"character": 8, // 0-based
"newName": "fetchUserProfiles",
"findInStrings": false,
"findInComments": false,
}
```
**Output**
```jsonc
{
"canRename": true,
"edits": [
{
"filePath": "/absolute/path/to/project/src/foo/bar.ts",
"textEdits": [
{
"range": {
"start": { "line": 12, "character": 4 },
"end": { "line": 12, "character": 20 },
},
"newText": "fetchUserProfiles",
},
],
},
{
"filePath": "/absolute/path/to/project/src/usage.ts",
"textEdits": [
{
"range": {
"start": { "line": 5, "character": 16 },
"end": { "line": 5, "character": 32 },
},
"newText": "fetchUserProfiles",
},
],
},
],
}
```
If the symbol cannot be renamed:
```jsonc
{
"canRename": false,
"reason": "This symbol cannot be renamed.",
}
```
**Notes**
- `line` / `character` are **0-based** (same as LSP).
- `filePath` may be relative if `projectRoot` or `workspaceRoot` is provided. For global installs, absolute paths are recommended.
- If `tsconfigPath` is omitted, the server walks upward from `filePath` and picks the nearest `tsconfig.json` that actually includes the file.
- In monorepos, the server may merge rename locations from multiple TS projects under `workspaceRoot`.
- If you want deterministic behavior in a large monorepo, prefer passing `workspaceRoot`.
- Agents should:
1. Read each file
2. Apply `textEdits` in a stable order (typically reverse-sorted by position)
3. Write updated content back
---
### 2. `planFileMove`
Plan a file move/rename and compute all necessary import updates.
**Input**
```jsonc
{
"oldPath": "/absolute/path/to/project/src/feature/user/api.ts",
"newPath": "/absolute/path/to/project/src/features/user/api.ts",
"workspaceRoot": "/absolute/path/to/workspace", // optional
"projectRoot": "/absolute/path/to/project", // optional, mainly for relative paths / legacy clients
"tsconfigPath": "/absolute/path/to/project/tsconfig.json", // optional override for the primary project
}
```
**Output**
```jsonc
{
"edits": [
{
"filePath": "/absolute/path/to/project/src/index.ts",
"textEdits": [
{
"range": {
"start": { "line": 3, "character": 0 },
"end": { "line": 3, "character": 50 },
},
"newText": "export * from './features/user/api';",
},
],
},
],
"fsMoves": [
{
"from": "/absolute/path/to/project/src/feature/user/api.ts",
"to": "/absolute/path/to/project/src/features/user/api.ts",
},
],
}
```
**Notes**
- `fsMoves` is only a **suggestion** – the agent/editor should perform the actual move.
- `edits` should be applied after the move so that imports point to the new path.
- If `workspaceRoot` is provided, the server scans sibling `tsconfig.json` files and merges import updates across the workspace.
- `tsconfigPath` only selects the primary project explicitly; sibling projects still come from `workspaceRoot` discovery.
---
### 3. `planDirectoryMove`
Plan a directory move/rename and compute all necessary import updates for files under that directory.
**Input**
```jsonc
{
"oldDir": "/absolute/path/to/project/src/feature/auth",
"newDir": "/absolute/path/to/project/src/features/auth",
"workspaceRoot": "/absolute/path/to/workspace", // optional
"projectRoot": "/absolute/path/to/project", // optional, mainly for relative paths / legacy clients
"tsconfigPath": "/absolute/path/to/project/tsconfig.json", // optional override for the primary project
}
```
**Output**
```jsonc
{
"edits": [
{
"filePath": "/absolute/path/to/project/src/router.tsx",
"textEdits": [
{
"range": {
"start": { "line": 10, "character": 20 },
"end": { "line": 10, "character": 49 },
},
"newText": "'./features/auth/routes'",
},
],
},
],
"fsMoves": [
{
"from": "/absolute/path/to/project/src/feature/auth/index.ts",
"to": "/absolute/path/to/project/src/features/auth/index.ts",
},
{
"from": "/absolute/path/to/project/src/feature/auth/hooks.ts",
"to": "/absolute/path/to/project/src/features/auth/hooks.ts",
},
],
}
```
**Notes**
- All TypeScript / TSX files under `oldDir` are treated as candidates for moves.
- Internally this is typically implemented as repeated `getEditsForFileRename` calls.
- If `workspaceRoot` is provided, the server also merges import updates from sibling TS projects in a monorepo.
---
## Monorepo example
Given a workspace like this:
```text
repo/
package.json
api/tsconfig.json
api/src/shared/user.ts
admin/tsconfig.json
admin/src/pages/users.ts
```
If `admin/src/pages/users.ts` imports `api/src/shared/user.ts`, you can move the API file with:
```jsonc
{
"oldPath": "/absolute/path/to/repo/api/src/shared/user.ts",
"newPath": "/absolute/path/to/repo/api/src/domain/user.ts",
"workspaceRoot": "/absolute/path/to/repo"
}
```
With `workspaceRoot` set, the server can include import updates for both `api` and `admin`.
---
## Typical agent flow
A coding agent integrating this MCP server would usually:
1. Decide on an operation:
- rename a symbol, or
- move a file/directory
2. Call the corresponding tool (`planRenameSymbol`, `planFileMove`, `planDirectoryMove`)
3. Inspect the returned `edits` and `fsMoves`
4. Apply `fsMoves` using its own filesystem tools
5. Apply `edits` to the affected files
6. Optionally run `tsc` or tests to validate
---
## Limitations
- **TypeScript only**
JavaScript-only projects without `tsconfig.json` are not currently targeted.
- **Project model is created per call** (depending on implementation)
For extremely large monorepos you may want to cache the server or run it close to the project root.
- **`tsconfig.json` discovery is convention-based**
The server currently discovers `tsconfig.json` files, not arbitrary `tsconfig.*.json` variants unless you pass `tsconfigPath`.
- **No actual file I/O via MCP**
This server never writes to disk; agents must handle file operations.
---
## License
MIT © 2025 Takuto Tanaka
TDQS
A4/5.0
Scored across 3 tools
Disambiguation5/5
Each tool targets a distinct operation: directory moves, file moves, and symbol renames. There is no overlap in purpose.
Naming Consistency5/5
All tools follow a consistent 'plan' + specific noun pattern (DirectoryMove, FileMove, RenameSymbol), making them predictable.
Tool Count5/5
With only 3 tools, the server is tightly scoped to planning moves and renames, which is appropriate for its focused helper role.
Completeness5/5
The tool surface covers all necessary planning operations for TypeScript refactoring: directory moves, file moves, and symbol renames, with no glaring gaps.
Maintenance
ActivityInactive
ResponsivenessNo issues