Aprende a exponer datos como Resources para que el modelo acceda a información sin ejecutar acciones.
Hasta ahora hemos trabajado con tools — funciones que ejecutan acciones y devuelven resultados. Ahora conozcamos los resources: datos que el modelo puede leer, pero no modificar. Mientras que las tools son "verbos" (hacer algo), los resources son "sustantivos" (acceder a algo). Esta distinción es fundamental en la arquitectura MCP.
En FastMCP, un resource se crea con el decorador @mcp.resource(), que recibe una URI como identificador único:
@mcp.resource("config://app")
def get_config() -> str:
"""Devuelve la configuración de la app."""
return "versión: 1.0, modo: producción"
La diferencia fundamental: tools ejecutan acciones (enviar un correo electrónico, calcular, consultar una API), mientras que los resources exponen datos (configuraciones, documentación, estado). El modelo lee los resources para obtener contexto, pero no puede usarlos para modificar nada.
Piensa en los resources como archivos en un sistema de archivos virtual. Cada resource tiene una dirección (URI) y un contenido. El modelo puede "abrir y leer" estos archivos, pero no puede "escribir" en ellos. Usa resources para todo lo que el modelo necesita saber, pero no necesita hacer: configuraciones, documentación, constantes y datos de referencia.
Los Resources estáticos devuelven datos fijos que no cambian entre llamadas: configuraciones de la aplicación, documentación, constantes y reglas de negocio. Son los más fáciles de implementar y los más comunes en los servers MCP. El modelo puede acceder a ellos en cualquier momento para obtener información de referencia.
@mcp.resource("config://app")
def get_app_config() -> str:
"""Configuración de la aplicación."""
return """
Aplicación: Mi Server MCP
Versión: 1.0.0
Entorno: producción
Máx. de conexiones: 100
Timeout predeterminado: 30s
"""
@mcp.resource("docs://ajuda")
def get_help() -> str:
"""Documentación de ayuda."""
return "Usa las tools disponibles para calcular y consultar el clima."
Los Resources estáticos son excelentes para proporcionar contexto para el modelo. Por ejemplo, un resource con las reglas de negocio de la empresa permite que el modelo responda preguntas sobre políticas sin necesidad de una tool. Un resource con la documentación del sistema ayuda al modelo a guiar al usuario. Piensa en los resources como el «manual de instrucciones» que el modelo puede consultar.
A diferencia de los estáticos, los resources dinámicos devuelven datos que cambian en cada acceso. La fecha y hora actuales, el estado del sistema, los contadores, los datos de monitoreo: todo eso es dinámico. La función del resource se ejecuta cada vez que el modelo accede a ese URI, lo que garantiza que los datos estén siempre actualizados.
from datetime import datetime
@mcp.resource("status://hora-atual")
def get_hora_atual() -> str:
"""Devuelve la fecha y hora actuales del servidor."""
agora = datetime.now()
return f"Fecha y hora: {agora.strftime('%d/%m/%Y %H:%M:%S')}"
@mcp.resource("status://sistema")
def get_status_sistema() -> str:
"""Devuelve el estado actual del sistema."""
import platform
return (
f"SO: {platform.system()}\n"
f"Python: {platform.python_version()}\n"
f"Hora: {datetime.now().strftime('%H:%M:%S')}"
)
El modelo decide que necesita un dato (ej.: la hora actual) y solicita el resource mediante la URI.
FastMCP recibe la solicitud y ejecuta la función asociada a esa URI en ese momento.
La función devuelve el dato actualizado (ej.: "14:35:22") y el modelo lo usa en su respuesta al usuario.
Los Resources dinámicos son particularmente útiles en escenarios de monitoreo y observabilidad. Un server MCP puede exponer resources con métricas del sistema, estado de los servicios, registros recientes y paneles de estado, lo que permite que el modelo responda preguntas como «¿Cómo está el estado del sistema?» o «¿Cuál es el uso actual de la memoria?» sin necesidad de tools específicas.
Cada resource se identifica con una URI (Uniform Resource Identifier): una dirección única que sigue el estándar tipo://caminho. El "tipo" (scheme) indica la categoría del dato y la "ruta" identifica el recurso específico. Las URIs bien organizadas facilitan que el modelo descubra y use los resources.
El formato de la URI es scheme://path, donde el scheme indica el tipo de dato:
La URI identifica únicamente cada recurso. Dos URI diferentes siempre apuntan a recursos diferentes. Organiza tus URI de forma lógica y coherente.
data://x1 — sin significadoresource://get_stuff — verbo en resourceabc://123 — scheme sin semánticaconfig://ConfiguraçõesDoApp — acentos y mayúsculasconfig://app — claro y concisostatus://health — semántica claradocs://api/endpoints — jerárquicodb://users/schema — específico
El protocolo MCP permite que el client liste todos los resources disponibles en el server. FastMCP lo hace automáticamente: todos los resources registrados con @mcp.resource() aparecen en el listado. Además, MCP admite resource templates — resources parametrizados en los que una parte de la URI es variable.
Los resource templates permiten crear resources parametrizados. FastMCP detecta automáticamente los parámetros en la URI:
@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
"""Devuelve el perfil de un usuario."""
return f"Perfil del usuario {user_id}"
O {user_id} en la URI se convierte en un parámetro. El modelo puede acceder users://alice/profile o users://bob/profile — cada uno devuelve datos diferentes. FastMCP los registra como un resource template en el listado.
El listado de resources funciona como un "catálogo" del server. El client MCP puede solicitar la lista completa de resources antes de usar cualquiera de ellos. Esto permite que el modelo sepa exactamente qué datos están disponibles y cómo acceder a ellos. Mantén organizadas tus URIs y descripciones (docstrings) para facilitar su descubrimiento.
Ten cuidado con lo que expones como resource. Todos los resources registrados quedan visibles para el cliente MCP. Nunca expongas datos sensibles como contraseñas, tokens de API, claves privadas o datos personales sin la protección adecuada. Trata los resources como endpoints públicos: si el modelo no debe leer un dato, no crees un resource para él.
Probemos los resources que creamos en Claude Desktop. El modelo debería poder enumerar los resources disponibles y leer el contenido de cada uno. A diferencia de las tools (que el modelo llama activamente), los resources son datos a los que el modelo puede acceder cuando necesita contexto para responder una pregunta.
Prueba tus resources con preguntas que motiven al modelo a buscarlos:
config://app.
status://hora-atual y devolver el valor dinámico.
status://sistema.
docs://ajuda.
Una buena práctica es crear un resource docs://ajuda en todo server MCP que explique qué tools y resources están disponibles. Cuando el usuario pregunta "¿Qué puedes hacer?", el modelo lee ese resource y presenta las capacidades del server de forma organizada. Es como crear un menú de ayuda integrado.
Pregunta sobre la configuración. Verifica que el modelo devuelva los datos fijos del resource config://app.
Pregunta la hora dos veces con un intervalo. Verifica que los valores cambien entre las consultas.
Haz preguntas que usen tanto tools como resources. Ej.: "Consulta el clima y dime la hora actual."
Siguiente Módulo: 3.7 — Añadiendo prompts