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

PasoQuiénHace quéDato que viaja
①UsuarioEscribe petición en terminalTexto natural
②HostClaude analiza y decide qué tool usarDecisión interna
③ClientEnvía request JSON-RPC al ServerJSON-RPC request
④ServerEjecuta la operación realOperación de filesystem
⑤ServerRetorna resultado al ClientJSON-RPC response
⑥ClientPasa resultado al HostDatos internos
⑦HostFormatea y presenta al usuarioTexto 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 id de 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:

  1. Claude Code muestra "0 MCP servers connected" al ejecutar /mcp
  2. El tool query aparece en la lista pero Claude nunca lo usa
  3. El tool se invoca pero retorna { "content": [] } (array vacío)
  4. El Server responde correctamente pero Claude Code muestra "Error parsing response"
Ver solución
  1. Capa: Host — No hay servers configurados, o todos los procesos fallan al arrancar.

    • Verificar: claude mcp list y cat ~/.claude/settings.json
    • Causa: settings.json vacío, comandos incorrectos, o node/npx no instalados
  2. 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"
  3. 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
  4. 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, o content no es un array, o el type no 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:

  1. El Host (Claude Code) como caja principal
  2. Un Client por cada Server conectado (dentro del Host)
  3. Cada Server como caja externa con sus tools listados
  4. Flechas de comunicación entre Client y Server
  5. 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:

  1. Qué escribiste (input del usuario)
  2. Qué Server y tool usó Claude Code
  3. Qué datos viajaron (puedes observar el tool call en la UI de Claude Code)
  4. 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:

  1. ¿Qué MCP server agregarías a tu setup y por qué?
  2. ¿Cómo encajaría en tu diagrama?
  3. ¿Qué tools necesitaría?
  4. ¿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

  1. MCP Architecture Overview - Vista completa de la arquitectura oficial
  2. MCP Connection Lifecycle - Detalle del lifecycle de conexión
  3. JSON-RPC 2.0 Specification - Especificación del protocolo base
  4. MCP Transports - Documentación de stdio y HTTP/SSE
  5. MCP Inspector - Visualizar mensajes MCP en tiempo real
  6. Claude Code MCP Documentation - Configuración y uso de MCP en Claude Code
  7. MCP Debugging Guide - Guía oficial de debugging
  8. 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.