MCP: Mensajes JSON-RPC, servidores FastMCP y un seguimiento ReAct
Sigue una solicitud del Protocolo de Contexto de Modelo desde las herramientas/lista hasta la respuesta final, con servidores FastMCP, un agente LangGraph ReAct y un rastreador que registra cada paso.
Fuentes: How MCP Works: A Deep Dive with Code
El Protocolo de Contexto de Modelo, o MCP, es un estándar abierto de Anthropic que permite a los modelos de IA como Claude acceder a herramientas externas, fuentes de datos y servicios. Una buena analogía es un conector universal: en lugar de escribir una integración personalizada para cada herramienta, existe una forma estándar para que un modelo se comunique con sistemas externos.
Las componentes
La estructura está formada por tres partes. El anfitrión MCP es la aplicación que utiliza realmente una persona, ya sea una ventana de chat o un IDE, y contiene un cliente que gestiona la conexión. El protocolo MCP es la capa de comunicación estandarizada entre el anfitrión y los servidores. Cada servidor MCP se conecta a un tipo de recurso, como una base de datos, una API externa o un entorno de ejecución de código, y actúa como puente hacia él.
Qué ocurre en tiempo de ejecución
A nivel general, una solicitud pasa por estas etapas:
- El usuario envía una consulta al anfitrión.
- El anfitrión pregunta a los servidores MCP qué herramientas ofrecen.
- Los servidores devuelven sus listas de herramientas.
- El anfitrión envía la consulta junto con la lista de herramientas al LLM.
- El LLM elige una herramienta y se lo comunica al anfitrión.
- El anfitrión llama al servidor MCP adecuado para ejecutarla.
- El servidor ejecuta la herramienta y devuelve el resultado.
- El anfitrión transmite ese resultado de vuelta al LLM.
- El LLM escribe la respuesta final y el anfitrión la entrega.
Un servidor expone tres tipos de elementos. Las herramientas son funciones que el modelo puede invocar, como search_web, query_database o send_email. Los recursos son datos legibles que el anfitrión puede obtener como contexto, como archivos, registros de base de datos, eventos de calendario y documentos, los cuales el modelo puede leer pero no ejecutar. Las instrucciones son plantillas preescritas que ofrece el servidor. Por ejemplo, un servidor de GitHub podría proporcionar una plantilla “resumir este PR” que el anfitrión puede mostrar al usuario.
En esencia, MCP es simplemente una forma estandarizada para que un anfitrión converse con un servidor. Establece el formato de los mensajes y las reglas de la conversación, y nada más. Concretamente, define cuatro elementos.
- Forma del mensaje. Todo se realiza mediante JSON-RPC 2.0. Una solicitud contiene un
id, unmethodyparams, mientras que una respuesta repite elidjunto con unresulto unerror, de modo que ambas partes comunican de la misma manera. - Métodos disponibles. El protocolo establece un vocabulario fijo de llamadas que un host puede realizar, como
tools/listpara la detección,tools/callpara ejecutar una herramienta,resources/readpara obtener datos yprompts/getpara recuperar un modelo. Los servidores deben implementarlos. - Proceso de conexión. Al establecerse la conexión por primera vez, ambas partes intercambian mensajes
initializeen los que declaran su versión de protocolo y sus capacidades, de modo que cada una sepa qué soporta la otra antes de que ocurra cualquier otra cosa.
Una sola llamada a la herramienta se divide en cuatro mensajes. Primero, el host pregunta qué herramientas existen:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
El servidor responde con las descripciones de sus herramientas:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search_web",
"description": "Search the web for a given query",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
}
Luego el anfitrión llama a uno de ellos:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_web",
"arguments": {
"query": "latest news on MCP protocol"
}
}
}
Y el servidor devuelve el resultado:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Anthropic released MCP in Nov 2024 as an open standard..."
}
]
}
}
Aprender mediante la creación de proyectos funciona mejor, por lo que el resto de esta explicación muestra un pequeño servidor MCP utilizado por un agente.
Qué hace FastMCP
FastMCP es un framework en Python para desarrollar servidores MCP con la menor cantidad posible de código genérico. Sin él, un desarrollador tendría que implementar el bucle de mensajes JSON-RPC, serializar y deserializar cada solicitud y respuesta, escribir esquemas JSON a mano para cada función expuesta, y manejar mensajes de protocolo como initialize, tools/list, tools/call, resources/list y prompts/list. Con él, basta con una función ordinaria en Python más un decorador, ya que el framework se encarga del resto:
from fastmcp import FastMCP
mcp = FastMCP("My Server") # creates the server
@mcp.tool() # registers the function as an MCP tool
def add(a: float, b: float) -> float:
"""Add two numbers.""" # docstring → tool description sent to the LLM
return a + b # type hints → JSON Schema sent to the LLM
mcp.run() # starts the stdio message loop
A partir de las anotaciones de tipo, FastMCP construye por sí mismo un esquema JSON, y la documentación sirve como descripción en lenguaje sencillo que el modelo lee al decidir si vale la pena llamar a una herramienta. Al invocar mcp.run() se inicia un bucle que bloquea en stdin y stdout mientras utiliza el formato de comunicación MCP, y ese bucle es precisamente al que se conecta MultiServerMCPClient.
Tres primitivas en los servidores de ejemplo
Cada servidor del proyecto es una aplicación FastMCP independiente que expone los tres tipos de primitivas.
Primero vienen las herramientas: las funciones que el modelo puede llamar. Basta con decorar una función de Python con @mcp.tool(), y FastMCP convierte esas anotaciones y la documentación en el esquema JSON que se envía al cliente durante tools/list. El modelo estudia ese esquema para determinar cuándo aplicar la herramienta y qué argumentos proporcionar.
# servers/math_server.py
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide a by b. Raises an error if b is zero."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
Los recursos son datos de solo lectura que se encuentran en una URI. El modelo no los invoca automáticamente, por lo que deben solicitarse de forma explícita. En este proyecto solo se demuestra la idea, mientras que sus usos en entornos de producción podrían incluir archivos de configuración, instantáneas de una base de datos o documentación de referencia.
# servers/math_server.py
@mcp.resource("math://constants")
def get_math_constants() -> str:
"""Common mathematical constants."""
return f"π = {math.pi}\n e = {math.e}\n ..."
@mcp.resource("math://formulas/{category}")
def get_formulas(category: str) -> str:
"""Retrieve mathematical formulas by category (geometry | algebra | statistics)."""
catalog = {
"geometry": (
"Geometry Formulas:\n"
" Circle area: A = π × r²\n"
" Circle circumference: C = 2π × r\n"
" Rectangle area: A = length × width\n"
" Triangle area: A = (base × height) / 2\n"
" Sphere volume: V = (4/3) × π × r³\n"
),
"algebra": (
"Algebra Formulas:\n"
" Quadratic formula: x = (−b ± √(b²−4ac)) / 2a\n"
" Difference of squares: a²−b² = (a+b)(a−b)\n"
" Perfect square: (a+b)² = a²+2ab+b²\n"
" Sum of arithmetic seq: S = n(a₁+aₙ)/2\n"
),
"statistics": (
"Statistics Formulas:\n"
" Mean: μ = Σx / n\n"
" Variance: σ² = Σ(x−μ)² / n\n"
" Std Dev: σ = √(Σ(x−μ)² / n)\n"
" Z-score: z = (x−μ) / σ\n"
),
}
return catalog.get(
category,
f"Unknown category '{category}'. Available: geometry, algebra, statistics",
)
El URI math://formulas/{category} es una plantilla. Su parte {category} es un parámetro de ruta, lo que convierte a math://formulas/geometry y math://formulas/algebra en dos recursos distintos atendidos por la misma función.
Los prompts son plantillas de instrucciones reutilizables. Un prompt es un mensaje del sistema parametrizado que el cliente puede solicitar, una forma de incluir una personalidad de experto o instrucciones de tarea dentro del servidor para que cualquier cliente conectado pueda utilizarlos de manera consistente.
# servers/math_server.py
@mcp.prompt()
def math_tutor(difficulty: str = "intermediate") -> str:
return (
f"You are an expert math tutor for {difficulty}-level students. "
"Break every problem into numbered steps..."
)
Los servidores, en conjunto, exponen 19 herramientas, como se muestra en las secciones siguientes.
La perspectiva del cliente
Esto es exactamente lo que sucede al ejecutar python main.py con una consulta. La ruta de solicitud de extremo a extremo se ve así:
You type a query
│
▼
main.py ← entry point, parses args, kicks off async loop
│
▼
client/agent.py ← spawns 3 MCP servers, builds the agent, invokes it
│ │
│ ▼
│ utils/tracker.py ← fires on every LLM call, tool call, and result
│
▼
LangGraph ReAct loop ← think → call tool → observe → repeat
│
▼
servers/{math,text,data}_server.py ← each runs as an isolated subprocess
Paso 1: donde comienza la ejecución
main.py es lo primero que ejecuta Python. Carga las variables de entorno, analiza los argumentos de la línea de comandos, muestra un panel de bienvenida y pasa el control a un ejecutor asíncrono.
async def _run(queries: list) -> None:
from client.agent import run_query # imported here (late) to keep startup fast
for i, q in enumerate(queries):
await run_query(q)
def main() -> None:
...
asyncio.run(_run(queries))
asyncio.run() crea un bucle de eventos nuevo y se bloquea hasta que _run() finalice. La consulta utilizada para la demostración fue:
Generate 8 random numbers between 5 and 50 using seed=42,
then calculate their statistics, and tell me if there are any outliers.
Ejecútelo desde la línea de comandos de la siguiente manera:
python3 main.py --query "Generate 8 random numbers between 5 and 50 using seed=42, \
then calculate their statistics, and tell me if there are any outliers."
Un panel de información estática se imprime luego mediante _print_header():
╭────────────────────────────── 🔌 MCP Example ───────────────────────────────╮
│ Multi-Server MCP Demo │
│ │
│ Three FastMCP servers, each exposing tools + resources + prompts: │
│ ● Math Server — add, subtract, multiply, divide, power, sqrt, │
│ percentage │
│ ● Text Server — count_words, word_frequency, reverse, transform, │
│ extract_emails │
│ ● Data Server — generate_numbers, calculate_statistics, find_outliers, │
│ normalise │
│ │
│ Stack : FastMCP · LangChain · LangGraph · OpenAI · Rich │
│ Track : live Rich panels + JSONL log files under logs/ │
╰──────────────────────────────────────────────────────────────────────────────╯
Paso 2: creación del agente
client/agent.py contiene run_query(query), la función asíncrona que coordina todo el proceso. Comienza creando un rastreador y un archivo de registro.
log_file = str(LOGS_DIR / f"run_{int(time.time())}.jsonl")
tracker = MCPTracker(log_file=log_file)
Antes de que se conecte cualquier servidor, se instancia un MCPTracker y se prepara un archivo JSONL con marca de tiempo en la carpeta logs/. A partir de entonces, cada evento se escribe allí en tiempo real.
A continuación, se imprime la consulta del usuario:
╭──── 💬 USER QUERY ────╮
│ Generate 8 random... │
╰────────────────────────╯
Luego se definen los servidores desde los cuales se generarán:
def _server_config() -> Dict[str, Any]:
silent_env = {**os.environ, "FASTMCP_LOG_LEVEL": "ERROR"}
return {
"math_server": {
"command": sys.executable,
"args": ["servers/math_server.py"],
"transport": "stdio",
"env": silent_env,
},
"text_server": { ... },
"data_server": { ... },
}
Cada entrada describe un servidor MCP que se ejecuta como un subproceso. El command es el intérprete ya en ejecución (sys.executable), args indica el nombre del script del servidor, y transport especifica cómo se comunican el cliente y el servidor; en este caso stdio se refiere a los canales de entrada y salida estándar. El campo env establece el entorno del subproceso, y FASTMCP_LOG_LEVEL=ERROR suprime el mensaje de inicio de FastMCP.
El transporte stdio es el más simple en MCP: el cliente escribe mensajes JSON-RPC en stdin del servidor y lee las respuestas desde stdout, por lo que no se abre ningún puerto de red.
Después de eso, el cliente se conecta a cada servidor y descubre las herramientas disponibles:
client = MultiServerMCPClient(_server_config())
tools = await client.get_tools()
MultiServerMCPClient, de langchain-mcp-adapters, realiza lo siguiente para cada entrada de servidor al mismo tiempo: crea un proceso hijo, envía la señal de inicio MCP initialize a través de stdio, envía una solicitud tools/list, recibe la lista de esquemas de herramientas y envuelve cada esquema en un objeto Tool de LangChain.
Cuando await client.get_tools() finaliza, el resultado es una lista simple con 19 objetos StructuredTool: siete del servidor de matemáticas, siete del de texto y cinco del de datos. Esa lista representa el conjunto completo de acciones disponibles para el modelo.
Connected to 3 servers (math_server, text_server, data_server) with 19 tools: add, subtract, multiply,
divide, power, square_root, calculate_percentage, count_words, word_frequency, reverse_text,
transform_case, find_and_replace, extract_emails, count_vowels_consonants, generate_numbers,
calculate_statistics, find_outliers, sort_values, normalize_values
Luego se crean el modelo de lenguaje y el agente:
model = ChatOpenAI(model=model_name, temperature=0)
agent = create_react_agent(model, tools)
El create_react_agent de LangGraph crea un grafo de estado compilado con esta estructura:
START
│
▼
[call_model] ─── no tool call ──▶ END
│
tool call requested
│
▼
[call_tools]
│
▼
[call_model] (loop again with tool result in context)
Este es el patrón ReAct, razonamiento más acción. El modelo razona sobre el siguiente paso, actúa llamando a una herramienta, observa el resultado y lo repite hasta tener suficiente información para responder.
Finalmente se invoca al agente:
config = {"callbacks": [tracker]}
result = await agent.ainvoke({"messages": [("human", query)]}, config=config)
La entrada "callbacks": [tracker] se integra en el sistema de callbacks de LangChain. Cada vez que el framework realiza una acción importante, como iniciar o finalizar una llamada a un LLM o a una herramienta, llama al método correspondiente en tracker. Así es como el tracker puede observar todo sin estar dentro de ninguna lógica específica.
Paso 3: verlo en tiempo real
MCPTracker extiende BaseCallbackHandler de LangChain. Sus métodos nunca se llaman directamente, ya que LangChain los ejecuta en los momentos adecuados.
agent.ainvoke() called
│
├─▶ on_chain_start() "▶ AGENT STARTED" panel
│
├─▶ on_chat_model_start() "🤖 LLM CALL #1" panel (timer starts)
├─▶ on_llm_end() "LLM responded ⏱ 1.23s → will call: add, multiply"
│
├─▶ on_tool_start() "🔧 TOOL CALL #1" panel (timer starts)
├─▶ on_tool_end() "✓ TOOL RESULT ⏱ 0.01s" panel
│
├─▶ on_tool_start() (second tool, if any)
├─▶ on_tool_end()
│
├─▶ on_chat_model_start() "🤖 LLM CALL #2" (LLM synthesises final answer)
├─▶ on_llm_end() no tools this time → loop ends
│
└─▶ agent.ainvoke() returns
Cada vez que se dispara on_tool_start, el rastreador determina qué servidor posee la herramienta y asigna un color correspondiente. El único propósito es la legibilidad.
TOOL_SERVER_MAP = {
"add": "math_server",
"count_words": "text_server",
"generate_numbers": "data_server",
...
}
SERVER_COLORS = {
"math_server": "cyan",
"text_server": "green",
"data_server": "yellow",
}
Cada evento se convierte en una línea de JSON en logs/run_<timestamp>.jsonl. El archivo se abre en modo de apilamiento y se escribe de inmediato, por lo que ejecutar tail -f logs/run_*.jsonl en otra terminal muestra los eventos en bruto desplazándose a medida que el agente funciona. Después de que agent.ainvoke() devuelva un resultado, client/agent.py llama manualmente a print_summary(), el cual informa sobre el número total de llamadas al LLM, las llamadas a herramientas y el tiempo transcurrido durante toda la ejecución.
El primer panel que aparece corresponde a la llamada número 1 al LLM, con un único mensaje:
── 🤖 LLM CALL #1 model=gpt-5-mini messages=1 ──╮
│ Role Content preview │
│ Human Generate 8 random numbers between 5 and 50… │
╰──────────────────────────────────────────────────────╯
El grafo ReAct acaba de iniciarse. El modelo recibe el prompt del sistema, inyectado por LangGraph junto con la lista de herramientas y sus esquemas, y ese único mensaje humano, por lo que messages=1.
LLM responded ⏱ 5.35s → will call: generate_numbers
El rastreador inspeccionó la respuesta bruta del modelo. En lugar de prosa, el modelo respondió con una solicitud estructurada para llamar a una herramienta:
{
"name": "generate_numbers",
"arguments": {"count": 8, "min_val": 5, "max_val": 50, "seed": 42}
}
Dentro de response.generations[0][0].message.tool_calls el rastreador detectó la solicitud e imprimió su nombre. Los 5.35 segundos corresponden simplemente al tiempo de ida y vuelta a la API de OpenAI. LangGraph lee esa decisión y pasa al nodo call_tools, lo que genera la primera llamada a herramienta:
╭── 🔧 TOOL CALL #1 ──────────────────╮
│ Tool : generate_numbers │
│ Server: data_server │
│ Args : │
│ {'count': 8, 'min_val': 5, │
│ 'max_val': 50, 'seed': 42} │
╰───────────────────────────────────────╯
Desde el nombre de la herramienta generate_numbers, el rastreador consultó TOOL_SERVER_MAP, que se resuelve en data_server, y pintó el panel de amarillo porque SERVER_COLORS["data_server"] es "yellow". En este momento exacto, LangChain envía un mensaje JSON-RPC tools/call a través del tubo stdio al proceso hijo data_server:
{"method": "tools/call", "params": {"name": "generate_numbers",
"arguments": {"count": 8, "min_val": 5, "max_val": 50, "seed": 42}}}
El proceso lo recibe, ejecuta la función de Python y escribe el resultado de vuelta en su stdout.
╭── ✓ TOOL RESULT ⏱ 0.63s ────────────────────────────╮
│ [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91] │
╰──────────────────────────────────────────────────────────╯
Ejecutó este código exacto:
random.seed(42)
return [round(random.uniform(5, 50), 2) for _ in range(8)]
# → [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]
Los 0.63 segundos abarcan el tiempo desde el envío de la solicitud hasta la recepción de la respuesta a través del canal, incluyendo la sobrecarga por la planificación de procesos en Python. LangGraph agrega el resultado a la lista de mensajes del agente como un ToolMessage, de modo que la lista ahora contiene tres elementos: humano, IA (la decisión de llamar a la herramienta) y herramienta (el resultado).
Luego sigue la llamada número 2 al LLM, con tres mensajes:
╭── 🤖 LLM CALL #2 model=gpt-5-mini messages=3 ──╮
│ Role Content preview │
│ Human Generate 8 random numbers… │
│ AI (the tool-call decision) │
│ Tool [33.77, 6.13, 17.38, ...] │
╰──────────────────────────────────────────────────────╯
Se vuelve a llamar al modelo con toda la historia acumulada hasta el momento. Él ve la pregunta original, su propia decisión anterior de llamar a generate_numbers, y los números que se obtuvieron. Su razonamiento es más o menos el siguiente: ya se tienen los números y la pregunta también solicitaba estadísticas, por lo que se debería ejecutar calculate_statistics con ellos. Eso genera la llamada al herramienta número 2 y su resultado:
Tool : calculate_statistics
Server: data_server
Args : {'numbers': [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]}
Result: {"count":8, "min":6.13, "max":45.15, "mean":24.9962,
"median":25.575, "std_dev":14.8181, "variance":219.5755,
"range":39.02, "q1":15.04, "q3":38.14}
El modelo no recordó nada aquí. Tomó los valores, palabra por palabra, del anterior ToolMessage en su ventana de contexto y los incluyó como argumentos de la herramienta siguiente. Así es como se ve la cadena de operaciones en un bucle ReAct: lo que genera una herramienta se convierte en contexto que la siguiente llamada al modelo puede leer y reutilizar.
En la llamada 3 del LLM hay cinco mensajes, y el modelo llama a find_outliers:
Tool : find_outliers
Server: data_server
Args : {'numbers': [...], 'threshold': 2}
Result: {"outliers": [], "outlier_count": 0,
"total_checked": 8, "mean": 24.9962, "std_dev": 14.8181}
La función find_outliers calcula la puntuación z de cada valor (z = (x − mean) / std_dev) y verifica si alguno supera el umbral de 2. Ninguno lo hace, por lo que outliers es una lista vacía.
El número de llamada del LLM 4 muestra siete mensajes:
╭── 🤖 LLM CALL #4 messages=7 ──╮
│ Human / AI / Tool │
│ AI / Tool │
│ AI / Tool │
╰───────────────────────────────────╯
LLM responded ⏱ 30.25s
La falta del sufijo “will call” indica que el modelo generó texto ordinario y no una solicitud de herramienta, lo que pone fin al bucle ReAct. La llamada tardó 30 segundos, ya que el contexto era extenso (siete mensajes, incluidos resultados en JSON sin procesar) y el modelo realizó una síntesis larga y detallada, calculando manualmente un valor z para cada dato. LangGraph no encuentra ninguna llamada a herramientas en la respuesta y dirige el flujo a END, que muestra la respuesta final:
╭── ✅ FINAL ANSWER ───────────────────────────────╮
│ Random numbers: [33.77, 6.13, 17.38, ...] │
│ Mean: 24.9962 / Median: 25.575 / Std Dev: 14.8181│
│ Outliers: none (all |z| < 2) │
╰───────────────────────────────────────────────────╯
Luego aparece el resumen de la carrera:
╭─────────────────────────────────────────────────────╮
│ LLM Calls 4 │
│ Tool Calls 3 │
│ Total Time 42.25s │
│ Log File logs/run_1776864980.jsonl │
╰─────────────────────────────────────────────────────╯
La secuencia completa de mensajes
Estos son todos los elementos de la lista de mensajes del agente cuando agent.ainvoke() devolvió:
1 HumanMessage "Generate 8 random numbers…"
2 AIMessage [tool_call: generate_numbers({count:8, min:5, max:50, seed:42})]
3 ToolMessage [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]
4 AIMessage [tool_call: calculate_statistics({numbers:[...]})]
5 ToolMessage {count:8, mean:24.9962, std_dev:14.8181, ...}
6 AIMessage [tool_call: find_outliers({numbers:[...], threshold:2})]
7 ToolMessage {outliers:[], outlier_count:0, ...}
8 AIMessage "Here are the results. Random numbers: …" ← final answer
Cada llamada al LLM recibe todo lo acumulado hasta el momento, por lo que el valor de messages en los paneles de seguimiento aumenta en 1, 3, 5, 7.
El registro JSONL
Todos los eventos anteriores también se registraron en logs/run_x.jsonl a medida que ocurrían, con un objeto JSON por línea:
{"timestamp": "...", "event": "agent_start", "data": {"runnable": "LangGraph", "run_id": "..."}}
{"timestamp": "...", "event": "llm_call", "data": {"call_number": 1, "model": "gpt-5-mini", "messages": 1}}
{"timestamp": "...", "event": "llm_end", "data": {"elapsed": "5.35s", "tool_calls_requested": ["generate_numbers"]}}
{"timestamp": "...", "event": "tool_start", "data": {"call_number": 1, "tool": "generate_numbers", "server": "data_server", "args": "..."}}
{"timestamp": "...", "event": "tool_end", "data": {"elapsed": "0.63s", "output_preview": "[33.77, 6.13, ...]"}}
{"timestamp": "...", "event": "llm_call", "data": {"call_number": 2, "model": "gpt-5-mini", "messages": 3}}
...
{"timestamp": "...", "event": "run_summary", "data": {"llm_calls": 4, "tool_calls": 3, "total_elapsed": "42.25s"}}
Por qué es importante
El verdadero valor de MCP radica en la distribución. Antes de que existiera un estándar, cualquier equipo que quisiera superar las capacidades de un LLM tenía que crear su propia capa de integración, y todo ese trabajo no se podía transferir a otros modelos o frameworks. Ahora, un servidor se escribe una sola vez y sirve a cualquier cliente compatible. Un equipo de bases de datos podría publicar un servidor de solo lectura para su esquema, un equipo de DevOps podría exponer herramientas de despliegue, y una plataforma de datos podría ofrecer funciones de consulta y análisis. Cualquier agente puede conectarse a todos ellos, y los equipos nunca necesitan ponerse de acuerdo sobre los detalles de implementación.
Leer más
- Reconstruyendo un agente al estilo Claude Code con LangChain Deep Agents — Cómo funciona el mecanismo de un agente de programación, desde el bucle principal hasta las herramientas, la planificación, la memoria, los subagentes y las aprobaciones en entorno aislado, reconstruido paso a paso con deepagents.
- Diez servidores MCP que vale la pena instalar primero, en orden de prioridad para desarrolladores — Un conjunto inicial clasificado de servidores MCP para asistentes de programación basados en IA, desde Context7 y GitHub hasta Postgres y sistemas de memoria, con configuraciones de instalación y advertencias sobre permisos.