$ desarrollomcp
Volver al blog
Tutoriales

Primeros Pasos con MCP: Guía para Desarrolladores

Por DesarrolloMCP
|
#mcp #typescript #nodejs #tutorial

Introducción

Si ya conoces los fundamentos de MCP, es hora de ensuciarnos las manos. En este tutorial, aprenderás a construir tu primer servidor MCP desde cero.

Requisitos previos

Antes de comenzar, asegúrate de tener instalado:

# Node.js v18 o superior
node --version  # v18.0.0 o mayor

# npm o pnpm
npm --version   # 8.0.0 o mayor

Instalación del SDK

MCP proporciona SDKs oficiales para diferentes lenguajes. Comenzaremos con TypeScript:

# Crear nuevo proyecto
mkdir mi-servidor-mcp
cd mi-servidor-mcp

# Inicializar proyecto
npm init -y

# Instalar SDK de MCP
npm install @modelcontextprotocol/sdk

# Instalar TypeScript y tipos
npm install -D typescript @types/node

Configuración de TypeScript

Crea un archivo tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Tu primer servidor MCP

Estructura básica

Crea el archivo src/index.ts:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

// Crear instancia del servidor
const server = new Server(
  {
    name: "mi-primer-servidor-mcp",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

Definir herramientas (Tools)

Las herramientas son funciones que la IA puede ejecutar. Vamos a crear una calculadora simple:

// Registrar handler para listar herramientas
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "sumar",
        description: "Suma dos números",
        inputSchema: {
          type: "object",
          properties: {
            a: {
              type: "number",
              description: "Primer número",
            },
            b: {
              type: "number",
              description: "Segundo número",
            },
          },
          required: ["a", "b"],
        },
      },
      {
        name: "multiplicar",
        description: "Multiplica dos números",
        inputSchema: {
          type: "object",
          properties: {
            a: { type: "number" },
            b: { type: "number" },
          },
          required: ["a", "b"],
        },
      },
    ],
  };
});

Implementar la lógica

Ahora implementamos qué hace cada herramienta:

// Registrar handler para ejecutar herramientas
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case "sumar": {
      const { a, b } = args as { a: number; b: number };
      const resultado = a + b;
      return {
        content: [
          {
            type: "text",
            text: `El resultado de sumar ${a} + ${b} es: ${resultado}`,
          },
        ],
      };
    }

    case "multiplicar": {
      const { a, b } = args as { a: number; b: number };
      const resultado = a * b;
      return {
        content: [
          {
            type: "text",
            text: `El resultado de multiplicar ${a} × ${b} es: ${resultado}`,
          },
        ],
      };
    }

    default:
      throw new Error(`Herramienta desconocida: ${name}`);
  }
});

Iniciar el servidor

// Conectar servidor con transporte stdio
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Servidor MCP iniciado en stdio");
}

main().catch((error) => {
  console.error("Error fatal:", error);
  process.exit(1);
});

Servidor completo

Aquí está el código completo de src/index.ts:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
  {
    name: "calculadora-mcp",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// Lista de herramientas
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "sumar",
        description: "Suma dos números",
        inputSchema: {
          type: "object",
          properties: {
            a: { type: "number", description: "Primer número" },
            b: { type: "number", description: "Segundo número" },
          },
          required: ["a", "b"],
        },
      },
      {
        name: "multiplicar",
        description: "Multiplica dos números",
        inputSchema: {
          type: "object",
          properties: {
            a: { type: "number" },
            b: { type: "number" },
          },
          required: ["a", "b"],
        },
      },
    ],
  };
});

// Implementación de herramientas
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    case "sumar": {
      const { a, b } = args as { a: number; b: number };
      return {
        content: [
          {
            type: "text",
            text: `El resultado es: ${a + b}`,
          },
        ],
      };
    }

    case "multiplicar": {
      const { a, b } = args as { a: number; b: number };
      return {
        content: [
          {
            type: "text",
            text: `El resultado es: ${a * b}`,
          },
        ],
      };
    }

    default:
      throw new Error(`Herramienta desconocida: ${name}`);
  }
});

// Iniciar servidor
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Servidor MCP iniciado");
}

main().catch(console.error);

Compilar y ejecutar

Añade scripts a tu package.json:

{
  "name": "mi-servidor-mcp",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc && node dist/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "latest"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.3.0"
  }
}

Compila y ejecuta:

# Compilar TypeScript
npm run build

# Ejecutar servidor
npm start

Conectar con Claude Desktop

Para usar tu servidor con Claude Desktop, añádelo a la configuración:

En macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

En Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "calculadora": {
      "command": "node",
      "args": ["/ruta/a/tu/proyecto/dist/index.js"]
    }
  }
}

Reinicia Claude Desktop y tu servidor estará disponible.

Ejemplo con recursos

Además de herramientas, puedes exponer recursos (datos):

import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";

// Listar recursos disponibles
server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: [
      {
        uri: "config://settings",
        name: "Configuración de la app",
        mimeType: "application/json",
      },
    ],
  };
});

// Leer un recurso específico
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const { uri } = request.params;

  if (uri === "config://settings") {
    return {
      contents: [
        {
          uri,
          mimeType: "application/json",
          text: JSON.stringify({
            theme: "dark",
            language: "es",
            version: "1.0.0",
          }, null, 2),
        },
      ],
    };
  }

  throw new Error(`Recurso no encontrado: ${uri}`);
});

Debugging

Para debug, usa console.error() (no console.log, que interfiere con el protocolo):

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  console.error("Recibida petición:", request.params);
  // ... tu código
});

Mejores prácticas

1. Validación de entrada

function validateNumber(value: any): number {
  if (typeof value !== "number" || isNaN(value)) {
    throw new Error(`Valor inválido: ${value}`);
  }
  return value;
}

2. Manejo de errores

try {
  const result = await operacionRiesgosa();
  return { content: [{ type: "text", text: result }] };
} catch (error) {
  return {
    content: [
      {
        type: "text",
        text: `Error: ${error instanceof Error ? error.message : "Desconocido"}`,
      },
    ],
    isError: true,
  };
}

3. Logging estructurado

console.error(JSON.stringify({
  timestamp: new Date().toISOString(),
  level: "info",
  message: "Herramienta ejecutada",
  tool: name,
}));

Próximos pasos

Ahora que tienes tu primer servidor MCP funcionando, puedes:

  1. Añadir más herramientas complejas
  2. Conectar con bases de datos
  3. Integrar con APIs externas
  4. Publicar tu servidor en el MCP Registry

Conclusión

Has aprendido a:

  • ✅ Instalar y configurar el SDK de MCP
  • ✅ Crear un servidor MCP básico
  • ✅ Definir herramientas y recursos
  • ✅ Conectar con Claude Desktop
  • ✅ Implementar mejores prácticas

En el próximo artículo exploraremos el MCP Registry y cómo compartir tus servidores con la comunidad.


Post anterior: Introducción al Model Context Protocol

Próximo post: El Registry de MCP: Descubre Servidores Públicos

Recursos: