Inicio / Inteligencia Artificial / AI-First Full Stack: Construye Apps con IA / MCP: Model Context Protocol

MCP: Model Context Protocol

Protocolo MCP de Anthropic: servidores, clientes, tools, resources, transporte y creación de servidores MCP.

Intermedio
🔒 Solo lectura
📖

Estás en modo lectura

Puedes leer toda la lección, pero para marcar progreso, hacer ejercicios y ganar XP necesitas una cuenta Pro.

Desbloquear por $9/mes

MCP: Model Context Protocol

MCP (Model Context Protocol) es un protocolo abierto creado por Anthropic que estandariza cómo las aplicaciones AI se conectan con fuentes de datos y herramientas externas. Piensa en MCP como el "USB-C de la IA": una interfaz universal para conectar LLMs con el mundo.


¿Por qué MCP?

Antes de MCP, cada integración era custom:

Sin MCP:                        Con MCP:
App1 ──custom──▶ GitHub         App1 ──MCP──▶ MCP Server GitHub
App1 ──custom──▶ Slack          App2 ──MCP──▶ MCP Server GitHub
App2 ──custom──▶ GitHub         App1 ──MCP──▶ MCP Server Slack
App2 ──custom──▶ Slack          App2 ──MCP──▶ MCP Server Slack

N apps × M tools = N×M          N apps × 1 protocolo = N+M
integraciones                   integraciones

Arquitectura MCP

┌─────────────────┐
│   MCP Client     │  (Claude Desktop, Cursor, tu app)
│   (Host App)     │
└────────┬────────┘
         │ MCP Protocol (JSON-RPC sobre stdio/SSE/HTTP)
         │
┌────────┴────────┐
│   MCP Server     │  (proceso separado)
│                  │
│  ┌─ Tools ──────┐│  Funciones que el LLM puede invocar
│  ├─ Resources ──┐│  Datos que el LLM puede leer
│  └─ Prompts ────┘│  Templates de prompts reutilizables
└─────────────────┘

Conceptos clave

Concepto Descripción Ejemplo
Tool Función ejecutable create_issue, send_email
Resource Datos de solo lectura file://docs/api.md, db://users
Prompt Template de prompt reutilizable code-review, summarize
Transport Cómo se comunican client/server stdio, SSE, HTTP

Crear un MCP Server con TypeScript

Setup

npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node

Server básico

// src/server.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';

const server = new McpServer({
  name: 'my-app-server',
  version: '1.0.0',
});

// ── Tool: buscar en base de datos ──────────────────────
server.tool(
  'search_docs',
  'Busca documentos en la base de conocimiento',
  {
    query: z.string().describe('Término de búsqueda'),
    limit: z.number().default(5).describe('Máximo de resultados'),
  },
  async ({ query, limit }) => {
    const results = await searchDatabase(query, limit);
    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(results, null, 2),
        },
      ],
    };
  }
);

// ── Tool: crear ticket de soporte ──────────────────────
server.tool(
  'create_ticket',
  'Crea un ticket de soporte técnico',
  {
    title: z.string().describe('Título del ticket'),
    description: z.string().describe('Descripción detallada'),
    priority: z.enum(['low', 'medium', 'high', 'critical']),
  },
  async ({ title, description, priority }) => {
    const ticket = await createSupportTicket({ title, description, priority });
    return {
      content: [
        {
          type: 'text',
          text: `Ticket creado: #${ticket.id} - ${ticket.title}`,
        },
      ],
    };
  }
);

// ── Resource: documentación de la API ──────────────────
server.resource(
  'api-docs',
  'docs://api/reference',
  async (uri) => {
    const docs = await loadApiDocs();
    return {
      contents: [
        {
          uri: uri.href,
          mimeType: 'text/markdown',
          text: docs,
        },
      ],
    };
  }
);

// ── Resource dinámico: usuario por ID ──────────────────
server.resource(
  'user-profile',
  'users://{userId}/profile',
  async (uri) => {
    const userId = uri.pathname.split('/')[1];
    const user = await getUser(userId);
    return {
      contents: [
        {
          uri: uri.href,
          mimeType: 'application/json',
          text: JSON.stringify(user),
        },
      ],
    };
  }
);

// ── Prompt: revisión de código ─────────────────────────
server.prompt(
  'code-review',
  'Genera un prompt para revisión de código',
  {
    language: z.string().describe('Lenguaje de programación'),
    code: z.string().describe('Código a revisar'),
  },
  async ({ language, code }) => ({
    messages: [
      {
        role: 'user',
        content: {
          type: 'text',
          text: `Revisa este código ${language} como un senior developer:

\`\`\`${language}
${code}
\`\`\`

Analiza: bugs, seguridad, performance, legibilidad y mejoras.`,
        },
      },
    ],
  })
);

// Iniciar server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error('MCP Server running on stdio');
}

main();

Configurar MCP Client

En Claude Desktop

// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
  "mcpServers": {
    "my-app": {
      "command": "node",
      "args": ["/path/to/my-server/dist/server.js"],
      "env": {
        "DATABASE_URL": "postgresql://...",
        "API_KEY": "..."
      }
    }
  }
}

En tu propia aplicación

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';

const transport = new StdioClientTransport({
  command: 'node',
  args: ['./mcp-server/dist/server.js'],
});

const client = new Client({ name: 'my-app', version: '1.0.0' }, {});
await client.connect(transport);

// Listar tools disponibles
const tools = await client.listTools();
console.log('Tools:', tools.tools.map(t => t.name));

// Ejecutar una tool
const result = await client.callTool({
  name: 'search_docs',
  arguments: { query: 'authentication', limit: 3 },
});
console.log('Result:', result);

// Leer un resource
const resource = await client.readResource({
  uri: 'docs://api/reference',
});
console.log('Resource:', resource);

MCP con SSE Transport (HTTP)

Para servidores remotos, usa SSE en lugar de stdio:

// Server con SSE
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express from 'express';

const app = express();

app.get('/sse', async (req, res) => {
  const transport = new SSEServerTransport('/messages', res);
  await server.connect(transport);
});

app.post('/messages', async (req, res) => {
  // Manejar mensajes del cliente
  await transport.handlePostMessage(req, res);
});

app.listen(3002, () => console.log('MCP SSE server on port 3002'));
// Client con SSE
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';

const transport = new SSEClientTransport(
  new URL('http://localhost:3002/sse')
);
const client = new Client({ name: 'my-app', version: '1.0.0' }, {});
await client.connect(transport);

Integrar MCP Tools con un LLM

class MCPAgent {
  private mcpClient: Client;

  async chat(userMessage: string): Promise<string> {
    // 1. Obtener tools del MCP server
    const { tools } = await this.mcpClient.listTools();

    // 2. Convertir a formato OpenAI
    const openAITools = tools.map(tool => ({
      type: 'function' as const,
      function: {
        name: tool.name,
        description: tool.description || '',
        parameters: tool.inputSchema,
      },
    }));

    // 3. Chat con function calling
    const messages = [
      { role: 'user' as const, content: userMessage },
    ];

    const response = await openai.chat.completions.create({
      model: 'gpt-4o',
      messages,
      tools: openAITools,
    });

    // 4. Ejecutar tools via MCP
    if (response.choices[0].message.tool_calls) {
      for (const call of response.choices[0].message.tool_calls) {
        const result = await this.mcpClient.callTool({
          name: call.function.name,
          arguments: JSON.parse(call.function.arguments),
        });
        // ... continuar el loop
      }
    }

    return response.choices[0].message.content!;
  }
}

MCP Servers populares

Server Descripción
@modelcontextprotocol/server-github Issues, PRs, repos de GitHub
@modelcontextprotocol/server-slack Canales, mensajes de Slack
@modelcontextprotocol/server-postgres Consultas SQL a PostgreSQL
@modelcontextprotocol/server-filesystem Leer/escribir archivos locales
@modelcontextprotocol/server-brave-search Búsqueda web
@modelcontextprotocol/server-puppeteer Navegación web automatizada
🔒

Ejercicio práctico disponible

Simula un servidor MCP

Desbloquear ejercicios
// Simula un servidor MCP
// Desbloquea Pro para acceder a este ejercicio
// y ganar +50 XP al completarlo

function ejemplo() {
    // Tu código aquí...
}

¿Te gustó esta lección?

Con Pro puedes marcar progreso, hacer ejercicios, tomar quizzes, ganar XP y obtener tu constancia.

Ver planes desde $9/mes