ts-morph Refactoring Tools
Refatore bases de código TypeScript e JavaScript usando ts-morph. Suporta renomeação de símbolos e arquivos, movimentação de símbolos e busca por referências.
Documentação
MCP ts-morph Refactoring Tools
Um servidor MCP que fornece operações de refatoração baseadas em AST para codebases TypeScript/JavaScript usando ts-morph. Permite renomear símbolos, renomear arquivos/pastas, buscar referências, etc., mantendo a integridade de todo o projeto.
Índice
Início rápido
Adicione o seguinte ao arquivo de configuração do cliente MCP (mcp.json etc.). Usando npx, a versão mais recente publicada é utilizada automaticamente.
{
"mcpServers": {
"mcp-tsmorph-refactor": {
"command": "npx",
"args": ["-y", "@sirosuzume/mcp-tsmorph-refactor"],
"env": {}
}
}
}
Para personalizar o logging, consulte Configuração de logging. Para iniciar a partir do código-fonte local, consulte Desenvolvimento.
Ferramentas fornecidas
Cada ferramenta analisa o AST com ts-morph e realiza alterações mantendo as referências de todo o projeto. Todas as ferramentas exigem o caminho tsconfig.json do projeto.
| Ferramenta | Descrição |
|---|---|
rename_symbol_by_tsmorph | Renomeia nomes de símbolos em todo o projeto |
rename_filesystem_entry_by_tsmorph | Renomeia arquivos/pastas e atualiza caminhos de import |
find_references_by_tsmorph | Lista definições e referências de símbolos |
remove_path_alias_by_tsmorph | Substitui aliases de caminho por caminhos relativos |
move_symbol_to_file_by_tsmorph | Move símbolos para outro arquivo e atualiza referências |
change_signature_by_tsmorph | Adiciona/remove/reordena argumentos de funções e atualiza todas as chamadas |
get_type_at_position_by_tsmorph | Obtém informações de tipo inferido em uma posição especificada |
find_unused_exports_by_tsmorph | Enumera candidatos a export não utilizado |
rename_symbol_by_tsmorph
Renomeia o nome de um símbolo (função, variável, classe, interface, etc.) em uma posição específica dentro de um arquivo especificado, em todo o projeto.
- Casos de uso: Quando há muitas referências e a alteração manual é difícil.
- Informações necessárias: Caminho do arquivo alvo, posição do símbolo (linha, coluna), nome atual do símbolo, novo nome do símbolo.
rename_filesystem_entry_by_tsmorph
Renomeia vários arquivos e/ou pastas e atualiza automaticamente os caminhos de todas as declarações import / export no projeto.
- Casos de uso: Correção de caminhos de import devido a mudanças na estrutura de arquivos. Quando deseja renomear/mover vários arquivos/pastas de uma só vez.
- Informações necessárias: Array de operações de renomeação
renames: { oldPath: string, newPath: string }[]. - Comportamento:
- Usa principalmente análise de símbolos para resolução de referências.
- Referências que incluem aliases de caminho (como
@/) são atualizadas, mas convertidas para caminhos relativos. - Imports que referenciam índices de diretório (ex:
../components) são atualizados para caminhos de arquivo explícitos (ex:../components/index.tsx). - Verifica conflitos de caminho (caminhos existentes, duplicatas dentro da operação) antes da operação.
- Atenção: Em projetos com muitos arquivos/pastas ou projetos muito grandes, a análise e a atualização podem demorar. Referências a exports padrão no formato
export default Identifier;podem não ser atualizadas corretamente (limitação conhecida).
find_references_by_tsmorph
Busca e lista o local de definição de um símbolo em uma posição específica dentro de um arquivo especificado, bem como todos os locais de referência em todo o projeto.
- Casos de uso: Entender onde uma função ou variável é utilizada. Investigar o escopo de impacto de uma refatoração.
- Informações necessárias: Caminho do arquivo alvo, posição do símbolo (linha, coluna).
remove_path_alias_by_tsmorph
Substitui aliases de caminho (como @/components) incluídos em declarações import / export dentro de um arquivo ou diretório especificado por caminhos relativos (como ../../components).
- Casos de uso: Quando deseja aumentar a portabilidade do projeto ou alinhar-se a convenções de codificação específicas.
- Informações necessárias: Caminho do arquivo ou diretório a ser processado.
move_symbol_to_file_by_tsmorph
Move um símbolo especificado (função, variável, classe, interface, alias de tipo, Enum) para outro arquivo e atualiza automaticamente as referências em todo o projeto (incluindo caminhos de import/export).
- Casos de uso: Quando deseja extrair uma funcionalidade específica para outro arquivo e alterar a estrutura do código.
- Informações necessárias: Caminhos dos arquivos de origem e destino, nome do símbolo a ser movido. Se houver símbolos com o mesmo nome, o tipo (
declarationKindString) pode ser especificado para resolver a ambiguidade. - Comportamento: Dependências internas usadas apenas dentro desse símbolo também são movidas. Dependências referenciadas por outros símbolos do arquivo de origem permanecem no arquivo de origem e, se necessário,
exporté adicionado para importação no destino. - Atenção: Símbolos exportados como default export (
export default) não podem ser movidos.
change_signature_by_tsmorph
Adiciona, remove ou reordena argumentos de funções, métodos e arrow functions, atualizando também os argumentos de todas as chamadas no projeto.
- Casos de uso: Quando deseja adicionar um argumento obrigatório a uma função com muitos chamadores, ou remover/reordenar argumentos de funções referenciadas via import / re-export / encadeamento de métodos. Atualizações que tendem a ser perdidas em edições únicas de LLM são refletidas de forma confiável via type checker.
- Informações necessárias: Caminho do arquivo alvo, posição do identificador do nome da função (linha, coluna), nome da função, array de operações a aplicar
operations. - Operações (
operations):add: Insere o argumento emindex(final se omitido). SeargumentForCallersfor especificado, insere esse texto na mesma posição em cada chamada. Se omitido, não altera o chamador (apenas para argumentos opcionais/padrão no final).remove: Remove o argumento emindex. Remove a quantidade correspondente de chamadas que passam mais argumentos que esse número.reorder: Reconstrói a lista de argumentos e cada chamada de acordo comnewOrder. Falha se houver chamadas com número de argumentos incompatível.- As operações são aplicadas em sequência, e operações subsequentes referenciam a lista de argumentos após a operação anterior.
- Atenção: Chamadas com argumentos spread (
fn(...args)) falham em operações que modificam argumentos. Se houver muitos chamadores, verifique os arquivos afetados primeiro comdryRun: true. Userename_symbol_by_tsmorphpara renomear argumentos emove_symbol_to_file_by_tsmorphpara mover funções.
get_type_at_position_by_tsmorph
Retorna o tipo, símbolo e local de declaração inferidos pelo TypeChecker em uma posição especificada em um arquivo TypeScript/JavaScript.
- Casos de uso: Quando deseja verificar rapidamente "qual é o tipo inferido real desta variável / expressão / função" sem iniciar
tsc. Quando deseja obter assinaturas de tipo de forma mais barata do queReadarquivos de declaração. Quando deseja verificar a forma real de um valor antes de refatorar. - Informações necessárias: Caminho do arquivo alvo, posição a inspecionar (linha, coluna).
- Atenção: Se apontar para espaços em branco ou linhas de comentário, retorna o tipo inferido no nível do arquivo (ex:
typeof import("...")), o que normalmente não é o resultado pretendido. Verifique onodeKindda resposta e re-direcione para o identificador. Para analisar muitas posições de uma vez, usetscdiretamente.
find_unused_exports_by_tsmorph
Percorre todo o projeto e enumera export que não são referenciados fora dos arquivos de declaração como candidatos.
- Alvos de detecção:
exportinline (export function/class/const/let/var/enum/interface/type),export default(identificadores, funções, classes),export = <Identifier>. - Método de determinação: A partir dos resultados de
findReferencesAsNodes(), exclui referências no mesmo arquivo, referências sobExportDeclaration(re-exportações puras comoexport { x } from "./y") e referências emnode_modules; se restarem 0, é considerado candidato não utilizado. - Casos de uso: Limpeza de código morto, inventário da superfície pública de módulos. Antes de excluir, sempre faça uma verificação dupla com
find_references_by_tsmorph. sameFileRefs(decisão: excluir vs. unexport): Cada candidato inclui o número de referências no mesmo arquivo (excluindo a própria declaração e sites de re-exportação). Como os candidatos relatados são, por definição, "não referenciados fora do arquivo de declaração", a ação de exclusão é decidida por este valor.sameFileRefs=0: Não utilizado mesmo no mesmo arquivo → código morto real. Seguro excluir junto com a declaração (mais confiável combinando comtextHits=0).sameFileRefs=1+: Usado no mesmo arquivo → apenas a palavra-chaveexporté desnecessária. Mantenha a declaração (excluí-la quebrará referências no mesmo arquivo). Excluir todas as declarações relatadas quebrará o build.
textOccurrences(textHits): Número de ocorrências de\b<name>\bem fontes fora dos arquivos de declaração.0significa apenas "não há o nome em outros arquivos"; para saber se há uso no mesmo arquivo, consultesameFileRefsseparadamente (este campo sozinho não permite decidir "seguro excluir"). Se1+, pode haver literais de string / JSX / referências dinâmicas, então verifique comfind_references_by_tsmorph.- Falsos positivos de default export: Candidatos com a tag
[default](export default <Identifier>/export = <Identifier>) tendem a gerar falsos positivos porquefindReferencesAsNodesnão se conecta a default imports deimport Foo from "./mod". Default exports comtextHitssuficientemente maior que 0 estão quase certamente em uso. Trate como baixa confiança e verifique sempre comfind_references_by_tsmorph. responseFormat:"list"(padrão, 1 candidato por linha) /"summary"(agregação de todo o projeto = total, detalhamento de segurança de exclusão, por tipo, por diretório). Em repositórios grandes, listar tudo tende a exceder o limite de tamanho da resposta; primeiro use"summary"para entender a distribuição de código morto, filtre comentryPoints/excludeFilePatternse depois obtenha posições precisas com"list"(summaryescaneia tudo independentemente demaxResults).- Opções:
entryPoints(array de caminhos absolutos; sempre tratados como usados como API pública),excludeFilePatterns(exclui do escaneamento por correspondência parcial),maxResults(limite do modo list; padrão 100),expandNamespaceImports(padrão ON). - Limitações conhecidas:
require/import()dinâmicos, roteamento dependente de convenções do sistema de arquivos (comopage.tsxdo Next.js) e referências através de reflexão de strings não podem ser detectados. Filtre candidatos comentryPoints/excludeFilePatterns. - Pacotes dist compilados em monorepo são falsos positivos sistemáticos: Se um pacote de workspace publica artefatos de build (ex:
./dist/index.js) viaexports(oumain/module/types) no package.json, imports de outros pacotes são resolvidos para a saída do build (ou node_modules) e não se vinculam aos símbolos do lado src escaneado. Portanto, exports realmente consumidos aparecem como candidatos não utilizados em lote apenas para esse pacote. Esta forma é detectada estruturalmente e um aviso por pacote ⚠ (nome do pacote, entrypoint apontando para fora do escaneamento, número de candidatos afetados) é adicionado ao início dos resultados. Trate candidatos de pacotes com aviso como baixa confiança e verifique sempre comtextHitsefind_references_by_tsmorphantes de excluir. Solução alternativa: durante a análise, aponte oexportsdesse pacote para a fonte (como./src/index.ts) ou valide candidatos individualmente.
Configuração de logging
Os logs de operação do servidor são controlados por variáveis de ambiente. Configure no bloco env de mcp.json.
| Variável de ambiente | Descrição | Padrão |
|---|---|---|
LOG_LEVEL | Nível de detalhe do log. fatal / error / warn / info / debug / trace / silent | info |
LOG_OUTPUT | Destino de saída. console ou file | console |
LOG_FILE_PATH | Caminho absoluto do arquivo de log quando LOG_OUTPUT=file | [プロジェクトルート]/app.log |
Com LOG_OUTPUT=console e em ambiente de desenvolvimento (NODE_ENV !== 'production'), se pino-pretty estiver instalado, a saída é formatada de forma legível. Para evitar impacto na saída padrão do cliente MCP, especifique file.
Exemplo de configuração:
{
"mcpServers": {
"mcp-tsmorph-refactor": {
"command": "npx",
"args": ["-y", "@sirosuzume/mcp-tsmorph-refactor"],
"env": {
"LOG_LEVEL": "debug",
"LOG_OUTPUT": "file",
"LOG_FILE_PATH": "/Users/yourname/logs/mcp-tsmorph.log"
}
}
}
}
Desenvolvimento
Pré-requisitos
- Node.js (consulte o campo
voltadepackage.jsonpara a versão) - pnpm (consulte o campo
packageManagerdepackage.jsonpara a versão)
Configuração e build
git clone https://github.com/sirosuzume/mcp-tsmorph-refactor.git
cd mcp-tsmorph-refactor
pnpm install
pnpm build # dist/ に出力
Comandos principais
pnpm test # テスト実行
pnpm test:watch # ウォッチモードでテスト
pnpm check-types # 型チェック(コンパイルなし)
pnpm lint # Lint チェック
pnpm lint:fix # Lint 修正
pnpm format # フォーマット
pnpm inspector # MCP Inspector でデバッグ
Usar o build local a partir do cliente MCP
Após o build, você pode iniciar dist/index.js diretamente com node.
{
"mcpServers": {
"mcp-tsmorph-refactor-dev": {
"command": "node",
"args": ["/path/to/your/local/repo/dist/index.js"],
"env": {
"LOG_LEVEL": "debug"
}
}
}
}
Launcher de depuração
Para inspecionar detalhadamente a sequência de inicialização do servidor e a entrada/saída padrão, use scripts/mcp_launcher.js. Ele inicia o processo do servidor real como subprocesso e registra informações de inicialização e saída em .logs/mcp_launcher.log.
Altere command de mcp.json para "node" e args para o caminho de scripts/mcp_launcher.js, reinicie o cliente e você poderá ver .logs/mcp_launcher.log (e os logs do próprio servidor).
{
"mcpServers": {
"mcp-tsmorph-refactor": {
"command": "node",
"args": ["scripts/mcp_launcher.js"],
"env": {
"LOG_OUTPUT": "file",
"LOG_FILE_PATH": ".logs/mcp-ts-morph.log"
}
}
}
}
Release
Este pacote é publicado automaticamente no npm via workflow do GitHub Actions (.github/workflows/release.yml).
A tag Git é a fonte única de verdade para a versão. Tanto version de package.json quanto VERSION de src/version.ts são fixados em 0.0.0-development, e o workflow de release extrai o valor da tag e o incorpora. Não é necessário fazer bump manualmente.
Procedimento de publicação
git checkout main && git pull --ff-only
git tag v1.2.0
git push origin v1.2.0
O push da tag aciona o workflow, que executa em sequência:
- Extrai VERSION (
1.2.0) da tag (v1.2.0) (apenas SemVer estrito; pré-releases não suportados) pnpm testcom a versão placeholder- Reescreve
versiondesrc/version.tsepackage.jsoncomnode scripts/release-version.mjs --bake 1.2.0 pnpm build- Verifica com
grep -Fqueexports.VERSION = "1.2.0";está incluído emdist/version.js - Remove
_version_notedo package.json - Publica no npm com
pnpm publish --provenance(Trusted Publishing / OIDC)
Após a conclusão, verifique a publicação com npm view @sirosuzume/mcp-tsmorph-refactor version.
O npm Trusted Publishing é pré-requisito.
NPM_TOKENestá obsoleto; a publicação é feita via OIDC do GitHub Actions (consulteid-token: writederelease.yml).
Por que a tag é a fonte de verdade
No fluxo antigo, esquecer qualquer um dos 3 passos — "bump da version em package.json", "bump de serverInfo.version em src/mcp/config.ts" e "criar a tag" — resultava em releases inconsistentes (houve histórico real de divergência). No novo fluxo, o valor permanece 0.0.0-development durante todo o desenvolvimento, e o CI atualiza todos os locais olhando a tag no momento do release, portanto esquecimentos de bump são estruturalmente impossíveis.
O CI (.github/workflows/ci.yml) executa node scripts/release-version.mjs --check a cada PR / push na main e verifica se ambos os arquivos permanecem com placeholder. PRs com bump manual falham aqui.
Recuperação em caso de falha
- Se o workflow falhar no meio, não exclua a tag; faça merge da correção na main e crie a próxima tag de patch (
vX.Y.(Z+1)) (fix-forward). - Re-publicar com a mesma tag é impossível devido à imutabilidade do npm, então sobrescrever a tag é inútil.
Licença
Este projeto é publicado sob a licença MIT. Consulte o arquivo LICENSE para detalhes.