# Registros duplicados de servidores MCP estão executando duas vezes?

Um registro MCP duplicado raramente é apenas uma desordem inofensiva na configuração. Quando duas entradas descrevem o mesmo servidor com nomes diferentes, um agente pode receber duas rotas para a mesma capacidade. Com stdio, isso costuma significar dois processos filhos. Com um endpoint remoto, pode significar duas conexões autenticadas, dois inventários de ferramentas e dois lugares independentes em que o agente pode fazer a chamada errada.

A parte mais irritante é que a precedência da configuração não resolve esse tipo de falha. A precedência só decide o que acontece quando as entradas entram em conflito pelo nome. Ela não determina se `repo-api`, `internal-api` e `my-api` são três rótulos para um único executável e uma única conta. Trate a identidade do registro como uma questão operacional, não de nomenclatura.

## Registros duplicados criam caminhos de execução separados

Duas entradas distintas de servidor MCP podem iniciar a mesma coisa duas vezes porque o cliente trata os registros como definições de conexão, não como aliases que devem ser deduplicados. A especificação de transporte MCP diz que um cliente inicia um servidor stdio como subprocesso e troca JSON-RPC pela entrada e saída padrão desse processo. Se duas entradas configuradas invocam o mesmo comando, o resultado normal são dois subprocessos, cada um com sua própria inicialização e ciclo de vida.

Isso não significa que um agente vá chamar mecanicamente todas as ferramentas duas vezes. Os modelos decidem qual ferramenta exposta chamar. Na prática, o risco é maior: o agente pode ver ferramentas com descrições parecidas nos dois registros, chamar uma na primeira tentativa e a outra em uma nova tentativa, ou usar ambas porque seus nomes sugerem responsabilidades diferentes. Enquanto isso, a inicialização do servidor já pode produzir efeitos colaterais antes da primeira chamada de ferramenta.

Já vi servidores que pareciam passivos até que seu caminho de inicialização fosse examinado. Eles atualizam um token de acesso. Criam um diretório de cache. Abrem um banco de dados SQLite local. Iniciam um processo de consulta periódica para manter um índice aquecido. Registram um consumidor de webhook. Nenhuma dessas escolhas viola o MCP. Elas se tornam um problema quando a equipe presume que «servidor MCP» significa um único objeto compartilhado e inerte.

Um servidor remoto muda a forma da falha, mas não elimina a necessidade de evitá-la. O Streamable HTTP foi projetado para um processo de servidor independente capaz de lidar com várias conexões de clientes. Isso é útil quando vários clientes são intencionais. Também significa que o serviço pode receber duas conexões que afirmam ser do agente do mesmo desenvolvedor, a menos que tenha uma forma clara de distingui-las e restringi-las.

A primeira pergunta de diagnóstico é simples: essas duas entradas criam dois caminhos de execução para a mesma autoridade externa? Se a resposta for sim, elas são duplicadas, mesmo quando o JSON é diferente e os nomes parecem coerentes.

## O nome do servidor não é sua identidade

Um registro MCP tem pelo menos duas identidades, e as equipes costumam misturá-las.

A **identidade de exibição** é o nome configurado, como `repo-api` ou `staging-db`. Ela importa porque o cliente a usa para apresentar ferramentas e resolver conflitos de configuração. Serve às pessoas e ao controle interno do cliente.

A **identidade de execução** é aquilo que o registro realmente alcança: um executável com seus argumentos e ambiente relevante, ou uma URL remota com seu contexto de autenticação. Ela serve aos processos e aos sistemas externos.

Em uma configuração organizada, essas identidades coincidem. Mas não precisam coincidir, e presumir que coincidem é como os duplicados passam por uma revisão.

Considere estas entradas:

```json
{
  "mcpServers": {
    "billing": {
      "command": "python3",
      "args": ["tools/billing_mcp.py", "--account", "prod"]
    },
    "finance-tools": {
      "command": "python3",
      "args": ["tools/billing_mcp.py", "--account", "prod"]
    }
  }
}
```

Os nomes são diferentes, mas este é um programa com os mesmos argumentos. A menos que o próprio programa imponha uma única instância, serão dois lançamentos.

Agora veja uma versão menos óbvia:

```json
{
  "mcpServers": {
    "deploy": {
      "command": "./bin/deploy-mcp",
      "args": ["--workspace", "/Users/dev/work/acme"]
    },
    "release-helper": {
      "command": "node",
      "args": ["scripts/mcp-launch.js", "deploy", "--workspace", "/Users/dev/work/acme"]
    }
  }
}
```

Uma comparação textual diz que essas entradas são diferentes. Uma comparação no nível dos processos pode mostrar que o wrapper inicia o mesmo executável `deploy-mcp` com o mesmo workspace. Por isso, a revisão de configuração precisa de uma regra de identidade, não de uma simples busca por linhas duplicadas.

Use esta ordem ao comparar entradas:

1. Compare o endpoint remoto normalizado ou o executável final iniciado pelo comando.
2. Compare os argumentos que selecionam uma conta, locatário, repositório, workspace ou destino de escrita.
3. Compare o diretório de trabalho e os nomes das variáveis de ambiente não secretas que alteram o comportamento.
4. Compare a propriedade das credenciais separadamente. Duas entradas que chegam ao mesmo endpoint com autoridades diferentes não são duplicatas inofensivas. São uma decisão de permissões que precisa de justificativa.

Não compare valores secretos para realizar esta auditoria. Você não precisa deles, e copiá-los para a saída da auditoria cria um segundo problema de segurança. Registre que uma entrada usa `BILLING_TOKEN` e outra usa `PERSONAL_BILLING_TOKEN`; depois determine se essas variáveis autorizam a mesma conta.

## A precedência dos escopos não elimina nomes diferentes

O Claude Code documenta três escopos MCP: local, projeto e usuário. As entradas no escopo do projeto ficam em um arquivo `.mcp.json` do repositório, enquanto as entradas no escopo do usuário ficam disponíveis em todos os projetos. A documentação também diz que um nome de servidor idêntico é resolvido primeiro pelo escopo local, depois pelo projeto e, por fim, pelo usuário. A documentação anterior chamava o escopo do usuário de «global».

Esse comportamento protege você de um caso específico: o mesmo nome aparece em mais de um escopo. Ele não protege contra o registro duplicado mais comum:

```text
Escopo do usuário:    personal-git      -> /Users/dev/bin/git-mcp
Escopo do projeto:    repository-git    -> /Users/dev/bin/git-mcp
```

Os dois nomes podem continuar visíveis porque não há conflito de nomes. Ambos podem ser iniciados e ambos podem expor ferramentas quase idênticas.

Há outra armadilha. Um desenvolvedor vê que o arquivo do projeto contém `repository-git`, adiciona `personal-git` no escopo do usuário porque quer usar a ferramenta fora deste repositório e depois esquece que a entrada do usuário também é carregada dentro do repositório. A experiência inicial é agradável. A limpeza fica para depois, até que uma chamada de ferramenta grave dois registros de auditoria ou um worker em segundo plano bloqueie o mesmo diretório de estado.

Use os escopos para definir propriedade, não por conveniência:

- Coloque um registro no escopo do projeto quando o repositório exigir a integração e a configuração puder ser compartilhada com segurança.
- Coloque-o no escopo do usuário quando for um utilitário pessoal que deve funcionar em vários repositórios.
- Use o escopo local para um experimento privado e específico do repositório que não deve ser versionado.
- Não duplique uma entrada do projeto no escopo do usuário. Se precisar dela em outro lugar, invoque-a apenas onde a configuração do projeto se aplica ou defina uma entrada deliberadamente separada, com um destino diferente e uma finalidade documentada.

Uma substituição com o mesmo nome também merece atenção. Ela não cria duas entradas ativas como ocorre com dois nomes diferentes, mas pode esconder uma configuração da equipe atrás de uma configuração pessoal. O agente então executa ações com um executável privado ou endpoint pessoal, enquanto os revisores presumem que a definição do repositório está em vigor. É uma falha de procedência, não de contagem de processos, e também precisa ser corrigida.

## Prove a duplicação da configuração ao processo e à chamada

Não exclua a primeira entrada que parecer redundante. Estabeleça a cadeia entre configuração, processo e ação externa. Isso evita uma correção que parece limpa, mas remove silenciosamente a única entrada que usa a conta ou o workspace corretos.

Comece dentro do repositório afetado:

```sh
claude mcp list
claude mcp get repository-git
claude mcp get personal-git
```

A Anthropic documenta `claude mcp list`, `claude mcp get` e `claude mcp remove` como os comandos normais de gerenciamento. Use a saída para identificar todos os nomes visíveis e depois examine as entradas suspeitas uma por vez.

Registre cinco fatos para cada entrada em um arquivo temporário: nome configurado, escopo, comando ou URL, argumentos e conta ou workspace externo alcançado. Evite colar valores de ambiente. Para um servidor remoto, registre o host e o caminho, não um cabeçalho de autorização.

Em seguida, inicie uma sessão curta do agente e examine os processos enquanto ele estiver conectado. No macOS ou Linux, substitua `billing_mcp.py` por uma parte exclusiva do comando esperado:

```sh
ps -ax -o pid,ppid,lstart,command | grep '[b]illing_mcp.py'
```

Uma inicialização stdio duplicada produz algo parecido com isto:

```text
91204 91188 Tue Jul 21 10:14:07 2026 python3 tools/billing_mcp.py --account prod
91219 91188 Tue Jul 21 10:14:09 2026 python3 tools/billing_mcp.py --account prod
```

Os IDs dos processos são diferentes. O processo pai pode ser o mesmo processo do agente ou dois processos relacionados. A evidência importante é que os dois comandos têm a mesma identidade de execução e períodos de atividade sobrepostos.

Depois, faça uma chamada de ferramenta deliberadamente segura e somente de leitura. Escolha uma chamada com um resultado esperado limitado, como recuperar o identificador da conta atual ou listar um objeto conhecido. Verifique os próprios logs do sistema de destino, os logs do servidor ou seu diário de ações. Se houver duas conexões independentes, mas uma chamada, você encontrou uma inicialização duplicada do servidor. Se houver duas chamadas, determine se o agente selecionou duas ferramentas, repetiu a tentativa após um erro ou se o próprio servidor repetiu o trabalho. São causas diferentes e precisam de correções diferentes.

A especificação do ciclo de vida MCP exige inicialização antes da operação normal. Ver dois eventos de inicialização basta para provar duas conexões. Isso não prova que alguma ação de negócio ocorreu. Portanto, não diga aos responsáveis pelo incidente que «a implantação foi executada duas vezes» apenas porque viu dois handshakes.

## Crie impressões digitais das configurações sem ler credenciais

Uma verificação útil de duplicação produz uma impressão digital estável para cada entrada configurada e exclui os valores secretos. O script a seguir lê um ou mais arquivos de configuração JSON, extrai `mcpServers` e compara transporte, comando, argumentos, URL, diretório de trabalho e nomes das variáveis de ambiente. Forneça apenas arquivos que você está autorizado a inspecionar.

```python
#!/usr/bin/env python3
# save as mcp_duplicates.py
import hashlib
import json
import pathlib
import sys
from collections import defaultdict

if len(sys.argv) < 2:
    raise SystemExit("usage: mcp_duplicates.py CONFIG [CONFIG ...]")

entries = defaultdict(list)

for raw_path in sys.argv[1:]:
    path = pathlib.Path(raw_path).expanduser()
    with path.open() as handle:
        document = json.load(handle)

    for name, server in document.get("mcpServers", {}).items():
        identity = {
            "type": server.get("type", "stdio"),
            "command": server.get("command"),
            "args": server.get("args", []),
            "url": server.get("url"),
            "cwd": server.get("cwd"),
            "env_names": sorted(server.get("env", {}).keys()),
            "header_names": sorted(server.get("headers", {}).keys()),
        }
        encoded = json.dumps(identity, sort_keys=True, separators=(",", ":"))
        fingerprint = hashlib.sha256(encoded.encode()).hexdigest()[:12]
        entries[fingerprint].append((str(path), name, identity))

for fingerprint, matches in sorted(entries.items()):
    if len(matches) < 2:
        continue
    print(f"DUPLICATE EXECUTION IDENTITY {fingerprint}")
    for path, name, identity in matches:
        print(f"  {path}: {name}")
        print(f"    {json.dumps(identity, sort_keys=True)}")
```

Execute-o contra o `.mcp.json` de um projeto e uma exportação ou cópia higienizada da configuração no nível do usuário usada pelo seu cliente:

```sh
python3 mcp_duplicates.py .mcp.json ~/tmp/user-mcp.json
```

A saída deve ser parecida com esta:

```text
DUPLICATE EXECUTION IDENTITY 64e0e2509d8a
  .mcp.json: repository-git
    {"args":["tools/git_mcp.py"],"command":"python3","cwd":null,"env_names":["GIT_ACCOUNT"],"header_names":[],"type":"stdio","url":null}
  /Users/dev/tmp/user-mcp.json: personal-git
    {"args":["tools/git_mcp.py"],"command":"python3","cwd":null,"env_names":["GIT_ACCOUNT"],"header_names":[],"type":"stdio","url":null}
```

Esta verificação é intencionalmente conservadora. Ela sinaliza entradas com a mesma forma de execução declarada. Não consegue provar que dois comandos wrapper diferentes não convergem para um único processo, nem que duas URLs diferentes não encaminham para o mesmo serviço. Trate o resultado como uma fila de revisão, não como uma lista automática de exclusão.

Também espere falsos negativos quando uma configuração usa um caminho relativo e outra usa um caminho absoluto. Normalize os caminhos antes da comparação se sua equipe usa as duas formas. Faça isso em um script controlado que conheça a raiz do repositório. Não faça uma busca e substituição ampla nos arquivos de configuração.

## Duas instâncias independentes podem discordar sobre o estado

As falhas mais caras nem sempre são chamadas de API duplicadas. Duas instâncias podem discordar sobre o estado local enquanto cada uma se comporta exatamente como seu autor esperava.

Considere um servidor que mantém um cache local de metadados do repositório. A instância A começa com um checkout antigo e grava registros de cache em um diretório padrão compartilhado. A instância B começa depois de uma troca de branch, lê o mesmo diretório e decide que o cache é válido porque o arquivo existe. Uma chamada de ferramenta agora retorna dados que não pertencem à visão atual de nenhum dos processos. O agente pode então fazer uma chamada perfeitamente válida contra um objeto desatualizado.

Outra falha conhecida envolve um consumidor de fila. As duas instâncias se autenticam como o mesmo principal e consultam o mesmo fluxo de tarefas. Se a fila oferece entrega pelo menos uma vez, o tratamento de duplicidades talvez já seja esperado. Se o autor da ferramenta adiciona um mapa local de deduplicação, cada processo recebe seu próprio mapa. O mapa impede duplicidades dentro de um processo e não faz nada entre os dois.

A recomendação ruim aqui é «basta tornar o servidor sem estado». Ela é popular porque parece segura e porque serviços HTTP sem estado lidam bem com muitas conexões. Está errada para ferramentas locais que mantêm caches, estado de atualização do OAuth, observadores de arquivos ou identificadores de operações de propósito. O requisito correto é mais específico: documentar se instâncias simultâneas são suportadas, quais recursos elas compartilham e o que acontece quando duas instâncias usam a mesma identidade.

Peça aos responsáveis pelo servidor que respondam a estas perguntas no README ou na saída de inicialização:

- A inicialização grava arquivos locais, atualiza credenciais ou inicia uma tarefa em segundo plano?
- Dois processos podem usar o mesmo workspace, conta e diretório de cache?
- Cada chamada de ferramenta inclui uma chave de idempotência quando altera um sistema externo?
- Um operador consegue identificar o processo ou a sessão do cliente que produziu um registro?

Se a resposta à segunda pergunta for não, torne o conflito explícito. Use um bloqueio do sistema operacional, um diretório de execução exclusivo por processo ou um lease no servidor. Não dependa de que as pessoas se lembrem de configurá-lo uma única vez.

## Duplicação de ferramentas e duplicação de ações são incidentes diferentes

Um cliente pode expor duas ferramentas semelhantes sem executar nenhuma delas duas vezes. Também pode realizar uma ação externa repetida usando apenas uma ferramenta. As investigações saem do rumo quando alguém chama os dois resultados de «MCP duplicado».

**Exposição duplicada de ferramentas** significa que dois registros anunciam capacidades sobrepostas. O agente pode ver `billing_get_invoice` em dois servidores. Isso é um risco de configuração e de instruções. Corrija os registros e as descrições.

**Execução duplicada** significa que existem dois processos locais ou duas sessões remotas. Isso é um risco de conexão e ciclo de vida. Corrija o caminho de registro, o comportamento de concorrência do servidor ou ambos.

**Ação externa repetida** significa que o sistema de destino recebeu mais de uma solicitação relevante. Isso pode resultar de exposição duplicada, lógica de repetição, timeouts, intervenção do usuário, comportamento do servidor ou um erro do cliente. Prove o fato com um identificador de operação no destino, não por uma inferência baseada no número de processos MCP.

Mantenha estes registros juntos durante um incidente:

```text
Agent run ID:          run-7f3a
Configured name:       repository-git
Server process ID:     91204
MCP connection start:  2026-07-21T10:14:07Z
Tool request ID:       58
Target operation ID:   commit-3a8b
```

Os identificadores não precisam ter exatamente esses nomes. Eles precisam permitir a correlação entre o agente, o servidor e o serviço de destino. Se uma camada não puder produzir um valor de correlação, registre isso no incidente em vez de preencher a lacuna com suposições baseadas em horários.

A separação do Sallyport entre um diário Sessions para execuções do agente e um diário Activity para chamadas individuais é útil aqui porque preserva essa distinção. Uma segunda execução ou conexão não prova automaticamente uma segunda ação externa; os registros das chamadas ainda precisam demonstrá-la.

## Remova um registro sem criar um ponto cego

Depois de identificar uma duplicação verdadeira, escolha um registro canônico antes de remover qualquer coisa. A entrada canônica deve ter um responsável claro, escopo previsível, comando ou endpoint revisado e uma fonte de credenciais definida. «Este funcionou na minha máquina» não é um critério de escolha.

Para uma integração da equipe, a entrada do projeto geralmente é a melhor opção porque pode ser revisada junto com a base de código. Mantenha as credenciais fora desse arquivo compartilhado. O Claude Code oferece expansão de variáveis de ambiente em `.mcp.json`, incluindo valores em comandos, argumentos, campos de ambiente, URLs e cabeçalhos. Isso permite definições compartilhadas sem versionar um token.

Para um utilitário pessoal usado em vários projetos, o escopo do usuário pode ser o lugar certo. Nesse caso, remova a entrada do projeto apenas se o repositório não exigir uma definição comum para os demais colaboradores. Não transforme uma dependência da equipe em um requisito pessoal não documentado.

Use esta sequência de validação silenciosa depois da alteração:

1. Salve a entrada removida fora da configuração ativa durante o teste.
2. Inicie um processo novo do agente. Processos existentes podem manter conexões antigas.
3. Execute `claude mcp list` e inspecione a entrada restante com `claude mcp get <nome>`.
4. Faça uma chamada segura somente de leitura e registre uma conexão e uma solicitação ao destino.
5. Reinicie mais uma vez e confirme que o registro removido não voltou.

Se a remoção interromper um fluxo de trabalho, restaure apenas a definição canônica e corrija seu caminho, variável de ambiente ou permissão ausente. Não restaure as duas entradas como solução rápida. Isso recria a ambiguidade que você acabou de diagnosticar.

## Inclua a detecção de duplicidades na revisão da configuração

O melhor controle é uma regra simples de revisão: todo registro MCP precisa de um responsável, um escopo e uma identidade de execução exclusiva para sua finalidade. Isso basta para capturar a maioria dos acidentes antes que os agentes sejam executados.

Coloque a verificação de impressões digitais em um script do repositório se a equipe mantiver `.mcp.json` sob controle de versão. Execute-a na revisão local e na integração contínua contra a configuração compartilhada. Ela não verá as entradas no escopo do usuário de um desenvolvedor. Por isso, inclua também `claude mcp list` na lista de configuração para colaboradores que relatarem um comportamento estranho das ferramentas.

Para a configuração no escopo do usuário, mantenha um inventário curto fora da própria configuração. Uma linha por servidor basta:

```text
personal-git | user | git tooling across repositories | owner: developer
repository-git | project | repository release workflow | owner: platform team
```

Se as duas linhas apontarem para o mesmo executável e a mesma conta, uma delas precisa ser removida ou seus destinos precisam se tornar intencionalmente diferentes. Não aceite dois rótulos apenas porque um deles parece mais amigável em uma instrução.

A disciplina é simples: uma rota para cada finalidade, propriedade visível e evidência de que uma única ação solicitada produziu um único registro externo. Com isso, um processo duplicado se torna um defeito observável, não um mistério noturno escondido atrás de dois nomes de ferramentas quase idênticos.
