Skip to main content
Glama
nudge-digital-lab

TiendaTech Support MCP Server

Agente de soporte con servidor MCP propio

Proyecto 1 de una serie de 7 proyectos chicos, cada uno enfocado en una habilidad puntual que aparece hoy en avisos de trabajo para desarrolladores de agentes de IA. Este cubre: construir y consumir un servidor MCP (Model Context Protocol) desde cero.

El problema que resuelve

Una tienda de electrónica ("TiendaTech") necesita un agente de soporte que pueda:

  • Responder preguntas de clientes sobre políticas (devoluciones, garantía, envíos) sin inventar información.

  • Consultar y crear tickets de soporte reales, no simulados.

En vez de meter toda esa lógica adentro del prompt o hardcodeada en el cliente del LLM, ese acceso a datos vive en un servidor MCP separado: un proceso independiente que expone qué información y qué acciones están disponibles, con un contrato bien definido. El agente (el cliente que habla con Claude) no sabe nada de archivos ni de JSON — solo sabe que existe un servidor con ciertos recursos y herramientas.

Esto es exactamente el problema que MCP fue diseñado para resolver: separar "qué puede hacer un agente" de "qué modelo lo está operando", para no tener que reescribir la integración de datos cada vez que cambiás de LLM o de cliente.

Arquitectura

flowchart LR
    subgraph Cliente["src/agent.ts (proceso 1)"]
        CLI[REPL en terminal]
        MCPClient[Cliente MCP]
        Claude[Anthropic SDK]
    end

    subgraph Servidor["src/server.ts (proceso 2, hijo)"]
        MCPServer[Servidor MCP]
        Tools[Tools: search_tickets / get_ticket / create_ticket]
        Resources[Resources: artículos de la KB]
    end

    DB[(data/tickets.json)]
    KB[(data/kb/*.md)]

    CLI --> MCPClient
    MCPClient <-->|stdio JSON-RPC| MCPServer
    MCPServer --> Tools
    MCPServer --> Resources
    Tools <--> DB
    Resources <--> KB
    MCPClient --> Claude
    Claude -->|decide qué tool llamar| MCPClient

Son dos procesos Node separados que se comunican por stdio con el protocolo MCP (JSON-RPC 2.0):

  1. src/server.ts — el servidor MCP. No sabe nada de Claude ni de IA. Solo expone:

    • Resources (kb://politica-devoluciones.md, etc.): los 3 artículos de la base de conocimiento, como contenido de solo lectura pensado para dar contexto.

    • Tools (search_tickets, get_ticket, create_ticket): acciones que leen y escriben sobre data/tickets.json, una base de tickets de soporte.

  2. src/agent.ts — el agente. Levanta el servidor como proceso hijo, se conecta como cliente MCP, y hace de puente entre MCP y la API de Claude:

    • Al arrancar, lee todos los resources y los inyecta en el system prompt como contexto fijo.

    • Traduce la lista de tools del servidor al formato de tool-use de la API de Claude.

    • Corre un loop de conversación: si Claude decide llamar una tool, el agente ejecuta esa llamada contra el servidor MCP real y le devuelve el resultado, hasta que Claude da una respuesta final en texto.

Decisiones técnicas y por qué

  • Resources vs. Tools, a propósito. MCP distingue explícitamente entre datos de contexto (resources, decisión de cuándo leerlos la toma el host/agente) y acciones invocables por el modelo (tools, decisión de cuándo usarlas la toma el LLM). Usar ambos primitivos — y no meter todo como tools — muestra que la separación es intencional, no que "tools es lo único que existe en MCP".

  • Transporte stdio, no HTTP/SSE. Para un servidor MCP local de un solo cliente, stdio es más simple: no hay puertos, no hay CORS, no hay que levantar un server HTTP aparte. El SDK oficial de Anthropic soporta stdio, SSE y Streamable HTTP — stdio es el punto de entrada correcto para entender el protocolo antes de pasar a un despliegue remoto.

  • JSON planos en vez de SQLite/Postgres. El foco del proyecto es demostrar el protocolo MCP (cómo se define un tool, cómo se valida su input, cómo un cliente lo descubre y lo invoca), no la capa de persistencia. Cambiar data/tickets.json por una base real implica tocar únicamente readTickets/writeTickets en server.ts — el contrato MCP hacia el agente no cambia.

  • TypeScript + SDK oficiales. @modelcontextprotocol/sdk (servidor y cliente) y @anthropic-ai/sdk son los paquetes oficiales de Anthropic. Se usa la API de alto nivel McpServer (registerTool/registerResource) en vez de la API de bajo nivel con setRequestHandler, porque valida automáticamente el input contra el schema de Zod y da mensajes de error más claros — importante cuando el que "llena" los argumentos es un LLM y no un humano.

  • Sin frameworks de agentes (LangChain, etc.). El loop de tool-use (llamar al modelo → detectar tool_use → ejecutar → devolver tool_result → repetir) se escribe a mano en ~40 líneas. Para un solo agente con 3 tools, un framework agrega abstracción sin resolver un problema real; y entender ese loop sin magia es la habilidad que se quiere mostrar acá.

Stack

  • Node.js 22 + TypeScript

  • @modelcontextprotocol/sdk — servidor y cliente MCP

  • @anthropic-ai/sdk — Claude (modelo claude-sonnet-4-5)

  • zod — validación de inputs de las tools

  • Sin base de datos externa: data/tickets.json + data/kb/*.md

Cómo correrlo

npm install
cp .env.example .env   # completar ANTHROPIC_API_KEY
npm start               # compila y levanta el agente (que a su vez levanta el servidor MCP)

Ejemplo de conversación:

Vos: hola, tengo un teclado que no me terminó gustando, ¿lo puedo devolver?
Agente: Sí, podés devolverlo dentro de los 30 días de la compra siempre que esté sin uso...

Vos: se me rompió el auricular izquierdo de mis auriculares, ¿tienen algún ticket mío?
  → llamando herramienta MCP: search_tickets({"query":"auricular"})
Agente: Sí, encontré el ticket #1 a nombre de Marcos Videla, sigue abierto...

Si querés inspeccionar el servidor MCP de forma aislada (sin Claude), se puede correr con el MCP Inspector oficial:

npm run build
npx @modelcontextprotocol/inspector node dist/server.js

Estructura

src/
  server.ts     # servidor MCP: resources + tools
  agent.ts      # cliente MCP + integración con Claude + REPL
data/
  kb/*.md       # base de conocimiento (resources)
  tickets.json  # base de tickets (tools)

Qué demuestra este proyecto

  • Entender MCP como protocolo (no solo como "una librería más"): distinción resources/tools, transporte, ciclo de vida de conexión.

  • Diseñar el input schema de una tool con Zod pensando en que quien la va a llamar es un LLM, no un formulario.

  • Integrar el tool-use de la API de Claude con una fuente de tools que no está hardcodeada, sino descubierta dinámicamente en runtime contra un servidor externo.