Há algumas semanas escrevi sobre por que agentes de IA precisam de tokens pessoais. A configuração no fim daquele post funciona bem no Claude Code: crie um token, rode um comando, e o seu agente consegue ler relatórios de bug.
Aí as pessoas tentaram adicionar o BugDump ao Claude na web, e não funcionou.
Num conector personalizado do Claude não há onde colar um token. No ChatGPT também não. O VS Code aceita um cabeçalho se você editar o arquivo de configuração dele, mas o fluxo «Add Server» não pede nenhum. Os clientes MCP que a maioria das pessoas usa esperam uma URL e, quando o servidor responde 401, esperam fazer login.
Então adicionei login ao servidor MCP do BugDump. O código foi a parte pequena. Abaixo está como isso fica para quem se conecta e as quatro decisões que tomaram a maior parte do tempo.
Como um cliente MCP faz login
Você copia https://api.bugdump.com/api/mcp e adiciona ao Claude como um conector personalizado, ou clica em Adicionar ao Claude na página MCP do seu projeto, que copia por você. O Claude abre uma página do BugDump no seu navegador. Você entra, escolhe se o app pode alterar coisas ou só lê-las, e clica em Permitir.

Por baixo, é o fluxo que a especificação do MCP descreve. A primeira requisição volta como 401, com um cabeçalho WWW-Authenticate apontando para um pequeno documento JSON. Esse documento informa qual servidor cuida do login. O Claude busca os metadados desse servidor, manda você para a página de login e troca o resultado por um token. Nada disso é específico do Claude. Um cliente que segue a especificação só precisa da URL para encontrar a página de login.
Uma conexão para todos os seus projetos
Os tokens pessoais no BugDump são vinculados a um único projeto. É um modelo organizado. Um token da Acme Store não enxerga a Acme Admin, e ninguém precisa se perguntar em que projeto o agente está trabalhando.
Minha ideia era manter isso também no login: uma conexão por projeto, talvez com uma URL por projeto. Aí tentei adicionar uma segunda. O Claude não adiciona a mesma URL de conector duas vezes, e uma URL diferente para cada projeto significa um conector separado para configurar e acompanhar em cada um. Quem tem três projetos acabaria com três conectores, e a maioria das pessoas pararia no primeiro.
Por isso, uma conexão por login pertence a você, não a um projeto. Ela alcança todos os projetos dos quais você é membro, e todas as outras ferramentas recebem um argumento a mais, project: o slug do projeto, que pode ser omitido se você pertence a um projeto só. Uma ferramenta nova, list_projects, informa ao assistente o que ele pode acessar, incluindo a chave de cada projeto, para que ele saiba que AS-1 fica na Acme Store.
A parte de que mais gosto é o que acontece quando o assistente esquece de dizer de qual projeto está falando. O servidor não escolhe um por ele. Se você pertence a mais de um projeto, a chamada volta com isto:
{
"error": "MCP_PROJECT_REQUIRED",
"message": "This account belongs to several projects. Pass `project` with the slug of the one the user means.",
"projects": [
{ "slug": "acme-admin", "key": "AA", "name": "Acme Admin", "role": "OWNER" },
{ "slug": "acme-store", "key": "AS", "name": "Acme Store", "role": "OWNER" }
]
}
Isso volta como o resultado da própria ferramenta, e não como um erro de protocolo, então o modelo lê e tenta de novo com o slug certo. Não deve acontecer com frequência: as instruções do servidor dizem ao assistente para chamar list_projects antes de qualquer outra coisa.
A participação no projeto é verificada a cada chamada. Se alguém sai de um projeto, o assistente dessa pessoa perde o acesso a ele na requisição seguinte, e não há nada para limpar.
Só clientes conhecidos: Client ID Metadata Documents
No OAuth clássico, um app é registrado no servidor antes de poder pedir acesso a alguém, à mão ou via Dynamic Client Registration. A abordagem mais nova que a especificação do MCP recomenda, os Client ID Metadata Documents, deixa o app se identificar com uma URL que ele controla. A do Claude é um arquivo JSON em claude.ai que, entre outras coisas, lista os endereços em que o Claude pode receber o resultado do login.
É um bom design. Sozinho, porém, ele significa que qualquer pessoa capaz de hospedar um arquivo JSON pode aparecer na sua página de consentimento com o nome que quiser.
Por isso o BugDump aceita quatro apps: Claude, Claude Code e VS Code pela URL exata do documento de cada um, e o ChatGPT por um padrão fixo em chatgpt.com, porque ele publica um documento por conexão. A página de consentimento mostra o nome do app e o host onde o documento dele fica («Solicitado por claude.ai»), e isso o app não consegue falsificar. O Dynamic Client Registration está desligado. O Cursor usa esse mecanismo, então o Cursor continua usando um token pessoal, assim como scripts e jobs de CI. É para isso que os tokens servem bem, de qualquer forma.
Checando o token, o consentimento e a conta a cada requisição
Um access token dura uma hora. Depois disso, o app troca discretamente um refresh token por um novo, e é assim que uma conexão continua viva por semanas sem pedir que você faça login de novo. O problema é que a etapa de refresh não para para perguntar se você ainda quer o app conectado, nem se a sua conta continua ativa.
Por isso o endpoint MCP do BugDump pergunta, toda vez. A cada requisição, ele verifica se o access token existe e não expirou, se o seu consentimento para aquele app ainda existe e se a sua conta está ativa e não é de convidado. Desconectar um app apaga o consentimento e todos os tokens dele de uma vez, e a chamada seguinte falha com um 401 que o manda de volta para a página de login. Trocar ou redefinir a senha desconecta todos os apps ao mesmo tempo, que é o que você quer se o motivo da troca for um vazamento.

Os tokens em si são strings aleatórias guardadas como hash, iguais aos tokens pessoais. Não há chaves de assinatura para rotacionar, e revogar um token significa apagar uma linha.
O assistente continua agindo como você
Todo o resto ficou igual de propósito. Um app conectado por login age como você e vê o que você vê. Cada mudança que ele faz aparece no histórico e nos comentários da tarefa com o seu nome e o rótulo via MCP, e o log de auditoria registra qual app a fez. Escolha Somente leitura, e as ferramentas de escrita nem são registradas: o modelo nunca vê move_task, então não tem como tentar chamá-la.

Esse é o Claude num bug de checkout no Safari. Ele leu a tarefa, deixou uma nota sobre onde olhar primeiro, moveu-a para Em andamento e a atribuiu. Para quem ler a tarefa depois, fica claro qual parte veio do assistente.
O que ainda falta resolver
O ChatGPT precisa do modo de desenvolvedor para adicionar um servidor MCP personalizado, e o modo de desenvolvedor exige um plano pago do ChatGPT.
Mudar o acesso significa reconectar. Para dar acesso de escrita a um app que só lê, você o desconecta e conecta de novo. Prefiro que você faça essa escolha de forma deliberada, e não com um botão que depois esquece, mas é um passo a mais.
O rótulo ainda não diz o nome do app. Um comentário diz «via MCP», não «via Claude». Cada comentário e cada entrada do histórico já guardam qual app os fez; a página da tarefa só ainda não mostra isso.
Conectando o BugDump ao Claude, ao ChatGPT ou ao VS Code
Abra a página Servidor MCP de qualquer projeto e clique em Adicionar ao Claude, ou copie a URL para o ChatGPT ou o VS Code. Os passos para cada app estão em Conectar o Claude, o ChatGPT ou o VS Code ao BugDump. Se você usa o Cursor ou está conectando um script, os tokens pessoais continuam funcionando exatamente como antes: veja Usando o BugDump com o Claude Code (MCP).
Leia também
Autenticação em servidores MCP: por que agentes de IA precisam de tokens pessoais — por que uma chave de API compartilhada deixa de servir quando o agente pode mover tarefas e comentar.
O que aprendi criando um servidor MCP para uma ferramenta de desenvolvedores — como desenhar ferramentas que um agente usa certo já na primeira tentativa.
Por que seu agente de IA faz 40 chamadas para responder uma pergunta — o problema N+1 saindo do ORM e chegando ao servidor MCP, e as três perguntas que o resolvem.