Postagens

Por que construímos um servidor MCP nativo para retros

Ilustração editorial de um quadro de retro com post-its fluindo para um painel de chat à esquerda, gradiente suave de roxo e rosa, estilo vetorial flat moderno, o chat está escolhendo ferramentas em uma pequena paleta, sem textos legíveis ou rótulos de UI
Kelly Lewandowski

Kelly Lewandowski

Última atualização 19/05/20267 min de leitura

Poderíamos ter lançado um servidor MCP do Kollabe em uma tarde, rodando nossa spec OpenAPI por um gerador de código. Em vez disso, passamos algumas semanas projetando a superfície de ferramentas à mão. Esta é a parte dessa decisão que mais nos surpreendeu: o trabalho foi quase inteiramente sobre retros. Standups e planning poker são mecânicos. Você envia respostas; você dá um voto. Um modelo que sabe ler JSON e escrever JSON se vira bem com um wrapper gerado. Retros têm o formato oposto. São longas, bagunçadas, anônimas em partes, votadas, reagidas, agrupadas, resumidas, e referenciam pessoas que talvez você não consiga procurar pelo nome. A primeira versão que tentamos, aquela que espelhava REST um-para-um, caiu no momento em que um modelo tentou dar kudos a alguém.

"Nativo" não significa "código diferente"

Um servidor MCP nativo não é um backend separado. O nosso é uma camada fina por cima dos mesmos endpoints /api/v1/ que qualquer pessoa com um personal access token pode chamar diretamente. Os mesmos handlers, os mesmos schemas Zod, as mesmas verificações de permissão. Se mudamos uma regra em um, o outro acompanha. O que nativo significa é que a superfície de ferramentas foi projetada para quem a utiliza. Uma API REST é lida por um desenvolvedor com a documentação aberta. Um servidor MCP é lido por um modelo no meio de uma conversa, com mil tokens de system prompt já gastos e um usuário esperando. Os dois consumidores querem coisas diferentes do mesmo backend. Quatro diferenças acabaram importando para os retros.

Decisão 1: menos ferramentas, com toggles em vez de pares

Um servidor gerado teria nos dado um retro_create_reaction e um retro_delete_reaction, da mesma forma que nossas rotas REST separam create de delete. Duas ferramentas por reação emoji. Multiplique isso pelos itens e comentários e você está gastando tokens de verdade com ruído antes que o modelo tenha feito qualquer coisa útil. Reduzimos toda ação reversível a uma única ferramenta. retro_toggle_reaction é uma ferramenta só que liga ou desliga um emoji dependendo de quem chamou já ter reagido. Ela retorna "added" ou "removed" na resposta, então o modelo pode narrar o que aconteceu sem armazenar ids de reação que só seriam necessários para chamar delete. A mesma lógica manteve os votos em itens como um par (você pode ter múltiplos votos no mesmo item, então você realmente precisa de um id para remover um) e manteve criação e exclusão de itens separadas (itens não são estado reversível, são registros). Toggle quando reversível, manter separado quando não.

Decisão 2: escreva dicas dentro das descrições, não na documentação

A ferramenta de kudos do retro nos ensinou isso. A primeira versão aceitava um userId e um kudoType e retornava um erro amigável se você passasse alguém que não estivesse no space. Os modelos consistentemente inventavam um id de usuário, batiam no erro, pediam desculpas, e pediam ao usuário para colar o id correto. Inútil. Resolvemos reescrevendo a descrição da ferramenta em vez do handler:
Dê kudos a outro usuário, vinculado a um item de retro existente (crie um primeiro com retro_create_item se não houver). O recebedor precisa ser membro do space do retro — use organization_list_users (suporta um filtro de busca) para procurar o id do usuário pelo nome.
Mesmo código, mesmo erro, mas agora o modelo lê a descrição, chama organization_list_users com o nome que o usuário falou em voz alta, pega o id, e dá os kudos de uma só vez. O handler não mudou. A dica sim. Ilustração de uma bolha de chat à esquerda com um pequeno fluxo de trabalho à direita mostrando três passos: buscar um usuário, encontrar seu registro, e então anexar kudos a um item de retro, paleta pastel suave, estilo vetorial editorial flat Começamos a fazer isso em todo lugar. retro_update avisa dentro da descrição que excluir uma coluna também exclui todos os itens dela. retro_cast_item_vote menciona explicitamente o limite de votos por board e por coluna para que o modelo possa avisar o usuário antes de bater no 400. Todo "você precisa saber disso para me chamar corretamente" vai dentro da ferramenta, não em um guia separado que ninguém lê.

Decisão 3: uma ferramenta de busca semântica, não uma cadeia de list-and-filter

Retros se acumulam. Um time que roda um a cada duas semanas tem 26 boards por ano, com talvez 800 itens entre eles. Quando alguém pergunta a um assistente "o que dissemos sobre deploys instáveis no trimestre passado", a pior resposta possível é o modelo chamar retro_list, depois retro_list_items para cada resultado, e então ler todos eles para o contexto. Isso é uma tempestade de chamadas de ferramenta que custa dinheiro ao usuário e produz uma resposta pior do que um grep daria. Então construímos uma ferramenta de search que roda busca semântica em todo o space de uma só vez. Ela retorna itens de retro, comentários, action items, respostas de standup, respostas de enquetes, respostas de ice-breaker e notas, ranqueados por similaridade de cosseno em relação à consulta, agrupados por tipo. O modelo recebe os 20 resultados mais relevantes em uma chamada em vez de se espalhar por centenas de registros.

Decisão 4: consentimento por funcionalidade no momento do OAuth

O servidor MCP do Kollabe tem cerca de quarenta ferramentas entre retros, standups, planning poker, action items e busca. Pedir ao usuário para consentir com as quarenta em uma única tela é o tipo de decisão que as pessoas clicam sem ler. Dividimos a tela de consentimento por categoria. Quando você conecta o Kollabe ao Claude ou ao Cursor, você marca as categorias que quer (retros, standups, planning poker, action items, busca) e o token fica escopado a elas. Um time que só quer que seu PM rascunhe action items de retro através do Claude não precisa conceder acesso a standup ou poker. Uma revogação na página de configurações do usuário derruba tudo, independente de ter consentido a uma ou todas as categorias. O token também nomeia uma organização específica do Kollabe. Se você pertence a várias orgs, você escolhe qual na tela de consentimento, e o token age como você, naquela org apenas. Trocou de org, reconecta.

O que isso significa no quadro do retro

Um usuário que conectou o Kollabe ao seu cliente de IA agora pode ter uma conversa parecida com esta, com o modelo fazendo o trabalho pesado:
  1. Pré-popular o board
    "Abra o retro desta sprint e adicione itens dos post-mortems que escrevemos no Linear nesta quinzena, um por incidente, na coluna O Que Poderia Melhorar." O modelo cria os itens, marca como anônimos onde o ticket de origem era, e para.
  2. Encontre contexto de retros antigos
    "Já falamos sobre instabilidade de CI antes?" A busca semântica retorna os três retros onde o assunto apareceu e os action items que saíram deles, em uma chamada.
  3. Transforme discussão em action items
    "Crie action items a partir dos três itens mais votados do board, atribua cada um a quem o escreveu, prazo sexta-feira." retro_list_items e em seguida algumas chamadas a action_item_create. O modelo faz a atribuição a partir do autor do item.
  4. Dê kudos pelo nome
    "Dê kudos à Priya por desbloquear a migração." O modelo chama organization_list_users com uma busca por "Priya," e então anexa os kudos.
Nada disso é uma feature nova. Cada uma dessas chamadas mapeia para um endpoint REST que está no ar há meses. A camada MCP é a diferença entre "a API existe" e "o modelo consegue usar a API".

O que faríamos de novo, o que pularíamos

Construiríamos o padrão de toggle desde o primeiro dia. Escreveríamos as dicas com referências cruzadas dentro das descrições desde o primeiro dia. Lançaríamos a busca semântica antes de qualquer endpoint individual de list, porque é a ferramenta que o modelo realmente quer. O que pularíamos é a tentação de tornar o MCP "mais rico" que o REST. Tentamos, brevemente, embutir auto-resumos na ferramenta retro_get. Os modelos então resumiam o resumo, e a latência triplicou. O chato venceu. A ferramenta MCP retorna o mesmo formato que o endpoint REST. IA em cima disso é o usuário que opta via prompt, não algo que a gente embute no protocolo. Se quiser experimentar isso nos seus próprios retros, o guia de setup leva sessenta segundos de OAuth. O contexto mais aprofundado sobre o protocolo está no nosso explicador de MCP. E se você prefere ver IA encaixar em um retro antes de plugar um modelo, nosso gerador de templates de retrospectiva é um bom começo sem compromisso.

Não. O servidor MCP é um adaptador fino sobre os mesmos handlers /api/v1/. O trabalho interessante está nas definições das ferramentas: nomeação, agrupamento, dicas, e quais ações são reduzidas a um único toggle. A lógica de backend é compartilhada.

Sim. retro_create_item aceita uma flag anonymous, e retro_create_item_comment também. Quando ativada, a resposta omite o id do usuário autor, do mesmo jeito que a UI faz. Anonimato é garantido no nível do handler, não na descrição.

A descrição da ferramenta retro_update avisa que excluir uma coluna também exclui todos os itens dela. Confiamos no modelo para trazer isso ao usuário antes de chamá-la, do mesmo jeito que um desenvolvedor lendo a documentação notaria o aviso. Não há um passo separado de confirmação dentro do protocolo.

Não. O consentimento é dividido por categoria no momento do OAuth. Você pode conceder acesso só a retros, ou qualquer combinação de retros, standups, planning poker, action items e busca. Os tokens são revogáveis nas suas configurações do Kollabe.