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.

FerramentaDescrição
rename_symbol_by_tsmorphRenomeia nomes de símbolos em todo o projeto
rename_filesystem_entry_by_tsmorphRenomeia arquivos/pastas e atualiza caminhos de import
find_references_by_tsmorphLista definições e referências de símbolos
remove_path_alias_by_tsmorphSubstitui aliases de caminho por caminhos relativos
move_symbol_to_file_by_tsmorphMove símbolos para outro arquivo e atualiza referências
change_signature_by_tsmorphAdiciona/remove/reordena argumentos de funções e atualiza todas as chamadas
get_type_at_position_by_tsmorphObtém informações de tipo inferido em uma posição especificada
find_unused_exports_by_tsmorphEnumera 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 em index (final se omitido). Se argumentForCallers for 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 em index. 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 com newOrder. 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 com dryRun: true. Use rename_symbol_by_tsmorph para renomear argumentos e move_symbol_to_file_by_tsmorph para 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 que Read arquivos 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 o nodeKind da resposta e re-direcione para o identificador. Para analisar muitas posições de uma vez, use tsc diretamente.

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: export inline (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 sob ExportDeclaration (re-exportações puras como export { x } from "./y") e referências em node_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 com textHits=0).
    • sameFileRefs=1+: Usado no mesmo arquivo → apenas a palavra-chave export é 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>\b em fontes fora dos arquivos de declaração. 0 significa apenas "não há o nome em outros arquivos"; para saber se há uso no mesmo arquivo, consulte sameFileRefs separadamente (este campo sozinho não permite decidir "seguro excluir"). Se 1+, pode haver literais de string / JSX / referências dinâmicas, então verifique com find_references_by_tsmorph.
  • Falsos positivos de default export: Candidatos com a tag [default] (export default <Identifier> / export = <Identifier>) tendem a gerar falsos positivos porque findReferencesAsNodes não se conecta a default imports de import Foo from "./mod". Default exports com textHits suficientemente maior que 0 estão quase certamente em uso. Trate como baixa confiança e verifique sempre com find_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 com entryPoints / excludeFilePatterns e depois obtenha posições precisas com "list" (summary escaneia tudo independentemente de maxResults).
  • 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 (como page.tsx do Next.js) e referências através de reflexão de strings não podem ser detectados. Filtre candidatos com entryPoints / 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) via exports (ou main / 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 com textHits e find_references_by_tsmorph antes de excluir. Solução alternativa: durante a análise, aponte o exports desse 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 ambienteDescriçãoPadrão
LOG_LEVELNível de detalhe do log. fatal / error / warn / info / debug / trace / silentinfo
LOG_OUTPUTDestino de saída. console ou fileconsole
LOG_FILE_PATHCaminho 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 volta de package.json para a versão)
  • pnpm (consulte o campo packageManager de package.json para 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:

  1. Extrai VERSION (1.2.0) da tag (v1.2.0) (apenas SemVer estrito; pré-releases não suportados)
  2. pnpm test com a versão placeholder
  3. Reescreve version de src/version.ts e package.json com node scripts/release-version.mjs --bake 1.2.0
  4. pnpm build
  5. Verifica com grep -F que exports.VERSION = "1.2.0"; está incluído em dist/version.js
  6. Remove _version_note do package.json
  7. 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_TOKEN está obsoleto; a publicação é feita via OIDC do GitHub Actions (consulte id-token: write de release.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.