Módulo 2: Arquitectura Host-Client-Server
Flujo Completo Request-Response + Mini-Proyecto
Flujo Completo Request-Response + Mini-Proyecto
Descripción de la cápsula
En las 3 cápsulas anteriores aprendiste cada capa por separado: el Host orquesta, el Client comunica, el Server provee. Ahora vas a unir todo. En esta cápsula vas a trazar requests completos desde que escribes algo en Claude Code hasta que recibes la respuesta, pasando por cada capa con los mensajes JSON-RPC reales que viajan entre ellas.
Trazar flujos completos es la habilidad más práctica de este módulo. Cuando construyas MCP servers en los módulos 4-6, cada bug tendrá una ubicación en este flujo. Cuando algo no funcione, podrás decir "el problema está entre el Client y el Server en la fase de tools/call" en vez de "no sé por qué no funciona." Y cuando diseñes tu server del proyecto integrador (módulo 8), sabrás exactamente qué espera cada capa de las demás.
Al final de esta cápsula completarás el mini-proyecto del módulo: diagramar la arquitectura Host-Client-Server de tu setup actual de Claude Code.
Flujo 1: El request más simple
Escenario: "¿Qué archivos hay en mi proyecto?"
Empezamos con el flujo más básico — un usuario hace una pregunta que requiere un solo tool de un solo server.
FLUJO COMPLETO — Request simple
Usuario → Claude Code:
"¿Qué archivos hay en mi proyecto?"
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ① USUARIO │
│ "¿Qué archivos hay en mi proyecto?" │
│ │ │
│ ▼ │
│ ② HOST (Claude Code) │
│ Claude (modelo) analiza la petición: │
│ → Necesita listar archivos del filesystem │
│ → Tiene el tool "list_directory" disponible │
│ → Decide usar: filesystem.list_directory │
│ │ │
│ ▼ │
│ ③ CLIENT (MCP Client del Filesystem Server) │
│ Envía JSON-RPC: │
│ { "method": "tools/call", │
│ "params": { "name": "list_directory", │
│ "arguments": { "path": "/Users/dev/project" } │
│ }, "id": 5 } │
│ │ │
│ ▼ │
│ ④ SERVER (Filesystem MCP Server) │
│ Recibe request → Ejecuta fs.readdir("/Users/dev/project") │
│ Resultado: ["src/", "package.json", "README.md", "test/"] │
│ │ │
│ ▼ │
│ ⑤ SERVER responde al CLIENT │
│ { "result": { "content": [{ "type": "text", │
│ "text": "src/\npackage.json\nREADME.md\ntest/" }] }, │
│ "id": 5 } │
│ │ │
│ ▼ │
│ ⑥ CLIENT entrega al HOST │
│ Pasa el resultado al Host │
│ │ │
│ ▼ │
│ ⑦ HOST presenta al USUARIO │
│ "Tu proyecto tiene estos archivos: │
│ 📁 src/ │
│ 📄 package.json │
│ 📄 README.md │
│ 📁 test/" │
│ │
└─────────────────────────────────────────────────────────────────┘
Los 7 pasos en detalle
| Paso | Quién | Hace qué | Dato que viaja |
|---|---|---|---|
| ① | Usuario | Escribe petición en terminal | Texto natural |
| ② | Host | Claude analiza y decide qué tool usar | Decisión interna |
| ③ | Client | Envía request JSON-RPC al Server | JSON-RPC request |
| ④ | Server | Ejecuta la operación real | Operación de filesystem |
| ⑤ | Server | Retorna resultado al Client | JSON-RPC response |
| ⑥ | Client | Pasa resultado al Host | Datos internos |
| ⑦ | Host | Formatea y presenta al usuario | Texto formateado |
Tiempo total: Milisegundos. El paso más lento es ④ (la operación real — en este caso, leer el filesystem).
Flujo 2: Request con múltiples Servers
Escenario: "Lee mi README y crea un issue en GitHub con un resumen"
Este flujo involucra 2 MCP Servers en secuencia.
FLUJO COMPLETO — Request multi-server
Usuario: "Lee mi README.md y crea un issue en GitHub con un resumen"
① USUARIO → petición
② HOST analiza:
→ Paso A: Necesita leer README.md → Filesystem Server
→ Paso B: Necesita crear issue → GitHub Server
→ Orquesta en secuencia (B depende de A)
③-A CLIENT 1 → Filesystem Server:
{ "method": "tools/call",
"params": { "name": "read_file",
"arguments": { "path": "README.md" } },
"id": 10 }
④-A Filesystem Server ejecuta → lee README.md
⑤-A Filesystem Server responde:
{ "result": { "content": [{ "type": "text",
"text": "# Mi Proyecto\nUna app de gestión..." }] },
"id": 10 }
⑥-A CLIENT 1 → HOST: entrega contenido del README
② HOST procesa el contenido:
→ Claude genera un resumen del README
→ Prepara los argumentos para crear el issue
③-B CLIENT 2 → GitHub Server:
{ "method": "tools/call",
"params": { "name": "create_issue",
"arguments": {
"repo": "my-user/my-project",
"title": "Resumen del README",
"body": "## Resumen\nEsta app de gestión..."
} },
"id": 11 }
④-B GitHub Server ejecuta → POST https://api.github.com/repos/.../issues
⑤-B GitHub Server responde:
{ "result": { "content": [{ "type": "text",
"text": "Issue #42 created successfully" }] },
"id": 11 }
⑥-B CLIENT 2 → HOST: entrega confirmación
⑦ HOST → USUARIO:
"Leí tu README.md y creé el issue #42 en GitHub con un resumen
del contenido. Puedes verlo en github.com/my-user/my-project/issues/42"
Diagrama de secuencia temporal
Tiempo →
Usuario Host Client1 FileSrv Client2 GitHubSrv
│ │ │ │ │ │
│─"Lee │ │ │ │ │
│ README │ │ │ │ │
│ y crea │ │ │ │ │
│ issue"─▶│ │ │ │ │
│ │──tools/call─▶│ │ │ │
│ │ read_file │──request──▶│ │ │
│ │ │ │──lee fs── │ │
│ │ │ │ │ │ │
│ │ │◀─response──│◀───────── │ │
│ │◀─resultado───│ │ │ │
│ │ │ │
│ │──genera resumen (Claude)── │ │
│ │ │ │
│ │──tools/call────────────────────────────▶│ │
│ │ create_issue │──request──▶│
│ │ │ │──POST─▶
│ │ │ │ GitHub
│ │ │ │ API
│ │ │ │◀─200──
│ │ │◀─response──│
│ │◀─resultado──────────────────────────────│ │
│ │ │ │
│◀─"Creé │ │ │
│ issue │ │ │
│ #42"───│ │ │
Observaciones clave:
- El Host orquesta la secuencia — Client1 y Client2 no se conocen
- Client1 y Client2 son independientes — operan con Servers diferentes
- El Host (Claude) procesa entre los dos calls: genera el resumen
- Los
idde JSON-RPC son diferentes para cada request (10, 11)
Flujo 3: El lifecycle completo (desde el arranque)
Escenario: Claude Code arranca, conecta con un server, y atiende una petición
Este flujo muestra todo — desde que Claude Code inicia hasta que responde al usuario.
LIFECYCLE COMPLETO
═══════════════════════════════════════════
FASE 1: STARTUP (Claude Code arranca)
═══════════════════════════════════════════
Host lee configuración:
├── ~/.claude/settings.json
│ { "mcpServers": { "filesystem": { "command": "npx", "args": [...] } } }
│
Host lanza proceso:
├── $ npx -y @modelcontextprotocol/server-filesystem /Users/dev/project
│ └── Proceso iniciado (PID: 12345)
│
Host crea MCP Client para este Server
═══════════════════════════════════════════
FASE 2: INITIALIZE (handshake)
═══════════════════════════════════════════
Client → Server (via stdin):
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": { "roots": { "listChanged": true } },
"clientInfo": { "name": "claude-code", "version": "1.0.0" }
}
}
Server → Client (via stdout):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-03-26",
"capabilities": { "tools": { "listChanged": true } },
"serverInfo": { "name": "filesystem-server", "version": "0.5.0" }
}
}
Client → Server (notification):
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
═══════════════════════════════════════════
FASE 3: DISCOVER (descubrir capabilities)
═══════════════════════════════════════════
Client → Server:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
Server → Client:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "read_file",
"description": "Read the complete contents of a file",
"inputSchema": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Path to file" }
},
"required": ["path"]
}
},
{
"name": "list_directory",
"description": "List directory contents",
"inputSchema": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Path to directory" }
},
"required": ["path"]
}
}
]
}
}
Host registra: "filesystem server tiene 2 tools: read_file, list_directory"
Estado: filesystem ✅ connected
═══════════════════════════════════════════
FASE 4: READY (esperando peticiones del usuario)
═══════════════════════════════════════════
Claude Code muestra prompt al usuario: >
═══════════════════════════════════════════
FASE 5: OPERATION (usuario hace petición)
═══════════════════════════════════════════
Usuario escribe: "Lee el archivo package.json"
Host (Claude) decide: usar filesystem.read_file
Client → Server:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": { "path": "/Users/dev/project/package.json" }
}
}
Server ejecuta: fs.readFile("/Users/dev/project/package.json")
Server → Client:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{
"type": "text",
"text": "{\n \"name\": \"my-app\",\n \"version\": \"1.0.0\"\n}"
}],
"isError": false
}
}
Host presenta al usuario:
"El archivo package.json contiene:
nombre: my-app
versión: 1.0.0"
═══════════════════════════════════════════
FASE 6: SHUTDOWN (usuario cierra sesión)
═══════════════════════════════════════════
Usuario: Ctrl+C
Host cierra conexión con Client
Client cierra comunicación con Server
Proceso del Server termina (PID 12345 killed)
Flujo 4: Manejo de errores
Escenario: El usuario pide leer un archivo que no existe
FLUJO CON ERROR
Usuario: "Lee el archivo config.secret.json"
② Host decide: usar filesystem.read_file
③ Client → Server:
{ "method": "tools/call",
"params": { "name": "read_file",
"arguments": { "path": "config.secret.json" } },
"id": 6 }
④ Server ejecuta: fs.readFile("config.secret.json")
→ ERROR: ENOENT - file not found
⑤ Server → Client:
{
"id": 6,
"result": {
"content": [{
"type": "text",
"text": "Error: File not found: config.secret.json\nThe file does not exist in /Users/dev/project/"
}],
"isError": true
}
}
⑥ Client → Host: entrega error
⑦ Host → Usuario:
"No pude leer config.secret.json — el archivo no existe en tu proyecto.
¿Querías decir config.json o settings.json?"
Nota: El Host (Claude) no solo presenta el error — lo interpreta y ofrece alternativas. Esa capacidad de manejar errores de forma inteligente es parte del valor del Host.
Comparación: dónde buscar según el síntoma
Cuando algo falla, el síntoma te dice en qué capa buscar:
Mapa de diagnóstico:
SÍNTOMA → CAPA → CAUSA PROBABLE
─────────────────────────────────────────────────────────────
Server no aparece en /mcp → Host → Configuración incorrecta
Server aparece como "disconnected" → Host/Client → Proceso no arranca
Server conectado pero sin tools → Client/Server → Initialize falla
Tool existe pero no se usa → Host → Claude no lo selecciona
Tool se invoca pero error → Server → Lógica del handler
Respuesta vacía o formato raro → Server → Response mal formateado
Timeout en la respuesta → Server → Operación tarda mucho
Todo funciona pero resultado malo → Server → Lógica incorrecta
Flowchart de debugging
¿El server aparece en /mcp?
├── NO → Verifica settings.json y el comando
│ $ claude mcp list
│ ¿El comando funciona manualmente?
│ $ npx -y @modelcontextprotocol/server-xxx
│
├── Aparece como "disconnected"
│ → El proceso crashea al iniciar
│ → Verifica dependencias y variables de entorno
│ → Ejecuta el comando manualmente para ver errores
│
└── SÍ, "connected" con tools
├── ¿Claude usa el tool correcto?
│ ├── NO → Sé más específico en tu petición
│ └── SÍ → ¿El resultado es correcto?
│ ├── NO → Problema en el handler del Server
│ └── Error → Revisa el mensaje de error
│ ├── isError: true → Error de operación (tu código)
│ └── error JSON-RPC → Error de protocolo
Anatomía de los datos en cada capa
Qué formato tienen los datos en cada punto del flujo
PUNTO EN EL FLUJO FORMATO DE DATOS
──────────────────────────────────────────────
① Usuario → Host Lenguaje natural
"Lee el archivo README.md"
② Host (decisión) Estructura interna del modelo
{ tool: "read_file", server: "filesystem",
args: { path: "README.md" } }
③ Client → Server JSON-RPC 2.0 sobre stdio
{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"read_file",
"arguments":{"path":"README.md"}}}
④ Server (ejecución) Operación nativa
fs.readFileSync("README.md", "utf-8")
⑤ Server → Client JSON-RPC 2.0 sobre stdio
{"jsonrpc":"2.0","id":1,"result":
{"content":[{"type":"text",
"text":"# README content..."}]}}
⑥ Client → Host Datos parseados internamente
{ content: "# README content..." }
⑦ Host → Usuario Lenguaje natural formateado
"El README contiene..."
Patrón: Los datos se transforman en cada capa — de lenguaje natural a JSON-RPC, de JSON-RPC a operación nativa, y de vuelta.
Flujo con múltiples Clients simultáneos
Cómo el Host gestiona conexiones paralelas
Cuando Claude Code tiene 3 MCP servers configurados, el lifecycle de arranque es paralelo:
Claude Code startup (paralelo):
Tiempo →
────────────────────────────────────────────
Host ──lanza proceso 1──▶ Filesystem Server
──lanza proceso 2──▶ GitHub Server
──lanza proceso 3──▶ Memory Server
Client1 ──initialize──▶ Filesystem ──response──▶ Client1
Client2 ──initialize──▶ GitHub ──response──▶ Client2
Client3 ──initialize──▶ Memory ──response──▶ Client3
Client1 ──tools/list──▶ Filesystem ──response──▶ Client1
Client2 ──tools/list──▶ GitHub ──response──▶ Client2
Client3 ──tools/list──▶ Memory ──response──▶ Client3
Host registra todas las capabilities:
├── filesystem: read_file, write_file, list_directory, ...
├── github: search_repos, create_issue, list_prs, ...
└── memory: store, retrieve, search, ...
Estado: READY
Todos los servers: connected ✅
Cuando un server falla, los demás no se ven afectados:
Startup con un server que falla:
Client1 ──initialize──▶ Filesystem ──response──▶ ✅
Client2 ──initialize──▶ GitHub ──TIMEOUT── ❌ (token inválido)
Client3 ──initialize──▶ Memory ──response──▶ ✅
Host registra:
├── filesystem: connected ✅
├── github: disconnected ❌
└── memory: connected ✅
Claude Code funciona con filesystem y memory.
Operations de GitHub no están disponibles.
Troubleshooting
"El flujo se interrumpe en la fase de initialize"
Causa: El Server no responde al mensaje initialize del Client, o responde con un formato incorrecto.
Diagnóstico:
# Simula el initialize manualmente
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | npx -y @modelcontextprotocol/server-filesystem /tmp
Si no obtienes una respuesta JSON válida, el Server tiene un problema de inicialización.
"El Host no orquesta bien entre servers"
Causa: Claude (el modelo) tiene dificultad decidiendo qué server usar cuando las capabilities se solapan.
Solución: Usa peticiones más específicas:
- ❌ "Busca información" (ambiguo: ¿filesystem? ¿GitHub? ¿memory?)
- ✅ "Busca archivos .py en mi proyecto" (claramente filesystem)
- ✅ "Busca issues abiertos en mi repo de GitHub" (claramente GitHub)
"La respuesta del Server llega pero el Host no la muestra bien"
Causa: El Server retorna datos en un formato que el Host no puede presentar limpiamente.
Solución: Asegura que tus respuestas sean texto legible:
// ✅ Buena respuesta (legible)
{ "content": [{ "type": "text", "text": "Encontré 3 archivos:\n- main.py\n- utils.py\n- test.py" }] }
// ❌ Mala respuesta (JSON crudo difícil de leer)
{ "content": [{ "type": "text", "text": "[{\"name\":\"main.py\"},{\"name\":\"utils.py\"},{\"name\":\"test.py\"}]" }] }
Ejercicios
Ejercicio 1: Trazar un flujo simple (Fácil)
Traza el flujo completo para esta petición: "Cuenta cuántas líneas tiene el archivo main.py". Identifica cada paso (①-⑦), qué capa actúa, y qué datos viajan.
Ver solución
① Usuario → Host:
"Cuenta cuántas líneas tiene el archivo main.py"
② Host (Claude) analiza:
→ Necesita leer el archivo para contar líneas
→ Tool: filesystem.read_file
→ Server: Filesystem
③ Client → Server (JSON-RPC):
{ "jsonrpc": "2.0", "id": 7,
"method": "tools/call",
"params": { "name": "read_file",
"arguments": { "path": "main.py" } } }
④ Server ejecuta:
→ fs.readFile("main.py") → contenido del archivo
⑤ Server → Client (JSON-RPC):
{ "jsonrpc": "2.0", "id": 7,
"result": { "content": [{ "type": "text",
"text": "import os\nimport sys\n\ndef main():\n print('hello')\n\nif __name__ == '__main__':\n main()" }] } }
⑥ Client → Host:
Entrega el contenido del archivo
⑦ Host → Usuario:
"El archivo main.py tiene 8 líneas."
(Claude cuenta las líneas del contenido recibido)
Nota: El Server no cuenta líneas — retorna el contenido. Es el Host (Claude) quien cuenta las líneas del texto recibido.
Ejercicio 2: Trazar un flujo con error (Medio)
Traza el flujo cuando el usuario pide "Ejecuta la query SELECT * FROM users" pero la database no está disponible (connection refused).
Ver solución
① Usuario → Host:
"Ejecuta la query SELECT * FROM users"
② Host decide:
→ Tool: postgres.query
→ Server: PostgreSQL
③ Client → Server:
{ "jsonrpc": "2.0", "id": 15,
"method": "tools/call",
"params": { "name": "query",
"arguments": { "sql": "SELECT * FROM users" } } }
④ Server intenta ejecutar:
→ connection.query("SELECT * FROM users")
→ ERROR: Connection refused at localhost:5432
⑤ Server → Client:
{ "jsonrpc": "2.0", "id": 15,
"result": {
"content": [{ "type": "text",
"text": "Error: Could not connect to PostgreSQL at localhost:5432. Connection refused. Ensure PostgreSQL is running." }],
"isError": true
} }
⑥ Client → Host:
Entrega el error
⑦ Host → Usuario:
"No pude ejecutar la query porque PostgreSQL no está disponible
en localhost:5432. Verifica que el servicio esté corriendo:
sudo systemctl start postgresql
o si usas Docker:
docker start postgres-container"
Puntos clave:
- El Server maneja el error (no crashea) y retorna
isError: true - El Host (Claude) interpreta el error y sugiere soluciones
- El flujo completo funciona — solo el resultado es un error
Ejercicio 3: Trazar un flujo multi-server (Medio)
Traza el flujo para: "Busca los archivos .test.ts en mi proyecto y envía la lista al canal #testing de Slack". Asume Filesystem server y Slack server configurados.
Ver solución
① Usuario → Host:
"Busca los archivos .test.ts y envía la lista al canal #testing de Slack"
② Host analiza:
→ Paso A: buscar archivos → Filesystem server
→ Paso B: enviar a Slack → Slack server
→ Secuencial: B depende del resultado de A
③-A Client 1 → Filesystem Server:
{ "jsonrpc": "2.0", "id": 20,
"method": "tools/call",
"params": { "name": "search_files",
"arguments": { "path": "/project", "pattern": "*.test.ts" } } }
④-A Server ejecuta búsqueda en filesystem
⑤-A Filesystem Server → Client 1:
{ "jsonrpc": "2.0", "id": 20,
"result": { "content": [{ "type": "text",
"text": "Found 4 files:\n- src/auth.test.ts\n- src/api.test.ts\n- src/utils.test.ts\n- src/db.test.ts" }] } }
⑥-A Client 1 → Host: entrega lista de archivos
② Host procesa:
→ Claude formatea la lista para Slack
③-B Client 2 → Slack Server:
{ "jsonrpc": "2.0", "id": 21,
"method": "tools/call",
"params": { "name": "send_message",
"arguments": {
"channel": "#testing",
"text": "📋 Test files en el proyecto:\n• src/auth.test.ts\n• src/api.test.ts\n• src/utils.test.ts\n• src/db.test.ts"
} } }
④-B Slack Server ejecuta: POST Slack API
⑤-B Slack Server → Client 2:
{ "jsonrpc": "2.0", "id": 21,
"result": { "content": [{ "type": "text",
"text": "Message sent to #testing successfully" }] } }
⑥-B Client 2 → Host: confirma envío
⑦ Host → Usuario:
"Encontré 4 archivos de test y envié la lista al canal #testing de Slack:
- src/auth.test.ts
- src/api.test.ts
- src/utils.test.ts
- src/db.test.ts"
Ejercicio 4: Diagnosticar por síntomas (Difícil)
Para cada síntoma, identifica la capa del problema (Host, Client, Server) y la causa probable:
- Claude Code muestra "0 MCP servers connected" al ejecutar
/mcp - El tool
queryaparece en la lista pero Claude nunca lo usa - El tool se invoca pero retorna
{ "content": [] }(array vacío) - El Server responde correctamente pero Claude Code muestra "Error parsing response"
Ver solución
-
Capa: Host — No hay servers configurados, o todos los procesos fallan al arrancar.
- Verificar:
claude mcp listycat ~/.claude/settings.json - Causa: settings.json vacío, comandos incorrectos, o node/npx no instalados
- Verificar:
-
Capa: Host — Claude (el modelo) no considera el tool relevante para la petición del usuario.
- Verificar: La petición es lo suficientemente específica
- Causa: La descripción del tool no comunica bien su propósito, o la petición del usuario es ambigua
- Fix: Ser más específico: "Ejecuta una query SQL en la database" en vez de "busca datos"
-
Capa: Server — El handler del tool retorna un array vacío en vez de contenido.
- Verificar: El handler del Server tiene un bug en la construcción del response
- Causa: La operación se ejecuta pero el resultado no se incluye en
content - Fix: Asegurar que el handler siempre retorne al menos un item en
content
-
Capa: Client — El Server retorna JSON válido pero con formato MCP incorrecto.
- Verificar: El response del Server cumple con la spec de MCP
- Causa: Falta el campo
content, ocontentno es un array, o eltypeno es válido - Fix: Validar que el response siga el schema
{ content: [{ type: "text", text: "..." }] }
Mini-Proyecto: Diagramar tu Setup de Claude Code
Objetivo
Crear un diagrama completo de la arquitectura Host-Client-Server de tu setup actual de Claude Code, incluyendo todos los MCP servers que tengas configurados.
Instrucciones
Paso 1: Inventario de tu setup
Ejecuta estos comandos en tu terminal:
# Ver tus MCP servers configurados
claude mcp list
# Ver el estado de conexión (dentro de una sesión de Claude Code)
/mcp
Documenta cada server: nombre, comando, scope, estado.
Paso 2: Dibuja la arquitectura
Crea un diagrama que muestre:
- El Host (Claude Code) como caja principal
- Un Client por cada Server conectado (dentro del Host)
- Cada Server como caja externa con sus tools listados
- Flechas de comunicación entre Client y Server
- El transport usado (stdio o HTTP)
Formato sugerido:
# Diagrama de Arquitectura MCP — Mi Setup
## Host: Claude Code
### Conexiones activas
#### Server 1: [nombre]
- **Comando:** [comando de arranque]
- **Transport:** stdio
- **Scope:** user/project/local
- **Estado:** connected/disconnected
- **Tools:**
- [tool1] — [descripción]
- [tool2] — [descripción]
- [tool3] — [descripción]
#### Server 2: [nombre]
[...]
## Diagrama visual
Claude Code (Host) │ ├── Client 1 ──stdio──▶ [Server 1] │ ├── tool_a │ ├── tool_b │ └── tool_c │ ├── Client 2 ──stdio──▶ [Server 2] │ ├── tool_d │ └── tool_e │ └── Client 3 ──stdio──▶ [Server 3] ├── tool_f └── tool_g
Paso 3: Traza un request completo
Elige una petición real que puedas hacer a Claude Code usando uno de tus MCP servers. Ejecuta la petición y traza el flujo completo:
- Qué escribiste (input del usuario)
- Qué Server y tool usó Claude Code
- Qué datos viajaron (puedes observar el tool call en la UI de Claude Code)
- Qué resultado recibiste
Paso 4: Traza un request cross-server (si aplica)
Si tienes 2+ servers, diseña una petición que los use a ambos y traza el flujo.
Paso 5: Reflexión
Responde:
- ¿Qué MCP server agregarías a tu setup y por qué?
- ¿Cómo encajaría en tu diagrama?
- ¿Qué tools necesitaría?
- ¿Podría ser tu proyecto del módulo 8?
Formato de entrega
# Mini-Proyecto Módulo 2: Arquitectura de Mi Setup
## Inventario
[Lista de servers con su configuración]
## Diagrama
[Diagrama visual ASCII]
## Flujo trazado
[Request completo paso a paso]
## Flujo cross-server (opcional)
[Request multi-server paso a paso]
## Reflexión
[Respuestas a las preguntas]
Ver ejemplo completo
# Mini-Proyecto Módulo 2: Arquitectura de Mi Setup
## Inventario
| Server | Comando | Scope | Estado |
|--------|---------|-------|--------|
| filesystem | npx server-filesystem ~/projects | user | connected ✅ |
| memory | npx server-memory | user | connected ✅ |
## Diagrama
Claude Code (Host)
│
├── Client 1 ──stdio──▶ Filesystem Server
│ ├── read_file
│ ├── write_file
│ ├── list_directory
│ ├── search_files
│ └── directory_tree
│
└── Client 2 ──stdio──▶ Memory Server
├── store_memory
├── retrieve_memory
└── search_memory
## Flujo trazado
Petición: "Lee mi archivo package.json"
① Yo → Claude Code: "Lee mi archivo package.json"
② Host: decide usar filesystem.read_file
③ Client 1 → Filesystem Server: tools/call read_file("package.json")
④ Server ejecuta: lee package.json del disco
⑤ Server → Client 1: contenido del archivo
⑥ Client 1 → Host: entrega contenido
⑦ Host → Yo: "Tu package.json contiene: nombre my-app, versión 1.0.0..."
## Flujo cross-server
Petición: "Lee mi README.md y recuerda de qué trata mi proyecto"
Paso A: filesystem.read_file("README.md") → contenido
Paso B: memory.store_memory("proyecto", "App de gestión de tareas...")
Resultado: "Leí tu README y guardé en memoria que tu proyecto es
una app de gestión de tareas con React y Node.js."
## Reflexión
1. Agregaría un GitHub server para gestionar PRs sin salir de Claude Code
2. Sería Client 3 conectado via stdio al GitHub MCP server
3. Necesitaría: list_prs, create_issue, search_repos, get_commit_history
4. Podría ser la base de mi proyecto del módulo 8 si lo conecto con
mi API interna del trabajo
Resumen del módulo completo
Has completado el Módulo 2: Arquitectura Host-Client-Server. Aquí está todo lo que aprendiste:
Cápsula 02 — El Host
- Claude Code como orquestador: gestiona conexiones, descubre capabilities, maneja permisos
- Un Host tiene múltiples Clients, uno por Server
- Scopes de configuración: user, project, local
Cápsula 03 — El Client
- JSON-RPC 2.0 como formato de mensajes: Request, Response, Notification
- Lifecycle: Initialize → Initialized → Operation → Shutdown
- Transports: stdio (local) y HTTP/SSE (remoto)
- Negociación de capabilities durante initialize
Cápsula 04 — El Server
- Tu código: expone capabilities (Tools, Resources, Prompts)
- Input schemas con JSON Schema para validación
- Patrones: API wrapper, database, filesystem, agregación
- Seguridad: validación de inputs, principio de mínimo privilegio
Cápsula 05 — Flujo completo
- 7 pasos del request: usuario → Host → Client → Server → Client → Host → usuario
- Orquestación cross-server: el Host coordina múltiples Servers
- Debugging por capas: cada síntoma apunta a una capa específica
- Los datos se transforman en cada capa
Lo que viene: Módulo 3
En el Módulo 3 (Tres Primitivas — Resources, Tools, Prompts) vas a profundizar en exactamente qué puede exponer un MCP Server:
- Resources: Datos contextuales con URIs, templates, suscripciones
- Tools: Funciones ejecutables con schemas, validación, side effects
- Prompts: Templates reutilizables con parámetros
La transición es directa: ya sabes que el Server provee capabilities al Host via el Client. Ahora vas a ver exactamente qué tipos de capabilities puede exponer y cómo diseñarlas efectivamente.
Recursos adicionales
- MCP Architecture Overview - Vista completa de la arquitectura oficial
- MCP Connection Lifecycle - Detalle del lifecycle de conexión
- JSON-RPC 2.0 Specification - Especificación del protocolo base
- MCP Transports - Documentación de stdio y HTTP/SSE
- MCP Inspector - Visualizar mensajes MCP en tiempo real
- Claude Code MCP Documentation - Configuración y uso de MCP en Claude Code
- MCP Debugging Guide - Guía oficial de debugging
- MCP Server Examples - Repositorio de servers de referencia
Siguiente módulo: Módulo 3: Tres Primitivas — Resources, Tools, Prompts — qué expone un MCP Server y cómo diseñar cada tipo de capability efectivamente.