Curso
En el mundo de la IA, el Model Context Protocol (MCP) se ha convertido rápidamente en un tema clave. MCP es un estándar abierto que ofrece a modelos de IA como Claude 4 una forma coherente de conectarse con herramientas externas, servicios y fuentes de datos en tiempo real. Esta conectividad cambia las reglas del juego porque permite a los modelos de lenguaje grandes (LLM) dar respuestas más relevantes, actuales y accionables al tender puentes entre la IA y los sistemas.
En este tutorial, nos adentraremos en FastMCP 2.0, un potente framework que facilita crear tu propio servidor MCP con solo unas pocas líneas de código. Veremos los componentes clave de FastMCP, cómo construir tanto un servidor como un cliente MCP, y cómo integrarlos sin fricción en tu flujo de trabajo. Si eres nuevo en MCP, echa un vistazo a nuestra guía del Model Context Protocol con proyecto de demostración para saber más.
¿Qué es FastMCP 2.0?
FastMCP 2.0 es un framework de Python de código abierto diseñado para que crear servidores y clientes del Model Context Protocol (MCP) sea sencillo y eficiente. Con solo unas líneas de código, los desarrolladores pueden crear servidores MCP a medida y conectarlos a sus aplicaciones de IA, como editores de código o asistentes conversacionales.
FastMCP 2.0 es el sucesor de FastMCP 1.0, que ahora se conoce como MCP Python SDK, y ofrece un kit completo para trabajar en el ecosistema MCP.
Lo que diferencia a FastMCP 2.0 es su conjunto de funcionalidades, mucho más allá de la especificación básica de MCP. Simplifica el despliegue, la autenticación, el proxy de clientes y servidores, e incluso permite generar servidores a partir de APIs REST.
Componentes clave de FastMCP 2.0
FastMCP 2.0 se articula en torno a tres componentes esenciales: herramientas (Tools), recursos (Resources) y prompts.
1. Tools
Las herramientas son funciones de Python expuestas a los LLM mediante el protocolo MCP. Al decorar una función con @mcp.tool, permites que el modelo de IA la invoque durante una conversación. Esto permite a los LLM ejecutar acciones reales, como consultar bases de datos, llamar a APIs o realizar cálculos.
from fastmcp import FastMCPmcp = FastMCP(name="UtilityServer")@mcp.tooldef convert_usd_to_eur(amount: float, rate: float = 0.91) -> float: """Converts a given amount in USD to EUR using the provided rate.""" return round(amount * rate, 2)
2. Resources
Los recursos proporcionan a los LLM o a las aplicaciones cliente acceso de solo lectura a datos, como archivos, registros de base de datos, configuraciones o contenido generado dinámicamente. Por ejemplo:
from fastmcp import FastMCPmcp = FastMCP(name="WeatherResourceServer")@mcp.resource("config://weather-settings")def get_weather_settings() -> dict: """Provides weather configuration.""" return { "default_units": "metric", "default_location": "Berlin", "features_enabled": ["forecast", "alerts"] }@mcp.resource("resource://welcome-message")def welcome_message() -> str: """Returns a dynamic greeting for users based on time of day.""" from datetime import datetime hour = datetime.now().hour if hour < 12: return "Good morning! Here's your weather update." elif hour < 18: return "Good afternoon! Need a forecast?" else: return "Good evening! Let's check the weather."
3. Prompts
Los prompts son plantillas de mensajes reutilizables y parametrizables que orientan las respuestas de los LLM. Al definirlos como funciones, garantizas instrucciones coherentes y con contexto que los clientes pueden invocar.
Son necesarios para ejecutar varias herramientas en secuencia y guiar al LLM para realizar tareas usando las herramientas y recursos disponibles.
from fastmcp import FastMCPfrom fastmcp.prompts.prompt import PromptMessage, TextContentmcp = FastMCP(name="TutorPromptServer")@mcp.promptdef explain_math_concept(concept: str) -> PromptMessage: """Creates a message asking an AI tutor to explain a math concept simply.""" text = f"Can you explain the math concept of '{concept}' in a way that's easy for a 12-year-old to understand?" return PromptMessage(role="user", content=TextContent(type="text", text=text))
Crear un ArXiv Explorer con FastMCP 2.0 y Tavily
En esta sección construiremos un servidor MCP "ArXiv Explorer". Este servidor tendrá dos herramientas: una para extraer enlaces y títulos de artículos científicos, y otra para resumirlos. Además, incluirá recursos y prompts para ayudarte a crear un informe completo sobre el tema elegido.
1. Preparación
Antes de empezar, necesitas obtener la clave de la API de Tavily. Puedes conseguir una clave gratuita con 1.000 solicitudes mensuales en tavily.com. Después, instala las librerías de Python necesarias:
pip install fastmcp tavily-python
2. Creación del servidor "ArxivExplorer"
Primero crearemos el archivo Python del servidor. El archivo incluye:
- Inicialización: crea una instancia de FastMCP asignando el nombre de servidor "ArxivExplorer".
- Recurso: El decorador
@mcp.resourceexpone nuestra funciónarxiv_topicscomo fuente de datos de solo lectura. Un cliente de IA puede obtener estos temas para inspirarse si el usuario no lo tiene claro. - Tools: el decorador
@mcp.toolconvierte funciones normales de Python en acciones que un LLM puede ejecutar. - search_arxiv: esta herramienta usa la API de Tavily para restringir la búsqueda a un dominio específico (arxiv.org), garantizando que solo obtengamos artículos científicos relevantes de arxiv.org.
- summarize_paper: esta herramienta usa
qna_searchde Tavily, optimizada para ofrecer respuestas directas y concisas, perfecta para generar un resumen. - Prompt: el decorador
@mcp.promptcrea una plantilla reutilizable. No es un simple prompt; es un plan estratégico que indica a un LLM cómo usar las herramientas del servidor en secuencia para resolver una tarea compleja. - Transporte HTTP:
mcp.run(transport="http")es clave. En lugar de usar “stdio” para procesos locales, arranca un servidor web. Así, cualquier cliente de la red (o de la misma máquina) puede conectarse a nuestro servidor vía URL, convirtiéndolo en una herramienta remota y compartible.
server.py:
import osfrom typing import Dict, Listfrom fastmcp import FastMCPfrom tavily import TavilyClient# --- Configuration ---TAVILY_API_KEY = os.environ.get("TAVILY_API_KEY")if not TAVILY_API_KEY: raise ValueError("Please set the TAVILY_API_KEY environment variable.")tavily = TavilyClient(api_key=TAVILY_API_KEY)mcp = FastMCP(name="ArxivExplorer")print("✅ ArxivExplorer server initialized.")# --- Dynamic Resource: Suggested AI research topics ---@mcp.resource("resource://ai/arxiv_topics")def arxiv_topics() -> List[str]: return [ "Transformer interpretability", "Efficient large-scale model training", "Federated learning privacy", "Neural network pruning", ]print("✅ Resource 'resource://ai/arxiv_topics' registered.")# --- Tool: Search ArXiv for recent papers ---@mcp.tool(annotations={"title": "Search Arxiv"})def search_arxiv(query: str, max_results: int = 5) -> List[Dict]: """ Queries ArXiv via Tavily, returning title + link for each paper, and *only* ArXiv results. """ resp = tavily.search( query=f"site:arxiv.org {query}", max_results=max_results ) return [ {"title": r["title"].strip(), "url": r["url"]} for r in resp.get("results", []) ]# --- Tool: Summarize an ArXiv paper ---@mcp.tool(annotations={"title": "Summarize Paper"})def summarize_paper(paper_url: str) -> str: """ Returns a one-paragraph summary of the paper at the given URL. """ prompt = f"Summarize the key contributions of this ArXiv paper: {paper_url}" return tavily.qna_search(query=prompt)print("✅ Tools 'Search Arxiv' and 'Summarize Paper' registered.")# --- Prompt Template: Explore a topic thoroughly ---@mcp.promptdef explore_topic_prompt(topic: str) -> str: return ( f"I want to explore recent work on '{topic}'.\n" f"1. Call the 'Search Arxiv' tool to find the 5 most recent papers.\n" f"2. For each paper URL, call 'Summarize Paper' to extract its key contributions.\n" f"3. Combine all summaries into an overview report." )print("✅ Prompt 'explore_topic_prompt' registered.")if __name__ == "__main__": print("\n🚀 Starting ArxivExplorer Server...") mcp.run(transport="http")
3. Creación del cliente interactivo
Necesitamos probar las funciones y endpoints del servidor MCP antes de integrarlo en la aplicación de IA. Para ello, FastMCP ofrece una API sencilla para conectar con el servidor MCP y testear todas sus funciones.
El archivo del cliente incluye:
- Transporte HTTP:
StreamableHttpTransportestá diseñado específicamente para conectarse a un servidor FastMCP ejecutándose en modo HTTP. - Ayudante unwrap_tool_result: es una utilidad crucial. El cliente FastMCP no devuelve datos en bruto; devuelve objetos estructurados. Esta función inspecciona la respuesta y extrae con seguridad los datos de Python que realmente necesitas.
- Flujo de trabajo: la función principal ejecuta una batería de pruebas completa.
- Hace ping al servidor para asegurarse de que está en línea.
- Enumera todas las herramientas, recursos y prompts disponibles.
- Lee el recurso
arxiv_topicsy analiza correctamente el resultado. - Llama a la herramienta
search_arxivy usa la función auxiliar para desempaquetar la lista de artículos. - Encadena herramientas tomando la URL del primer resultado y pasándola a
summarize_paper. - Finalmente, obtiene
explore_topic_prompt, mostrando las instrucciones listas para enviar a un LLM.
client.py:
import astimport asyncioimport pprintfrom fastmcp import Clientfrom fastmcp.client.transports import StreamableHttpTransport# --- Configuration ---SERVER_URL = "http://localhost:8000/mcp" # adjust if hosted elsewherepp = pprint.PrettyPrinter(indent=2, width=100)def unwrap_tool_result(resp): """ Safely unwraps the content from a FastMCP tool call result object. """ if hasattr(resp, "content") and resp.content: # The content is a list containing a single content object content_object = resp.content[0] # It could be JSON or plain text if hasattr(content_object, "json"): return content_object.json if hasattr(content_object, "text"): try: # Use ast.literal_eval for safely evaluating a string containing a Python literal return ast.literal_eval(content_object.text) except (ValueError, SyntaxError): # If it's not a literal, return the raw text return content_object.text return respasync def main(): transport = StreamableHttpTransport(url=SERVER_URL) client = Client(transport) print("\n🚀 Connecting to FastMCP server at:", SERVER_URL) async with client: # 1. Ping to test connectivity print("\n🔗 Testing server connectivity...") await client.ping() print("✅ Server is reachable!\n") # 2. Discover server capabilities print("🛠️ Available tools:") pp.pprint(await client.list_tools()) print("\n📚 Available resources:") pp.pprint(await client.list_resources()) print("\n💬 Available prompts:") pp.pprint(await client.list_prompts()) # 3. Fetch the topics resource print("\n\n📖 Fetching resource: resource://ai/arxiv_topics") res = await client.read_resource("resource://ai/arxiv_topics") topics = ast.literal_eval(res[0].text) print("Today's AI topics:") for i, t in enumerate(topics, 1): print(f" {i}. {t}") # 4. Test the search tool print("\n\n🔍 Testing tool: search_arxiv") raw_search = await client.call_tool( "search_arxiv", {"query": "Transformer interpretability", "max_results": 3}, ) search_results = unwrap_tool_result(raw_search) for i, paper in enumerate(search_results, 1): print(f" {i}. {paper['title']}\n {paper['url']}") # 5. Test the summarize tool on the first result if search_results: first_url = search_results[0]["url"] print("\n\n📝 Testing tool: summarize_paper") raw_summary = await client.call_tool( "summarize_paper", {"paper_url": first_url} ) summary = unwrap_tool_result(raw_summary) print("\nSummary of first paper:\n", summary) # 6. Test the prompt generator print("\n\n🚀 Testing prompt: explore_topic_prompt") prompt_resp = await client.get_prompt( "explore_topic_prompt", {"topic": "Transformer interpretability"} ) print("\nGenerated prompt for an LLM:") for msg in prompt_resp.messages: print(f"{msg.role.upper()}: {msg.content.text}\n")if __name__ == "__main__": asyncio.run(main())
Todos los archivos y configuraciones están disponibles en el repositorio de GitHub kingabzpro/FastMCP-Project. Puedes usarlo si te surge alguna incidencia. También he incluido la guía de instalación para ejecutarlo en local.
4. Ejecución de la aplicación
Ahora vamos a ejecutar tanto el servidor MCP como el cliente.
Primero, define la clave de API de Tavily como variable de entorno en tu sistema local:
export TAVILY_API_KEY='your_tavily_api_key'
Después, ejecuta el servidor:
python server.py
En segundos verás que el servidor FastMCP está en marcha en http://localhost:8000/mcp.

Abre una nueva terminal y ejecuta el script del cliente para comprobar que todo funciona correctamente:
python client.py
Como puedes ver, todas las funciones, recursos, herramientas y prompts funcionan perfectamente. Nuestro servidor MCP rinde bien incluso con múltiples solicitudes a la API de Tavily.
🚀 Connecting to FastMCP server at: http://localhost:8000/mcp🔗 Testing server connectivity...✅ Server is reachable!🛠️ Available tools:[ Tool(name='search_arxiv', title='Search Arxiv', description='Queries ArXiv via Tavily, returning title + link for each paper,\nand *only* ArXiv results.', inputSchema={'properties': {'query': {'title': 'Query', 'type': 'string'}, 'max_results': {'default': 5, 'title': 'Max Results', 'type': 'integer'}}, 'required': ['query'], 'type': 'object'}, outputSchema={'properties': {'result': {'items': {'additionalProperties': True, 'type': 'object'}, 'title': 'Result', 'type': 'array'}}, 'required': ['result'], 'title': '_WrappedResult', 'type': 'object', 'x-fastmcp-wrap-result': True}, annotations=ToolAnnotations(title='Search Arxiv', readOnlyHint=None, destructiveHint=None, idempotentHint=None, openWorldHint=None), meta=None), Tool(name='summarize_paper', title='Summarize Paper', description='Returns a one-paragraph summary of the paper at the given URL.', inputSchema={'properties': {'paper_url': {'title': 'Paper Url', 'type': 'string'}}, 'required': ['paper_url'], 'type': 'object'}, outputSchema={'properties': {'result': {'title': 'Result', 'type': 'string'}}, 'required': ['result'], 'title': '_WrappedResult', 'type': 'object', 'x-fastmcp-wrap-result': True}, annotations=ToolAnnotations(title='Summarize Paper', readOnlyHint=None, destructiveHint=None, idempotentHint=None, openWorldHint=None), meta=None)]📚 Available resources:[ Resource(name='arxiv_topics', title=None, uri=AnyUrl('resource://ai/arxiv_topics'), description=None, mimeType='text/plain', size=None, annotations=None, meta=None)]💬 Available prompts:[ Prompt(name='explore_topic_prompt', title=None, description=None, arguments=[PromptArgument(name='topic', description=None, required=True)], meta=None)]📖 Fetching resource: resource://ai/arxiv_topicsToday's AI topics: 1. Transformer interpretability 2. Efficient large-scale model training 3. Federated learning privacy 4. Neural network pruning🔍 Testing tool: search_arxiv 1. Transformer Interpretability Beyond Attention Visualization https://arxiv.org/abs/2012.09838 2. A Practical Review of Mechanistic Interpretability for ... https://arxiv.org/abs/2407.02646 3. Mechanistic Interpretability of Fine-Tuned Vision ... https://arxiv.org/abs/2503.18762📝 Testing tool: summarize_paperSummary of first paper: The paper proposes a novel method for interpreting Transformer networks beyond attention visualization, introducing a new way to compute relevancy. It aims to enhance interpretability in vision tasks. The method is shown to provide more accurate insights into model decisions.🚀 Testing prompt: explore_topic_promptGenerated prompt:USER: type='text' text="I want to explore recent work on 'Transformer interpretability'.\n1. Call the 'Search Arxiv' tool to find the 5 most recent papers.\n2. For each paper URL, call 'Summarize Paper' to extract its key contributions.\n3. Combine all summaries into an overview report." annotations=None meta=None
Integración del servidor MCP en Cursor AI
Mantén el servidor MCP en ejecución, porque vamos a integrarlo en el editor de código Cursor AI.
- Ve a “Settings”.
- Haz clic en la pestaña “Tools & Integrations”.
- Haz clic en el botón “New MCP Server”.
- Añade la siguiente configuración:
{ "mcpServers": { "ArxivExplorer": { "url": "http://127.0.0.1:8000/mcp/" } }}
Cuando guardes el archivo mcp.json con la configuración anterior, verás el nuevo servidor MCP en la sección “Tools & Integrations”, que mostrará dos herramientas como en la imagen.

Pruebas del servidor MCP en Cursor AI
Ahora viene la parte divertida. Veamos cómo se comporta nuestro servidor MCP con el editor de código Cursor AI. Aprenderemos a usar prompts para invocar herramientas, acceder a recursos y ejecutar prompts personalizados, todo desde el editor.
1. Probar los recursos
Empieza comprobando si tu servidor MCP puede proporcionar datos útiles a través de sus recursos.
Prompt: “what are the some popular arxiv topics”

Si todo está bien configurado, el modelo de IA entenderá tu petición y recuperará automáticamente la lista de temas desde el endpoint de recursos de tu servidor MCP.
2. Probar las herramientas individuales
A continuación, probemos las herramientas que has expuesto mediante MCP. Primero, testaremos la herramienta search_arxiv pidiéndole al modelo de IA que liste los diez artículos más relevantes sobre modelos de lenguaje grandes.
Prompt: “Please search for the top 10 research papers on large language models.”

La IA llamará a la herramienta search_arxiv y deberías ver una lista rápida y precisa de artículos relevantes extraídos directamente de arXiv.
Después probaremos la herramienta de resumen, que toma la URL del artículo y devuelve un resumen del trabajo.
Prompt: “Please summarize the following paper for me: https://arxiv.org/abs/2402.06196”

La herramienta de resumen recuperará el artículo y devolverá un resumen conciso.
3. Probar el prompt
Ahora invocaremos un prompt personalizado del MCP que nos ayudará a generar un informe.
Prompt: “Create a report on Quantum computing using the latest work.”

Si revisas el código del servidor, verás que el modelo de IA comprende la tarea y usa la función explore_topic_prompt.
@mcp.promptdef explore_topic_prompt(topic: str) -> str: return ( f"I want to explore recent work on '{topic}'.\n" f"1. Call the 'Search Arxiv' tool to find the 5 most recent papers.\n" f"2. For each paper URL, call 'Summarize Paper' to extract its key contributions.\n" f"3. Combine all summaries into an overview report." )
Primero, llamará a la herramienta "Search Arxiv" para encontrar los enlaces a los artículos.

Luego, pasará los enlaces a la herramienta "Summarize Paper" uno a uno para generar los resúmenes. Por último, creará el informe.

Conclusión
FastMCP 2.0 ofrece mucho más que una forma simple de crear servidores MCP. Proporciona un framework robusto para construir integraciones de IA seguras, modulares y escalables. Con funciones como autenticación, proxy avanzado (que permite que un servidor FastMCP actúe como frontend de otro) y la posibilidad de combinar varios servidores FastMCP en una sola aplicación mediante montaje e importación, puedes diseñar sistemas complejos y mantenibles con facilidad.
El soporte de middleware te permite añadir funcionalidades transversales, como registro de actividad o modificación de peticiones, a todas las solicitudes y respuestas MCP. También puedes enviar mensajes de log y actualizaciones de progreso a los clientes a través del contexto MCP, lo que facilita monitorizar y gestionar operaciones de larga duración.
En este tutorial, has aprendido a construir un servidor MCP completamente funcional y a probar sus características. Estas herramientas y el protocolo MCP se están convirtiendo en componentes esenciales de las aplicaciones modernas de IA, habilitando a los LLM para realizar tareas más avanzadas y automatizar flujos de trabajo con mayor eficacia.
Para seguir aprendiendo sobre servidores MCP, no te pierdas estos recursos:
- Model Context Protocol (MCP): guía con proyecto de demostración
- Top 10 MCP servers & clients para automatizar flujos de trabajo de IA en 2025
- Guía de Gradio MCP Server: crea, prueba, despliega e integra
- Crear un agente de IA con LangGraph y Model Context Protocol
- Chrome DevTools MCP: automatización y depuración del navegador con IA
Soy un científico de datos certificado que disfruta creando aplicaciones de aprendizaje automático y escribiendo blogs sobre ciencia de datos. Actualmente me centro en la creación de contenidos, la edición y el trabajo con grandes modelos lingüísticos.




