
Meu requirements.txt Está Fixado. O Contrato Real do Meu Servidor MCP Não Está.
De volta em 2026-07-14, encontrei e consertei uma verdadeira armadilha neste repositório: requirements.txt tinha mcp[cli] sem nenhuma restrição de versão. Qualquer instalação nova poderia puxar uma versão principal quebradora sem nenhum aviso. Eu a fixei para mcp[cli]>=1.28.0,<2.0.0 e segui em frente, sentindo que havia fechado a lacuna.
Eu não havia. Eu apenas fixei a biblioteca. O contrato real que meu servidor MCP expõe para qualquer agente que se conecta a ele — os nomes das ferramentas, formas de parâmetros e descrições que um LLM lê para decidir como chamar meu código — não é uma string de versão em lugar nenhum. Ele é gerado novamente, toda vez que o servidor é iniciado, a partir do que minhas assinaturas de função e docstrings dizem naquele momento. Nada fixa isso. Nada difere isso. Nada testa isso.
O que realmente gera o contrato
Meu servidor (server.py) é um aplicativo FastMCP com funções decoradas com @mcp.tool():
@mcp.tool()
def create_article(title: str, body_markdown: str, tags: list[str] = None, published: bool = False) -> dict:
"""Cria um novo artigo no DEV.to. Retorna id e url."""
payload = {"article": {"title": title, "body_markdown": body_markdown, "published": published}}
if tags:
payload["article"]["tags"] = tags
result = _dev("/articles", method="POST", data=payload)
return {"id": result["id"], "url": result.get("url"), "published": result.get("published")}
FastMCP inspeciona essa assinatura no momento da importação e constrói o JSON Schema que um agente realmente vê — nomes de parâmetros, tipos, quais são obrigatórios e a docstring como a descrição da ferramenta. Eu nunca escrevo esse esquema à mão e nunca o verifico em lugar nenhum. Ele é derivado, a cada execução, do código que edito por razões completamente não relacionadas.
Essa é a lacuna. A fixação do requirements.txt impede que o comportamento do próprio FastMCP mude sob mim entre as instalações. Não faz nada sobre meu comportamento mudando o esquema que o FastMCP gera a partir do meu código, em cada commit, sem nenhuma etapa de revisão separada.
Onde isso realmente dói
Três maneiras que eu poderia mudar este arquivo hoje, por razões que não têm nada a ver com "mudar a API", e cada uma delas reescreve silenciosamente o contrato:
Renomear ou reordenar um parâmetro. Se eu renomear body_markdown para body para clareza, a chave da propriedade do esquema gerado muda. Qualquer agente, prompt ou descrição de ferramenta em cache que referenciou body_markdown pelo nome agora está errado — não gerando erro, apenas construindo silenciosamente chamadas contra um campo que não existe mais no esquema que o servidor realmente anuncia.
Ampliar ou restringir um tipo. tags: list[str] = None se tornando tags: str = None (digamos, porque eu decido que separado por vírgula é mais fácil de passar de um script de shell) muda o type do esquema de array para string. Um agente que construiu seu plano de chamada de ferramenta contra o esquema antigo, ou um cliente com uma cópia em cache desatualizada, envia a forma antiga e agora falha em uma verificação de tipo que nunca falhou antes.
Editando uma docstring para clareza. "Cria um novo artigo no DEV.to. Retorna id e url." é o contrato semântico inteiro que um agente recebe sobre quando e como chamar essa ferramenta — sem especificação separada, sem documento OpenAPI, nada. Se eu apertar a redação mais tarde e acidentalmente deixar de fora o fato de que published tem como padrão False, isso não é uma correção de erro. Essa é uma mudança de contrato que acontece de viver em um comentário.
Nenhuma dessas mudanças dispara um teste. git diff mostra a mudança, mas nada neste repositório executa o esquema gerado através de uma verificação de instantâneo, então uma edição de forma de esquema é lida exatamente como uma passagem de redação de docstring no diff — mesmo arquivo, mesmo tipo de hunk, sem sinal de que uma delas quebra chamadores e a outra não.
Confirmando que a lacuna é real, não hipotética
Eu verifiquei se este servidor tem qualquer teste de estabilidade de esquema:
$ grep -rn "list_tools\|inputSchema\|get_schema" --include="*.py" .
Nada. Não há arquivo de teste, nenhum fixture de esquema dourado, nenhuma etapa de CI que sequer imprimiria o esquema para um humano olhar. A única maneira de saber o que um agente realmente recebe é mcp dev server.py e ler a saída do Inspector manualmente — o que nob
Empresas brasileiras que utilizam servidores MCP devem estar cientes da importância de versionar contratos expostos para evitar que mudanças silenciosas quebrem integrações com agentes de IA. A falta de testes de estabilidade de esquema pode levar a falhas inesperadas em aplicações.

