Levantar un agente de inteligencia artificial en un script local hoy en día toma diez líneas de código. Eso lo resuelve cualquiera con un tutorial de media hora. El verdadero dolor de cabeza —el que aparece cuando el proyecto intenta salir del laboratorio y tocar producción— es conectarlo al mundo real.
Escribir integraciones personalizadas para cada base de datos, cada bucket, cada API de terceros o cada servicio interno que nuestro agente necesita consultar se vuelve insostenible en cuanto el sistema escala. Si una API externa cambia un parámetro, el conector se rompe. Si sumas cinco herramientas nuevas, terminas con una maraña de dependencias acopladas imposible de auditar y mantener.
En este artículo vamos a resolver ese problema desde la raíz utilizando el Model Context Protocol (MCP). Veremos su arquitectura de tres capas, cómo levantar un servidor MCP personalizado en Python con FastMCP, cómo orquestar su consumo desde un agente en LangChain mediante canales estándar del sistema operativo, y cómo aprovechar herramientas comunitarias al vuelo con uv sin ensuciar nuestros entornos virtuales.
💻 Código y prácticas disponibles en GitHub:
Todo el material interactivo de esta clase está disponible en el repositorio OnesRomero/Langchain-practices:
- Notebook interactivo: 2.1_mcp.ipynb
- Servidor MCP de ejemplo: resources/2.1_mcp_server.py
El Problema: El Caos de las Integraciones Punto a Punto
Cuando diseñamos agentes sin una capa de abstracción de contexto, caemos inevitablemente en la trampa del acoplamiento estrecho. Cada fuente de datos exige su propia lógica de autenticación, serialización, manejo de errores y formateo de prompts para el modelo.
graph TD
subgraph Caos["1. El Escenario Tradicional: Caos Punto a Punto"]
A1[Agente IA] -. Conector ad-hoc .-> B1[(Bases de Datos / PostgreSQL)]
A1 -. Wrapper manual .-> C1[API Externa / Clima / Búsqueda]
A1 -. Lógica custom .-> D1[Docs GitHub / Logs Locales]
A1 -. Dependencia local .-> E1[Herramientas del Sistema Operativo]
end
subgraph Bus["2. La Arquitectura con MCP: Bus Universal"]
A2[Agente IA / Host] <-->|MCP Client| M[Protocolo MCP]
M <--> S1[MCP Server: Bases de Datos]
M <--> S2[MCP Server: Búsqueda Web / APIs]
M <--> S3[MCP Server: Documentación]
M <--> S4[MCP Server: Herramientas del Sistema]
end
Aquí es donde entra MCP. En lugar de tender cables directos y quebradizos entre el modelo y cada recurso, el protocolo opera como un bus universal.
Piénsalo como los puertos USB: eliminan la necesidad de tener cables y adaptadores propietarios para cada periférico. Con MCP, cada fuente de datos (archivos locales, servicios en la nube o APIs externas) se conecta mediante una interfaz estándar. El agente ya no necesita conocer la implementación interna de cada servidor; solo se comunica mediante el protocolo MCP y obtiene acceso inmediato a las capacidades expuestas.
Aunque el protocolo fue propuesto originalmente por Anthropic, nació como un estándar de código abierto totalmente agnóstico al proveedor. Da igual si estás orquestando Claude 3.5 Sonnet, GPT-4o, Llama 3 o un modelo local en Ollama: el protocolo opera exactamente de la misma manera. Construyes un servidor MCP una sola vez y queda disponible para cualquier agente del ecosistema.
| Dimensión | Enfoque Tradicional Punto a Punto | Arquitectura Estandarizada con MCP |
|---|---|---|
| Acoplamiento | Directo entre el prompt del agente y cada SDK | Desacoplado mediante contrato cliente-servidor |
| Mantenimiento | Rompimiento en cadena ante cambios de API | El servidor absorbe los cambios; el contrato se mantiene |
| Reutilización | Conectores duplicados por cada nuevo agente | Un único servidor MCP sirve a múltiples agentes |
| Seguridad y Permisos | Credenciales dispersas en la lógica del bot | Barrera de aislamiento en el proceso del servidor |
Anatomía de MCP: Topología, Primitivos y Transporte
Para implementar MCP con criterio de producción, primero debemos entender sus tres componentes estructurales y cómo dialogan entre sí.
1. La Topología de Tres Capas
flowchart LR
Host["1. Host (Cerebro)<br/>Orquestador / LangChain / LangGraph"] -->|Petición de Contexto / Acción| Client["2. MCP Client (Puente)<br/>MultiServerMCPClient"]
Client -->|Transporte stdio / SSE| Server["3. MCP Server (Proveedor)<br/>FastMCP / Herramientas / Recursos"]
Server -->|Ejecución de Acción / Retorno de Datos| Client
Client -->|Resultados Estructurados| Host
- El Host (Cerebro): Es la aplicación principal, la IA o el agente que orquesta la tarea completa y decide qué pasos ejecutar en función del objetivo del usuario.
- El MCP Client (El Puente Técnico): Reside en el entorno del host (por ejemplo, mediante adaptadores en librerías como
langchain-mcp-adapters). Gestiona el ciclo de vida de las conexiones, envía solicitudes estructuradas y recibe los resultados. - El MCP Server (El Proveedor): El proceso que expone las herramientas, los recursos o las plantillas específicas. Es quien interactúa físicamente con la base de datos, la API o el sistema de archivos, ejecuta la acción solicitada y devuelve la carga útil al cliente.
2. Los Tres Primitivos Clave (Scopes)
Un servidor MCP no se limita a exponer funciones remotas; administra tres alcances claramente diferenciados:
- Herramientas (Tools): Acciones ejecutables para que el modelo modifique su entorno o realice consultas dinámicas. Se definen con
docstringsdescriptivos y esquemas de tipos estrictos para que el modelo comprenda cuándo y cómo llamarlas. - Recursos (Resources): Datos de solo lectura accesibles mediante URIs (por ejemplo, rutas locales o URIs de GitHub como
github://repo/README.md). Traen documentación limpia o logs directo al contexto del modelo sin necesidad de programar llamadas de API ad-hoc. - Plantillas de Prompts (Prompts): Estructuras predefinidas que empaquetan reglas de negocio y guardrails (por ejemplo, limitar el alcance de un asistente técnico a librerías específicas). Esto evita tener que redactar el system prompt del agente manualmente en el cliente.
3. Mecanismos de Transporte: stdio vs. SSE
La comunicación entre el cliente y el servidor MCP viaja a través de dos mecanismos principales:
- Standard Input / Output (
stdio): Pensado para ejecución local o dentro del mismo contenedor. El cliente levanta el servidor como un subproceso del sistema operativo y se comunica mediante los canales de entrada y salida estándar. Es ultrarrápido, seguro por diseño y no introduce sobrecarga de red ni expone puertos. - Streamable HTTP con Server-Sent Events (SSE): Diseñado para ejecución remota y distribuida. Si el servidor MCP corre en la nube o pertenece a un servicio de terceros (como APIs públicas de clima o viajes), el cliente abre una conexión HTTP y recibe respuestas en streaming de forma fluida.
Manos a la Obra: Construyendo el Servidor MCP con FastMCP
Veamos la implementación de nuestro servidor MCP usando FastMCP. Este servidor expone una herramienta de búsqueda web mediante Tavily, un recurso de solo lectura que obtiene directamente la documentación de GitHub en formato Markdown, y plantillas de prompts para el agente.
El código corresponde al archivo resources/2.1_mcp_server.py de nuestro repositorio de prácticas:
"""
resources/2.1_mcp_server.py: Servidor MCP implementado con FastMCP.
Expone herramientas de búsqueda con Tavily, recursos de GitHub y prompts.
"""
from dotenv import load_dotenv
load_dotenv()
from mcp.server.fastmcp import FastMCP
from tavily import TavilyClient
from typing import Dict, Any
from requests import get
# 1. Instanciamos el servidor con FastMCP
mcp = FastMCP("mcp_server")
# Inicializamos el cliente de Tavily para búsquedas web
tavily_client = TavilyClient()
# 2. Herramienta (Tool) para buscar en la web
@mcp.tool()
def search_web(query: str) -> Dict[str, Any]:
"""Busca información en la web"""
results = tavily_client.search(query)
return results
# 3. Recurso (Resource): proporciona acceso al README del repositorio langchain-ai
@mcp.resource("github://langchain-ai/langchain-mcp-adapters/main/README.md")
def github_file():
"""
Recurso para acceder al archivo README.md de langchain-ai/langchain-mcp-adapters
"""
url = "https://raw.githubusercontent.com/langchain-ai/langchain-mcp-adapters/main/README.md"
try:
resp = get(url)
return resp.text
except Exception as e:
return f"Error: {str(e)}"
# 4. Plantilla de Prompt (Prompt): empaqueta guardrails y reglas de negocio
@mcp.prompt()
def prompt():
"""Analiza datos de un archivo del repositorio langchain-ai con información exhaustiva"""
return """
Eres un asistente útil que responde a las preguntas del usuario sobre LangChain, LangGraph y LangSmith.
Puedes usar las siguientes herramientas/recursos para responder a las preguntas del usuario:
- search_web: Busca información en la web
- github_file: Accede a los archivos del repositorio langchain-ai
Si el usuario hace una pregunta que no esté relacionada con LangChain, LangGraph o LangSmith, debes decir "Lo siento, solo puedo responder preguntas sobre LangChain, LangGraph y LangSmith."
Puedes realizar múltiples llamadas a herramientas y recursos para responder la pregunta del usuario.
También puedes hacer preguntas de aclaración al usuario para comprender mejor su pregunta.
"""
# 5. Ejecutamos el servidor sobre stdio
if __name__ == "__main__":
mcp.run(transport="stdio")
Nota cómo FastMCP simplifica la especificación del protocolo. Al usar los decoradores @mcp.tool(), @mcp.resource() y @mcp.prompt(), la librería genera automáticamente los esquemas JSON-RPC que el cliente necesita para descubrir las capacidades del servidor.
Consumiendo el Servidor desde un Agente en LangChain
Ahora que el servidor está listo, crearemos el cliente en nuestro agente dentro de un Jupyter Notebook o script interactivo (disponible en 2.1_mcp.ipynb).
Usaremos MultiServerMCPClient de la librería langchain-mcp-adapters y levantaremos el servidor como un subproceso local mediante stdio.
💡 Pro-Tip para Usuarios de Windows y Jupyter Notebooks
Si ejecutas subprocesos asíncronos en Windows o dentro de Jupyter Notebooks (ipykernel), te toparás frecuentemente con el error de fileno() o problemas en el bucle de eventos. Para evitarlo, incluye esta configuración al inicio de tu notebook:
import sys
import asyncio
# Solución para subprocesos y error fileno() en Windows / Jupyter
if sys.platform == "win32":
# 1. Usar ProactorEventLoop para soporte completo de subprocesos
if not isinstance(asyncio.get_event_loop_policy(), asyncio.WindowsProactorEventLoopPolicy):
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
# 2. Redirigir stderr para evitar el error fileno() al iniciar servidores MCP
if "ipykernel" in sys.modules:
sys.stderr = sys.__stderr__
El Código del Agente Cliente
"""
Consumo del servidor MCP local desde un agente en LangChain con stdio.
"""
from dotenv import load_dotenv
load_dotenv()
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from pprint import pprint
# 1. Configuramos el cliente MCP conectándolo al script de nuestro servidor local
client = MultiServerMCPClient({
"local_server": {
"transport": "stdio",
"command": "python",
"args": ["resources/2.1_mcp_server.py"],
}
})
# 2. Carga dinámica de capacidades expuestas por el servidor
tools = await client.get_tools()
resources = await client.get_resources("local_server")
prompt_data = await client.get_prompt("local_server", "prompt")
system_prompt = prompt_data[0].content
print(f"✅ Herramientas descubiertas: {[t.name for t in tools]}")
# 3. Instanciamos el agente con las herramientas dinámicas y el prompt del servidor
agent = create_agent(
model="gpt-4o",
tools=tools,
system_prompt=system_prompt
)
# 4. Invocación con trazabilidad mediante Thread ID
config = {"configurable": {"thread_id": "1"}}
consulta = "Cuéntame sobre la librería langchain-mcp-adapters"
response = await agent.ainvoke(
{"messages": [HumanMessage(content=consulta)]},
config=config
)
# 5. Inspeccionamos la respuesta estructurada
pprint(response)
¿Qué ocurre tras bambalinas durante la ejecución?
Cuando corres este código, el flujo operativo sigue una secuencia limpia y predecible:
- Lanzamiento del subproceso:
MultiServerMCPClientlevantapython resources/2.1_mcp_server.pyen segundo plano utilizando tuberías estándar de entrada y salida del sistema operativo (stdio). - Descubrimiento de capacidades: El cliente negocia con el servidor, descubre la herramienta
search_web, el recursogithub_filey la plantillaprompt. - Petición del usuario: El agente recibe la consulta mediante
HumanMessage. El modelo analiza el system prompt inyectado y evalúa si requiere llamar a las herramientas del servidor. - Ejecución aislada: El cliente remite la llamada por
stdioal proceso del servidor, este ejecuta la consulta en Tavily y devuelve el resultado estructurado. - Síntesis del resultado: La IA recibe los datos y formula su respuesta final respetando las directivas del prompt inicial.
Consumo al Vuelo de Servidores Comunitarios con uv
Una de las grandes ventajas de MCP es el catálogo creciente de servidores de código abierto creados por la comunidad (conectores a GitHub, Slack, sistemas de archivos, bases de datos o utilidades).
La fricción habitual al probar estas herramientas es la gestión de dependencias: crear un entorno virtual, pelear con versiones de pip y arriesgarte a ensuciar tu proyecto. Para resolver esto, nos apoyamos en uv, el gestor de paquetes ultra rápido para Python.
En lugar de instalar el paquete localmente, configuramos el cliente MCP para que invoque uv al vuelo. Veamos cómo integrar el servidor comunitario mcp-server-time para resolver consultas horarias y zonas horarias sin programar una sola línea de lógica de calendario:
"""
Consumo de servidores MCP comunitarios al vuelo mediante uv.
"""
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from pprint import pprint
# Delegamos la ejecución aislada en uv llamando al módulo mcp_server_time
client_tiempo = MultiServerMCPClient({
"time": {
"transport": "stdio",
"command": "uv",
"args": [
"run",
"python",
"-m",
"mcp_server_time",
"--local-timezone=America/Santiago",
],
}
})
# El cliente descubre automáticamente las funciones disponibles (ej. get_current_time)
tools_tiempo = await client_tiempo.get_tools()
agent_reloj = create_agent(
model="gpt-4o",
tools=tools_tiempo,
)
pregunta = HumanMessage(content="¿Qué hora es?")
resultado = await agent_reloj.ainvoke(
{"messages": [pregunta]}
)
pprint(resultado)
El resultado en consola
Al invocar el agente, la salida refleja cómo el modelo resuelve la necesidad de forma autónoma:
👤 Usuario: ¿Qué hora es?
🤖 [Tool Call] El agente invoca: get_current_time con {}
⚙️ [Tool Response] Retorno: 2026-09-22T14:47:35-03:00 (America/Santiago)
🤖 IA: Actualmente son las 2:47 PM en Santiago de Chile, martes 22 de septiembre del 2026.
No tuvimos que programar la lógica del reloj, calcular desplazamientos UTC ni lidiar con librerías de fechas. Le indicamos al cliente que levantara el paquete mcp-server-time mediante uv sobre stdio, y el cliente descubrió e invocó la herramienta al instante.
Buenas Prácticas de Ingeniería para Producción
- Principio de Mínimo Privilegio: Un servidor MCP expone capacidades reales. Nunca otorgues credenciales con privilegios de escritura o borrado masivo a un servidor si el agente solo requiere consultar registros.
- Usa
stdioen entornos contenerizados: Si despliegas tus agentes en AWS ECS, Kubernetes o contenedores Docker, ejecuta los servidores MCP como procesos hijos dentro del mismo contenedor víastdio. Eliminas latencias de red, ahorras costos de balanceadores y blindas la superficie de ataque. - Valida entradas con tipado estricto: El modelo de lenguaje construirá argumentos basados en los tipos de Python (
pydantico anotaciones estándar). Define esquemas claros en cada función decorada con@mcp.tool().
Qué Sigue en la Arquitectura Agéntica
El protocolo MCP resuelve de manera elegante la conexión de agentes con herramientas y fuentes de datos externas. Sin embargo, una vez resuelto el canal de comunicación, surge el siguiente reto arquitectónico: la memoria y el estado.
En la próxima entrega de esta serie veremos cómo dotar a nuestros agentes de un contexto inmutable y un estado persistente que evolucione a lo largo del tiempo, permitiéndole recordar preferencias de usuario y aprender en vivo durante interacciones continuas.
¿Estás diseñando arquitecturas con agentes de IA y buscas desacoplar tus integraciones con MCP?
- Conversemos en red: Conectemos en LinkedIn para debatir sobre arquitecturas agénticas y modelos en producción.
- Consultoría o proyectos: Si buscas llevar estas arquitecturas a tu empresa, escríbeme a través de la sección de contacto.
- Próximas entregas: Suscríbete al newsletter justo debajo para recibir la siguiente parte sobre persistencia y memoria.