Construye un MCP Server completo que administre tareas con persistencia en JSON: crear, listar, actualizar y eliminar.
Antes de escribir código, es esencial planificar la estructura de nuestro Gestor de Tareas. Vamos a definir cuáles tools el servidor MCP expondrá, cuál será la estructura de datos de cada tarea y cómo organizaremos el proyecto. Una buena planificación ahora evita retrabajos después y garantiza que el servidor sea coherente y fácil de mantener.
Nuestro MCP Server expondrá 4 herramientas para el modelo: crear_tarefa (agrega una nueva tarea), listar_tarefas (muestra las tareas existentes con filtro por estado), actualizar_tarefa (modifica el título, la descripción o el estado) y quitar_tarea (elimina una tarea por ID). Cada tarea tendrá los campos: id (UUID único), título, descripcion, status ("pendiente" o "hecha") y data_criacao. Todas las tareas se guardarán en un archivo JSON local.
Siempre empieza por definir las tools y sus parámetros antes de programar. Piensa desde el punto de vista del usuario: "¿Qué le pediría a Claude que hiciera con mis tareas?". Cada solicitud natural se convierte en una tool. "Crea una tarea" → criar_tarefa. "Muéstrame las pendientes" → listar_tarefas(status="pendente"). Este enfoque top-down garantiza que el servidor sea intuitivo.
El servidor MCP principal: importa FastMCP, define las 4 tools e inicia el servidor. Toda la lógica está aquí.
Archivo de persistencia: el servidor lo crea automáticamente. Contiene la lista de tareas en formato JSON.
Registrar el servidor en claude_desktop_config.json para que Claude pueda usar las tools automáticamente.
Para conservar las tareas entre sesiones, usaremos un archivo tarefas.json. Es simple, legible, no requiere dependencias externas y funciona perfectamente para proyectos locales. Crearemos funciones auxiliares para leer y guardar datos en este archivo usando el módulo pathlib para administrar rutas de forma segura y multiplataforma.
La estructura JSON será una lista de diccionarios, donde cada diccionario representa una tarea. Ejemplo: [{"id": "abc-123", "titulo": "Estudar MCP", "descricao": "Completar trilha 4", "status": "pendente", "data_criacao": "2025-01-15T10:30:00"}]. Dos funciones auxiliares centralizan el acceso al archivo: carregar_tarefas() lee el JSON y devuelve la lista (o una lista vacía si el archivo no existe) y salvar_tarefas(tarefas) escribe la lista actualizada en el archivo. Usar pathlib.Path garantiza que las rutas funcionen en cualquier sistema operativo.
La primera tool que vamos a implementar es la crear_tarefa. Recibe un título obligatorio y una descripción opcional, genera un ID único usando el módulo uuid, define el estado inicial como "pendiente", registra la fecha de creación y guarda todo en el archivo JSON. Es la operación más fundamental de nuestro gestor.
La tool está decorada con @mcp.tool() y definida como def criar_tarefa(titulo: str, descricao: str = ""). Internamente, ella: 1) carga las tareas existentes del JSON, 2) crea un diccionario nuevo con uuid.uuid4() para el ID, el estado "pendiente" y datetime.now().isoformat() para la fecha, 3) lo agrega a la lista y guarda, 4) devuelve un mensaje de confirmación con el ID generado. Claude recibe esa confirmación y puede informar al usuario de forma natural.
Usa type hints en los parámetros de la tool: MCP usa estas anotaciones para generar automáticamente la documentación que recibe el modelo. titulo: str le indica a Claude que debe proporcionar un texto. descricao: str = "" indica que es opcional. Cuanto más claros sean los tipos, mejor entenderá el modelo cómo usar la tool.
Siempre usa str(uuid.uuid4()) para convertir el UUID en una cadena antes de guardarlo en el JSON. El tipo UUID de Python no es serializable de forma predeterminada por el módulo json — si intentas guardar un objeto UUID directamente, recibirás un TypeError. Convertirlo en string resuelve el problema y mantiene la unicidad del identificador.
La tool listar_tarefas permite que Claude consulte las tareas existentes, con la opción de filtrar por estado. Devuelve una lista formateada que el modelo puede presentar de forma legible al usuario, incluida la cantidad total de resultados. Es la tool más usada: probablemente, toda interacción con el administrador comienza o termina con una lista.
Definida como def listar_tarefas(status: str = "todas"), la tool carga todas las tareas del JSON y, si el parámetro status for distinto de "todas", filtra solo las que coinciden ("pendiente" o "hecha"). El resultado debe ser una cadena con formato en la que cada tarea muestre: título, estado, descripción (si la hay) y fecha de creación. Incluye siempre la recuento total al principio: «Se encontraron X tareas». Si no hay tareas, devuelve un mensaje claro como «No se encontraron tareas».
Tools de consulta como listar_tarefas suelen ser las más usadas en cualquier MCP Server: representan cerca de 60-70% de las interacciones. Por eso, dedica tiempo a dar un buen formato al resultado. El modelo usa este texto para redactar la respuesta al usuario. Cuanto más claro y estructurado sea el resultado de la tool, mejor será la respuesta final que Claude genere para el usuario.
Las tools de actualizar_tarefa e quitar_tarea completan el CRUD de nuestro gestor. Ambas reciben el ID de la tarea como parámetro obligatorio y deben validar que ese ID realmente exista antes de ejecutar cualquier operación. La actualización permite cambiar el título, la descripción y/o el estado. La eliminación borra la tarea de forma permanente.
La tool atualizar_tarefa(id: str, titulo: str = None, descricao: str = None, status: str = None) busca la tarea por ID, actualiza solo los campos proporcionados (los que no sean None) y guarda. La herramienta remover_tarefa(id: str) localiza la tarea por ID y la elimina de la lista. Ambas deben validar que el ID exista — si no existe, devuelven un mensaje de error claro como "Tarea con ID 'xyz' no encontrada." Esto evita que el modelo se confunda al intentar operar sobre tareas inexistentes.
Usa parámetros opcionales con None como valor predeterminado en la tool de actualización. Así, Claude puede actualizar solo el campo necesario sin tener que volver a enviar todos los datos. Si el usuario dice "márcala como hecha", el modelo llama atualizar_tarefa(id="abc", status="feita") — el título y la descripción quedan sin cambios porque son None.
¡Siempre valida el ID! Si el modelo intenta actualizar o eliminar una tarea con un ID que no existe, nunca devuelvas una respuesta vacía ni una excepción sin manejar. Devuelve un mensaje de error claro y descriptivo. Sin esta validación, Claude puede creer que la operación se completó correctamente e informar al usuario de manera incorrecta, lo que genera una experiencia confusa y datos inconsistentes.
Con las 4 tools implementadas, es hora de probar el Administrador de Tareas de principio a fin. Vamos a configurar el servidor en Claude Desktop y recorrer un escenario completo: crear tareas, listarlas, actualizar su estado y eliminarlas. Esta prueba valida no solo el código, sino también la experiencia de uso mediante lenguaje natural.
Configura el servidor en claude_desktop_config.json agregando la entrada con el comando para ejecutar el server.py. Reinicia Claude Desktop y verifica que las 4 tools aparezcan en el ícono de herramientas. A partir de ahí, todas las interacciones son en lenguaje natural — Claude decide por su cuenta qué tool llamar según lo que pida el usuario.
"Crea una tarea para estudiar MCP con la descripción: Completar la ruta 4 del curso". Claude debe llamar a criar_tarefa y confirmar con el ID generado.
"Lista todas mis tareas" y luego "Muestra solo las pendientes". Claude debe llamar a listar_tarefas con y sin filtro de estado.
"Marca como hecha la tarea de estudiar MCP". Claude debe usar el ID de la tarea y llamar a atualizar_tarefa con status="feita".
"Elimina la tarea que acabo de completar". Claude debe llamar a remover_tarefa con el ID correcto y confirmar la eliminación.
Si algo no funciona, revisa el terminal donde se está ejecutando el servidor — los errores de Python aparecerán allí. Problemas comunes: ruta incorrecta en la configuración, falta de un import o error de serialización JSON. Usa print() para depuración temporal y verifica que el archivo tarefas.json se esté creando y actualizando correctamente en el directorio del proyecto.
Siguiente Módulo: 4.2 — Consultor de bases de datos