Construye un server con 4 operaciones matemáticas: tu primer server con múltiples tools y validación de entrada.
Antes de escribir código, vamos a planificar nuestro server de calculadora. La idea es crear cuatro tools matemáticas básicas: sumar, restar, multiplicar e dividir. Cada una recibirá dos números de punto flotante (float) como parámetros y devolverá el resultado de la operación. Este será tu primer server con varias tools: un paso importante para construir servers MCP más complejos.
Nuestro server tendrá 4 tools, todas siguiendo el mismo patrón de firma:
sumar(a: float, b: float) → float
restar(a: float, b: float) → float
multiplicar(a: float, b: float) → float
dividir(a: float, b: float) → float # con validación de b != 0
Todas reciben dos floats y devuelven un float. La excepción es la división, que debe validar si el divisor es cero antes de ejecutar la operación. Este patrón coherente facilita tanto la implementación como el uso por parte del modelo de IA.
Planificar las tools antes de programar es un buena práctica esencial. Define el nombre, los parámetros (con tipos) y el valor devuelto de cada tool. Esto garantiza la coherencia, facilita la documentación automática generada por FastMCP y ayuda al modelo de IA a entender cuándo y cómo usar cada herramienta. Piensa en las tools como una API: cuanto más predecible, mejor.
Empecemos por las operaciones más sencillas: suma y resta. Son tools directas, sin necesidad de una validación especial. Sirven como base para entender el patrón que se repetirá en las demás operaciones. Con FastMCP, cada tool es simplemente una función de Python decorada: así de sencillo.
# server_calculadora.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Calculadora")
@mcp.tool()
def sumar(a: float, b: float) -> float:
"""Suma dos números."""
return a + b
@mcp.tool()
def restar(a: float, b: float) -> float:
"""Resta b de a."""
return a - b
Observa cómo los type hints (a: float, b: float) son fundamentales. FastMCP usa estas anotaciones para generar automáticamente el esquema JSON que el cliente MCP envía al modelo. Sin anotaciones de tipo, el modelo no sabe qué tipo de dato enviar.
Siempre escribe docstrings en tus tools. La docstring se convierte en la descripción de la tool en el schema MCP: es lo que el modelo lee para decidir qué tool usar. Una docstring clara como «Suma dos números» es mucho mejor que no tener ninguna.
FastMCP convierte automáticamente los type hints de Python en JSON Schema. Un parámetro float se convierte {"type": "number"} en el schema. Un str se convierte {"type": "string"}. Esta conversión automática elimina la necesidad de escribir schemas manualmente: basta con anotar correctamente las funciones de Python y FastMCP se encarga del resto.
La tool de multiplicación sigue exactamente el mismo patrón que las anteriores. Es intencional: mantener la coherencia entre las tools facilita el trabajo del desarrollador y del modelo. También es una buena oportunidad para entender cómo FastMCP genera el schema automáticamente a partir de tu función de Python.
@mcp.tool()
def multiplicar(a: float, b: float) -> float:
"""Multiplica dos números."""
return a * b
Cuando FastMCP registra esta tool, genera automáticamente un esquema como: {"name": "multiplicar", "description": "Multiplica dois números.", "inputSchema": {"type": "object", "properties": {"a": {"type": "number"}, "b": {"type": "number"}}, "required": ["a", "b"]}}. Todo esto a partir de una simple función de Python con type hints y docstring.
La división es diferente de las demás operaciones porque tiene un caso especial peligroso: la división por cero. Si el usuario pide dividir cualquier número entre cero y la tool simplemente lo ejecuta a / b, Python lanzará un ZeroDivisionError y el servidor puede fallar. Debemos validar la entrada antes de ejecutar la operación.
@mcp.tool()
def dividir(a: float, b: float) -> str:
"""Divide a entre b. Devuelve un error si b es cero."""
if b == 0:
return "Error: no se permite dividir entre cero."
return f"{a / b}"
En lugar de dejar que la excepción se propague, devolvemos una mensaje de error amigable como string. El modelo recibe este mensaje y puede informar al usuario de forma natural: "No es posible dividir entre cero." Esto es mucho mejor que un traceback de Python incomprensible.
¡Nunca dejes que una tool falle! Una excepción no controlada puede hacer que todo el server MCP deje de funcionar y desconectar al cliente. Valida siempre las entradas, usa try/except cuando sea necesario y devuelve mensajes de error claros. El modelo sabe manejar mensajes de error; no sabe manejar un server que dejó de responder.
Con las 4 tools implementadas, es hora de configurar el server en Claude Desktop y probar cada operación. El objetivo es verificar que Claude identifique correctamente qué tool usar para cada pregunta y que todas las operaciones devuelvan resultados correctos, incluido el manejo de la división por cero.
Agrega el server al claude_desktop_config.json y reinicia Claude Desktop. Después, no olvides agregar el bloque de inicialización al final del archivo:
if __name__ == "__main__":
mcp.run()
Ahora prueba las tools con preguntas en lenguaje natural. Claude elegirá automáticamente la tool correcta para cada operación.
"¿Cuánto es 15 + 27?" — Claude debe usar la tool somar y devolver 42.
"¿Cuánto es 100 menos 37?" — Claude debe usar subtrair y devolver 63.
"Multiplica 8 por 7." — Claude debe usar multiplicar y devolver 56.
"Divide 100 entre 4." — Claude debe usar dividir y devolver 25.
"Divide 100 entre 0." — Claude debe recibir el mensaje de error y explicar que no es posible dividir entre cero.
Prueba también con números decimales ("¿Cuánto es 3.14 por 2?") y con números negativos ("Resta 50 de 30"). Verifica si Claude puede encadenar operaciones: "Suma 10 y 20, después multiplica por 3" — debe llamar a las tools en el orden correcto.
Ahora que el server básico funciona, podemos pensar en mejoras. Redondear los resultados, admitir explícitamente enteros y números de punto flotante, y agregar nuevas operaciones como la potenciación. Estas mejoras convierten un server de demostración en algo más robusto y profesional.
Algunas mejoras prácticas para el server de calculadora:
round(resultado, 10) para evitar problemas de punto flotante como 0.1 + 0.2 = 0.30000000000000004.
a: int | float para aceptar explícitamente tanto enteros como números de punto flotante.
potenciar(base: float, expoente: float) como ejercicio: sigue el mismo patrón que los demás.
Como ejercicio, implementa la tool potenciar(base: float, expoente: float). Debe devolver base ** expoente. Piensa: ¿necesita una validación especial? ¿Qué pasa con 0 ** 0? ¿Y con exponentes negativos? Practica el pensamiento de "¿qué puede salir mal?" — esta mentalidad te servirá en cada server MCP que construyas.
Siguiente Módulo: 3.5 — Servidor de consulta del clima