Enables TypeScript-aware file and directory moves within a project by leveraging a persistent tsserver instance to automatically update imports and maintain project integrity.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ts-refactor-mcpmove src/utils.ts to src/lib/utils.ts and update all imports"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
TypeScript-Aware File Moves for AI Agents
Problem
When AI coding agents move TypeScript files, imports break. The agent either:
Naively moves the file → broken imports everywhere → agent spends tokens fixing them one by one → often misses some → user left with broken build
Tries to manually update imports → slow, error-prone, misses re-exports and barrel files → still broken
Meanwhile, VS Code handles this perfectly. When you drag a file in the explorer, TypeScript's language server computes every import that needs updating and applies them atomically. But this capability is locked inside the editor — there's no way for an external agent to access it.
This is the gap: AI agents have filesystem access but no semantic understanding of TypeScript projects. The tooling exists, it's just not exposed.
Appetite
Small batch: 2 weeks
This is a focused integration project, not a research problem. The underlying capability (tsserver's getEditsForFileRename) already exists and is battle-tested. We're building a bridge, not inventing new technology.
Solution
Build an MCP server that wraps a persistent tsserver instance and exposes file-move refactoring as tools that any MCP-compatible agent (Claude, Cursor, etc.) can call.
Core Tools
moveFile
Moves the file and applies all import updates atomically. One tool call, zero broken imports, zero wasted tokens.
With dryRun: true, returns the edit plan without applying — useful if the agent wants to preview or confirm.
moveDirectory
Same thing, but for entire directories. Handles all files recursively.
warmup
Pre-loads the project so subsequent operations are fast. Agent can call this at session start.
Key Design Decisions
Persistent tsserver process
We keep tsserver running between requests. First request pays the startup cost (5-30s for large projects). Subsequent requests: 100ms-2s.
Without persistence, every file move would require a full project reload. That's the mistake existing solutions make.
Use the project's own TypeScript
We spawn tsserver from node_modules/typescript, not a global install. This ensures the refactoring logic matches the project's TypeScript version exactly.
Atomic operations with dry-run escape hatch
By default, the server applies all edits and moves the file in one call. This saves tokens and eliminates the chance of partial failures. For agents that want to preview changes first, dryRun: true returns the edit plan without applying.
Automatic tsserver sync
After applying edits, we notify tsserver that files changed. The project stays in sync without the agent needing to manage it.
Exposed timing and status
Every response includes how long the operation took. A getStatus tool lets agents check if the project is still loading. No black boxes.
Rabbit Holes
❌ Don't build a full LSP bridge
It's tempting to expose all of tsserver's capabilities — completions, diagnostics, go-to-definition. Resist this. Those features are already available through the editor. We're solving one specific problem: file moves that update imports.
If we scope-creep into "LSP for agents," we'll spend the whole cycle on protocol translation and never ship.
❌ Don't try to sync state bidirectionally
When the agent moves files outside our server, we can't perfectly track it. That's fine. We provide a notifyFileMoved hint, but we don't guarantee consistency. If things get out of sync, the agent can call warmup again.
Trying to build a perfect sync mechanism is a rabbit hole. tsserver already handles file watching internally — let it do its job.
❌ Don't support non-TypeScript projects
JavaScript-only projects without tsconfig.json have different (worse) inference behavior. We'd spend half the cycle on edge cases. Punt this to a future cycle.
No-Gos
No partial application — Either all edits succeed or none do; no half-broken states
No project creation — We require an existing
tsconfig.jsonNo monorepo magic — One tsserver per tsconfig; agent handles coordination
No caching across restarts — MCP server restart = cold start (acceptable)
Fat Marker Sketch
Risks and Mitigations
Risk | Likelihood | Mitigation |
tsserver startup too slow for UX | Medium |
|
Large projects timeout | Low | Return partial results + timing info |
tsserver crashes/hangs | Low | Process supervision + restart on failure |
Edit application corrupts files | Low | Atomic writes + validate edits before applying |
Agent wants to preview first | Low |
|
Success Criteria
Agent can move a file in a 1000+ file TypeScript project with zero broken imports
Second move in same session completes in <2 seconds
Works with Cursor, Claude Code, and any MCP-compatible client
Out of Scope (Future Cycles)
Symbol renaming (rename a function across files)
Extract to file (move a function to a new file)
Auto-fix broken imports (after manual moves)
JavaScript-only project support
Multi-root workspaces
These are all valuable, but each is its own pitch. Ship the core, learn from usage, then expand.
Work in Progress
Scope 1: tsserver Client
The job: A TypeScript class that manages a tsserver process and exposes a clean async API.
Interface:
Done when: Unit tests pass against a real tsserver with a small fixture project. No MCP, no file writing — just the protocol layer.
Scope 2: Edit Applier
The job: A module that takes a list of edits from tsserver and applies them to the filesystem atomically.
Interface:
Done when: Unit tests pass — given a temp directory with files, applies edits correctly, handles edge cases (nested directories, file doesn't exist yet, etc.)
Key decisions:
Apply edits in reverse order within a file (so positions don't shift)
Create parent directories for newPath if needed
All-or-nothing: validate all edits are applicable before writing any
Scope 3: MCP Shell
The job: The MCP server definition — tool schemas, argument parsing, response formatting, npm package setup.
Interface:
Done when: MCP server starts, tool is registered, callable from MCP inspector with mock responses. Doesn't need real tsserver yet — can stub the internals.
Integration Points
Each scope has no dependencies on the others during development:
Scope 1 tests against real tsserver with fixture files
Scope 2 tests against a temp directory with pre-written files
Scope 3 tests against mocked responses
Integration is wiring them together — a few hours once all three are green.
Schedule
Day 1-2 | Day 3-4 | Day 5 |
Scope 1: Spawn tsserver, parse responses | Scope 1: | Integration |
Scope 2: | Scope 2: Edge cases, atomicity | Integration |
Scope 3: MCP boilerplate, tool schema | Scope 3: npm packaging, config examples | Ship |