🤖
typescript-mcp で AI に LSP のリファクタリング機能を与える
一旦 npm install typescript typescript-mcp -D で MCP サーバーが動くところまで作った。
主語大きめだけど、 npm の名前空間が空いてたので...
これの続編
TL;DR
- 既存のエージェントの内蔵ツールはセマンティックな AST 操作ができない
- 書き換えてみて駄目だったら修正、みたいな挙動
 
 - MCP サーバーとして、 Rename, Move File, Go to Definition, Find References 等の LSP の機能を提供した
 
実際に動いている例
# Rename file
● typescript:move_file (MCP)(root: "~/s
                            andbox/claude-mcp",
                            oldPath: "examples/oth
                            er-types.ts", newPath:
                             "examples/types.ts")
  ⎿ Successfully moved file from "~/san
    dbox/claude-mcp/examples/other-types.ts" to
    "~/sandbox/claude-mcp/examples/type
    s.ts". Updated imports in 2 file(s).
    Changes:
      File moved: examples/other-types.ts →
    examples/types.ts
How to use
今現在は claude-code mcp サーバーとして動く。
# TypeScript プロジェクトを設定
$ npm install typescript typescript-mcp -D
# 初期化コマンド
$ npx typescript-mcp --init=claude
# .claude/mcp_servers.json MCP 設定を生成
# .claude/settings.json にツールのパーミッションを追加
## CLAUDE.md 用の追加プロンプト
# You prefer typescript mcp (`mcp__typescript_*`) to fix code over the default `Update` and `Write` tool.
# MCP サーバーと一緒に起動
$ claude
# /mcp で起動してるかわかる
╭─────────────────────────────────────────────────────╮
│ Manage MCP Servers                                  │
│ 1 servers found                                     │
│                                                     │
│   typescript · connected                            │
╰─────────────────────────────────────────────────────╯
カレントディレクトリの TypeScript LSP を掴むはず。
モチベーション
現代で AI にコードを書かせるには、今はまだ言語特化プロンプトが必要。なんなら MCP Agent として実装するのがいいはず
既存のエージェントの内蔵ツールは、書き換えてみて問題がでたら修正、みたいな挙動をする。typescript-mcp があれば安全にリファクタリングできる。
Go to Definitions 定義元にジャンプするので、node_modules 内の型定義ファイルを自分で参照できるようになる。
工夫: 実質 LSP の MCP だが...
最初は LSP をそのまま喋らせようとしたが、LLM は内部トークンのせいでワードカウントが下手という問題がある。
line:column ベースでカーソル位置の操作をさせようとすると、そのままできない。当てずっぽうで外す。
line は ClaudeCode や Roo はエージェント内部で diff を作るために保持しているので、何行目のこのシンボル、という風に API を調整してある。
const schema = z.object({
  root: z.string().describe("Root directory for resolving relative paths"),
  filePath: z
    .string()
    .describe("File path containing the symbol (relative to root)"),
  line: z
    .union([z.number(), z.string()])
    .describe("Line number (1-based) or string to match in the line"),
  oldName: z.string().describe("Current name of the symbol"),
  newName: z.string().describe("New name for the symbol"),
});
主な機能
mcp__typescript__ は claude code 側で生成される名前空間
1. セマンティックなファイル操作
- 
ファイル移動 (
mcp__typescript__move_file) - インポート文を自動更新 - 
ディレクトリ移動 (
mcp__typescript__move_directory) - ディレクトリ全体を移動し、すべてのインポートを更新 
2. シンボル操作
- 
シンボルのリネーム (
mcp__typescript__rename_symbol) - プロジェクト全体でシンボルをリネーム - 
シンボルの削除 (
mcp__typescript__delete_symbol) - シンボルとその参照をすべて削除 - 
参照の検索 (
mcp__typescript__find_references) - シンボルへのすべての参照を検索 
3. コード分析
- 
定義の取得 (
mcp__typescript__get_definitions) - シンボルの定義位置を取得 - 
診断情報 (
mcp__typescript__get_diagnostics) - TypeScript のエラーや警告を取得 - 
モジュールシンボル (
mcp__typescript__get_module_symbols) - モジュールのエクスポートを一覧表示 - 
型情報の取得 (
mcp__typescript__get_type_in_module,mcp__typescript__get_type_at_symbol) - 詳細な型シグネチャを取得 
使用例
# rename
> examples/scratch.ts foo to bar
Successfully renamed symbol "foo" to "bar" in 1 file(s) with 2 change(s).
# move file
> move examples/other-types.ts to examples/types.ts
Successfully moved file from "examples/other-types.ts" to "examples/types.ts"
Updated imports in 2 file(s).
# get definitions
```bash
> get toMcpHandler definitions
Found 1 definition for symbol "toMcpToolHandler"
  src/mcp/mcp_server_utils.ts:15:1 - export function toMcpToolHandler<T>(
課題
- プロンプトに工夫が必要
- 機能として存在していても、Roo や Claude Code は内部ツールを使おうとするバイアスが強いので、
typescript-mcpを優先的に使わせるのが難しい - 現状これ: 
You prefer typescript mcp (mcp__typescript_*) to fix code over the default Update and Write tool. - 専用ワークフロー定義が必要かも
 
 - 機能として存在していても、Roo や Claude Code は内部ツールを使おうとするバイアスが強いので、
 - claude code 以外でまだデバッグしてない
 - LSP MCP として実装すれば TS 以外も対応可能だったが、一旦 ts-morph で楽した
 
追記: v0.0.7
npx -y typescript-mcp@latest の グローバルな実行ではなく、dependencies の依存としてインストールするようにした。これによってローカルの typescript のバージョンを尊重できる。
Discussion