Construa um server com 4 operações matemáticas — seu primeiro server multi-tool com validação de entrada.
Antes de escrever qualquer código, vamos planejar nosso server de calculadora. A ideia é criar quatro tools matemáticas básicas: somar, subtrair, multiplicar e dividir. Cada uma receberá dois números de ponto flutuante (float) como parâmetros e retornará o resultado da operação. Este será o seu primeiro server com múltiplas tools — um passo importante na construção de servers MCP mais complexos.
Nosso server terá 4 tools, todas seguindo o mesmo padrão de assinatura:
somar(a: float, b: float) → float
subtrair(a: float, b: float) → float
multiplicar(a: float, b: float) → float
dividir(a: float, b: float) → float # com validação de b != 0
Todas recebem dois floats e retornam um float. A exceção é a divisão, que precisa validar se o divisor é zero antes de executar a operação. Esse padrão consistente facilita tanto a implementação quanto o uso pelo modelo de IA.
Planejar as tools antes de codificar é uma boa prática essencial. Defina o nome, os parâmetros (com tipos) e o retorno de cada tool. Isso garante consistência, facilita a documentação automática gerada pelo FastMCP e ajuda o modelo de IA a entender quando e como usar cada ferramenta. Pense nas tools como uma API — quanto mais previsível, melhor.
Vamos começar pelas operações mais simples: soma e subtração. São tools diretas, sem necessidade de validação especial. Elas servem como base para entender o padrão que será repetido nas demais operações. Com o FastMCP, cada tool é apenas uma função Python decorada — simples assim.
# server_calculadora.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Calculadora")
@mcp.tool()
def somar(a: float, b: float) -> float:
"""Soma dois números."""
return a + b
@mcp.tool()
def subtrair(a: float, b: float) -> float:
"""Subtrai b de a."""
return a - b
Note como os type hints (a: float, b: float) são fundamentais. O FastMCP usa essas anotações para gerar automaticamente o schema JSON que o cliente MCP envia ao modelo. Sem type hints, o modelo não sabe que tipo de dado enviar.
Sempre escreva docstrings nas suas tools. A docstring vira a descrição da tool no schema MCP — é ela que o modelo lê para decidir qual tool usar. Uma docstring clara como "Soma dois números" é muito melhor do que não ter docstring nenhuma.
O FastMCP converte automaticamente os type hints Python em JSON Schema. Um parâmetro float vira {"type": "number"} no schema. Um str vira {"type": "string"}. Essa conversão automática elimina a necessidade de escrever schemas manualmente — basta anotar as funções Python corretamente e o FastMCP cuida do resto.
A tool de multiplicação segue exatamente o mesmo padrão das anteriores. Isso é intencional — manter consistência entre as tools facilita a vida do desenvolvedor e do modelo. Aqui também é uma boa oportunidade para entender como o FastMCP gera o schema automaticamente a partir da sua função Python.
@mcp.tool()
def multiplicar(a: float, b: float) -> float:
"""Multiplica dois números."""
return a * b
Quando o FastMCP registra essa tool, ele gera automaticamente um schema como: {"name": "multiplicar", "description": "Multiplica dois números.", "inputSchema": {"type": "object", "properties": {"a": {"type": "number"}, "b": {"type": "number"}}, "required": ["a", "b"]}}. Tudo isso a partir de uma simples função Python com type hints e docstring.
A divisão é diferente das demais operações porque tem um caso especial perigoso: a divisão por zero. Se o usuário pedir para dividir qualquer número por zero e a tool simplesmente executar a / b, o Python lançará um ZeroDivisionError e o server pode crashar. Precisamos validar a entrada antes de executar a operação.
@mcp.tool()
def dividir(a: float, b: float) -> str:
"""Divide a por b. Retorna erro se b for zero."""
if b == 0:
return "Erro: divisão por zero não é permitida."
return f"{a / b}"
Ao invés de deixar a exceção estourar, retornamos uma mensagem de erro amigável como string. O modelo recebe essa mensagem e pode informar o usuário de forma natural: "Não é possível dividir por zero." Isso é muito melhor do que um traceback Python incompreensível.
Nunca deixe uma tool crashar! Uma exceção não tratada pode derrubar o server MCP inteiro, desconectando o cliente. Sempre valide entradas, use try/except quando necessário, e retorne mensagens de erro claras. O modelo sabe lidar com mensagens de erro — ele não sabe lidar com um server que parou de responder.
Com as 4 tools implementadas, é hora de configurar o server no Claude Desktop e testar cada operação. O objetivo é verificar que o Claude identifica corretamente qual tool usar para cada pergunta e que todas as operações retornam resultados corretos — incluindo o tratamento de divisão por zero.
Adicione o server ao claude_desktop_config.json e reinicie o Claude Desktop. Depois, não se esqueça de adicionar o bloco de inicialização ao final do arquivo:
if __name__ == "__main__":
mcp.run()
Agora teste as tools com perguntas naturais. O Claude vai escolher automaticamente a tool correta para cada operação.
"Quanto é 15 + 27?" — O Claude deve usar a tool somar e retornar 42.
"Qual é 100 menos 37?" — O Claude deve usar subtrair e retornar 63.
"Multiplique 8 por 7." — O Claude deve usar multiplicar e retornar 56.
"Divida 100 por 4." — O Claude deve usar dividir e retornar 25.
"Divida 100 por 0." — O Claude deve receber a mensagem de erro e explicar que divisão por zero não é possível.
Teste também com números decimais ("Quanto é 3.14 vezes 2?") e com números negativos ("Subtraia 50 de 30"). Verifique se o Claude consegue encadear operações: "Some 10 e 20, depois multiplique por 3" — ele deve chamar as tools na ordem correta.
Agora que o server básico funciona, podemos pensar em melhorias. Arredondamento de resultados, suporte explícito a inteiros e floats, e a adição de novas operações como potenciação. Essas melhorias transformam um server de demonstração em algo mais robusto e profissional.
Algumas melhorias práticas para o server de calculadora:
round(resultado, 10) para evitar problemas de ponto flutuante como 0.1 + 0.2 = 0.30000000000000004.
a: int | float para aceitar tanto inteiros quanto floats explicitamente.
potenciar(base: float, expoente: float) como exercício — segue o mesmo padrão das demais.
Como exercício, implemente a tool potenciar(base: float, expoente: float). Ela deve retornar base ** expoente. Pense: precisa de validação especial? O que acontece com 0 ** 0? E com expoentes negativos? Pratique o pensamento de "o que pode dar errado?" — essa mentalidade vai te servir em todo server MCP que construir.
Próximo Módulo: 3.5 — Server de Consulta ao Clima