Skip to main content
Glama
t09tanaka

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