DEV Community

Cover image for Cómo Crear un Servidor MCP para Potenciar Agentes IA en Pruebas API
Roobia
Roobia

Posted on • Originally published at apidog.com

Cómo Crear un Servidor MCP para Potenciar Agentes IA en Pruebas API

En resumen

Crea un servidor MCP con TypeScript que exponga tres herramientas clave: run_test, validate_schema y list_environments. Configura este servidor en ~/.claude/settings.json para Claude Code o en .cursor/mcp.json para Cursor. Así, tus agentes de IA podrán ejecutar pruebas de Apidog, validar esquemas OpenAPI y consultar entornos directamente desde la interfaz de chat. El código fuente es compacto (~150 líneas) y utiliza el paquete @modelcontextprotocol/sdk.

Prueba Apidog hoy mismo

Crea y configura un servidor MCP para que Claude Code, Cursor y otros agentes de IA ejecuten pruebas de API de Apidog, validen esquemas y consulten entornos, todo sin salir de la interfaz de chat.

💡 Caso de uso: Estás codificando y tu agente de IA termina de construir un endpoint. En vez de copiar código, abrir Apidog y validar manualmente, ejecuta un comando y obtén los resultados al instante.

El Model Context Protocol (MCP) permite a agentes de IA acceder a herramientas externas mediante una interfaz estandarizada. Al construir un servidor MCP para Apidog, tu agente de IA podrá ejecutar pruebas, validar esquemas y obtener entornos sin cambiar de contexto.

¿Qué es MCP?

MCP (Model Context Protocol) es un protocolo que permite a los agentes de IA acceder a herramientas y fuentes de datos externas, similar a un sistema de plugins. Funciona con Claude Code, Cursor y cualquier cliente compatible con MCP.

Un servidor MCP expone herramientas (funciones que el agente puede invocar) y recursos (datos consultables). En este caso, el servidor MCP de Apidog expone funciones para pruebas de API.

┌─────────────────┐         ┌──────────────────┐         ┌─────────────┐
│  Agente de IA   │         │  Servidor MCP    │         │  Apidog     │
│  (Claude Code)  │◄───────►│  (Tu Código)     │◄───────►│  API        │
└─────────────────┘   JSON  └──────────────────┘  HTTP   └─────────────┘
Enter fullscreen mode Exit fullscreen mode

Paso 1: Configura el proyecto

Crea un nuevo proyecto TypeScript:

mkdir apidog-mcp-server
cd apidog-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
Enter fullscreen mode Exit fullscreen mode

Crea el archivo tsconfig.json:

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

Agrega scripts de build y start en package.json:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

Paso 2: Crea el esqueleto del servidor MCP

Crea src/index.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: "apidog",
  version: "1.0.0",
  description: "Apidog API testing tools for AI agents"
});

// Aquí irán las herramientas

const transport = new StdioServerTransport();
await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

Este esqueleto crea un servidor MCP y lo conecta al transporte stdio, que maneja la comunicación entre el agente de IA y tu servidor.

Paso 3: Implementa la herramienta run_test

Agrega la herramienta run_test a src/index.ts:

server.tool(
  "run_test",
  {
    projectId: z.string().describe("Apidog project ID (en la URL del proyecto)"),
    environmentId: z.string().optional().describe("ID de entorno opcional"),
    testSuiteId: z.string().optional().describe("ID de test suite opcional")
  },
  async ({ projectId, environmentId, testSuiteId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY no definida"
        }]
      };
    }

    let url = `https://api.apidog.com/v1/projects/${projectId}/tests/run`;
    const params = new URLSearchParams();
    if (environmentId) params.append("environmentId", environmentId);
    if (testSuiteId) params.append("testSuiteId", testSuiteId);
    if (params.toString()) url += `?${params.toString()}`;

    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${apiKey}`,
          "Content-Type": "application/json"
        }
      });

      if (!response.ok) {
        const error = await response.text();
        return {
          content: [{
            type: "text",
            text: `Error API: ${response.status} ${error}`
          }]
        };
      }

      const results = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(results, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Fallo en la petición: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Estructura de la herramienta:

  1. Nombrerun_test
  2. Esquema — Validación de parámetros con Zod y descripciones
  3. Manejador — Llama a la API de Apidog y retorna el resultado

Paso 4: Añade la herramienta validate_schema

Permite validar esquemas OpenAPI antes de su despliegue:

server.tool(
  "validate_schema",
  {
    schema: z.object({}).describe("Objeto schema OpenAPI 3.x a validar"),
    strict: z.boolean().optional().default(false).describe("Modo estricto para validaciones adicionales")
  },
  async ({ schema, strict }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY no definida"
        }]
      };
    }

    try {
      const response = await fetch("https://api.apidog.com/v1/schemas/validate", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${apiKey}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ schema, strict })
      });

      const result = await response.json();

      if (!response.ok) {
        return {
          content: [{
            type: "text",
            text: `Validación fallida: ${JSON.stringify(result.errors, null, 2)}`
          }]
        };
      }

      return {
        content: [{
          type: "text",
          text: result.valid
            ? "El esquema es válido OpenAPI 3.x"
            : `Advertencias: ${JSON.stringify(result.warnings, null, 2)}`
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Validación fallida: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Paso 5: Añade la herramienta list_environments

Permite consultar los entornos disponibles de un proyecto:

server.tool(
  "list_environments",
  {
    projectId: z.string().describe("Apidog project ID")
  },
  async ({ projectId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY no definida"
        }]
      };
    }

    try {
      const response = await fetch(
        `https://api.apidog.com/v1/projects/${projectId}/environments`,
        {
          headers: {
            "Authorization": `Bearer ${apiKey}`
          }
        }
      );

      if (!response.ok) {
        const error = await response.text();
        return {
          content: [{
            type: "text",
            text: `Error API: ${response.status} ${error}`
          }]
        };
      }

      const environments = await response.json();
      return {
        content: [{
          type: "text",
          text: environments.length === 0
            ? "No se encontraron entornos para este proyecto"
            : environments.map((e: any) =>
                `- ${e.name} (ID: ${e.id})${e.isDefault ? " [default]" : ""}`
              ).join("\n")
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Fallo en la petición: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Paso 6: Compila y prueba el servidor

Compila el TypeScript:

npm run build
Enter fullscreen mode Exit fullscreen mode

Prueba con un cliente MCP simple (test-client.js):

import { spawn } from "child_process";

const server = spawn("node", ["dist/index.js"], {
  env: { ...process.env, APIDOG_API_KEY: "your-api-key" }
});

server.stdout.on("data", (data) => {
  console.log(`Server output: ${data}`);
});

server.stderr.on("data", (data) => {
  console.error(`Server error: ${data}`);
});

// Mensaje de prueba
const message = {
  jsonrpc: "2.0",
  id: 1,
  method: "initialize",
  params: {
    protocolVersion: "2024-11-05",
    capabilities: {},
    clientInfo: { name: "test-client", version: "1.0.0" }
  }
};

server.stdin.write(JSON.stringify(message) + "\n");
Enter fullscreen mode Exit fullscreen mode

Paso 7: Configura para Claude Code

Edita ~/.claude/settings.json así:

{
  "mcpServers": {
    "apidog": {
      "command": "node",
      "args": ["/absolute/path/to/apidog-mcp-server/dist/index.js"],
      "env": {
        "APIDOG_API_KEY": "your-api-key-here"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Reinicia Claude Code. Ahora podrás invocar las herramientas de Apidog directamente desde el chat:

Usa la herramienta run_test para ejecutar pruebas en mi proyecto Apidog.
ID del proyecto: proj_12345
Entorno: staging
Enter fullscreen mode Exit fullscreen mode
Valida este esquema OpenAPI según las reglas de Apidog:
[pegar esquema]
Enter fullscreen mode Exit fullscreen mode
Lista todos los entornos para el proyecto proj_12345
Enter fullscreen mode Exit fullscreen mode

Paso 8: Configura para Cursor

Para Cursor, agrega .cursor/mcp.json en tu proyecto:

{
  "mcpServers": {
    "apidog": {
      "command": "node",
      "args": ["/absolute/path/to/apidog-mcp-server/dist/index.js"],
      "env": {
        "APIDOG_API_KEY": "your-api-key-here"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Ejemplo de uso en Cursor:

@apidog run_test projectId="proj_12345" environmentId="staging"
Enter fullscreen mode Exit fullscreen mode

Código fuente completo

src/index.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: "apidog",
  version: "1.0.0",
  description: "Apidog API testing tools for AI agents"
});

// Tool: run_test
server.tool(
  "run_test",
  {
    projectId: z.string().describe("Apidog project ID"),
    environmentId: z.string().optional().describe("Environment ID"),
    testSuiteId: z.string().optional().describe("Test suite ID")
  },
  async ({ projectId, environmentId, testSuiteId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY not set"
        }]
      };
    }

    let url = `https://api.apidog.com/v1/projects/${projectId}/tests/run`;
    const params = new URLSearchParams();
    if (environmentId) params.append("environmentId", environmentId);
    if (testSuiteId) params.append("testSuiteId", testSuiteId);
    if (params.toString()) url += `?${params.toString()}`;

    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${apiKey}`,
          "Content-Type": "application/json"
        }
      });

      const results = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(results, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Request failed: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);

// Tool: validate_schema
server.tool(
  "validate_schema",
  {
    schema: z.object({}).describe("OpenAPI schema"),
    strict: z.boolean().optional().default(false)
  },
  async ({ schema, strict }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY not set"
        }]
      };
    }

    const response = await fetch("https://api.apidog.com/v1/schemas/validate", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${apiKey}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ schema, strict })
    });

    const result = await response.json();
    return {
      content: [{
        type: "text",
        text: result.valid
          ? "Schema is valid"
          : `Issues: ${JSON.stringify(result.errors || result.warnings, null, 2)}`
      }]
    };
  }
);

// Tool: list_environments
server.tool(
  "list_environments",
  {
    projectId: z.string().describe("Apidog project ID")
  },
  async ({ projectId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY not set"
        }]
      };
    }

    const response = await fetch(
      `https://api.apidog.com/v1/projects/${projectId}/environments`,
      {
        headers: { "Authorization": `Bearer ${apiKey}` }
      }
    );

    const environments = await response.json();
    return {
      content: [{
        type: "text",
        text: environments.map((e: any) =>
          `- ${e.name} (${e.id})${e.isDefault ? " [default]" : ""}`
        ).join("\n")
      }]
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

Lo que has construido

Componente Propósito
Servidor MCP Conecta agentes de IA a la API de Apidog
run_test Ejecuta colecciones de pruebas programáticamente
validate_schema Detecta errores de OpenAPI antes del despliegue
list_environments Descubre entornos de prueba disponibles
Validación Zod Maneja parámetros con seguridad de tipos
Transporte Stdio Compatible con Claude Code, Cursor y cualquier MCP

Próximos pasos

Extiende el servidor:

  • Agrega la herramienta compare_responses para comparar resultados entre entornos
  • Añade get_test_history para consultar el historial de pruebas
  • Implementa trigger_mock_server para iniciar/detener mocks

Consideraciones para producción:

  • Implementa retries para solicitudes inestables
  • Limita la velocidad para evitar bloqueos de la API
  • Añade logs para depuración de errores
  • Guarda las claves API en una bóveda segura

Comparte con tu equipo:

  • Publica en npm como @tu-organizacion/apidog-mcp-server
  • Documenta variables de entorno requeridas
  • Incluye ejemplos de configuración MCP

Solución de problemas comunes

El servidor MCP no carga en Claude Code:

  • Asegúrate de que la ruta en ~/.claude/settings.json es absoluta
  • Verifica que node está en tu PATH (which node)
  • Confirma que dist/index.js existe y está compilado
  • Revisa los logs MCP de Claude Code

Las herramientas no aparecen después de la configuración:

  • Reinicia completamente Claude Code
  • Ejecuta npm run build para compilar TypeScript
  • Verifica que las tres herramientas se definan antes de server.connect()
  • Asegúrate de que el servidor inicia sin errores (node dist/index.js)

Las solicitudes a la API fallan con 401:

  • Confirma que APIDOG_API_KEY está configurada correctamente
  • Elimina espacios extra o comillas en el valor de la clave
  • Verifica que tu cuenta de Apidog tiene acceso a la API habilitado
  • Prueba la clave manualmente:
curl -H "Authorization: Bearer $APIDOG_API_KEY" https://api.apidog.com/v1/user
Enter fullscreen mode Exit fullscreen mode

Errores de validación de Zod:

  • Los nombres de los parámetros deben coincidir con el esquema
  • Incluye todos los campos obligatorios (sin errores de tipado)
  • Usa .optional() para los campos opcionales
  • Lee el mensaje de error completo; Zod indica el campo con problema

Errores de compilación de TypeScript:

  • Ejecuta npm install para instalar dependencias
  • Verifica la versión de TypeScript (npx tsc --version, debe ser 5.x)
  • Limpia y recompila (rm -rf dist && npm run build)
  • Añade aserciones de tipo si es necesario en las respuestas de fetch

Probando tu servidor MCP localmente

Pruebas manuales con stdio:

# Inicia el servidor
node dist/index.js

# En otra terminal, envía un mensaje de prueba
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
Enter fullscreen mode Exit fullscreen mode

Salida esperada:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      { "name": "run_test", "description": "...", "inputSchema": {...} },
      { "name": "validate_schema", "description": "...", "inputSchema": {...} },
      { "name": "list_environments", "description": "...", "inputSchema": {...} }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Prueba una llamada a una herramienta:

echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_environments","arguments":{"projectId":"your-project-id"}}}' | node dist/index.js
Enter fullscreen mode Exit fullscreen mode

Tus agentes de IA ahora tienen acceso directo a las capacidades de prueba de Apidog. Olvídate de copiar/pegar entre chat y navegador. Escribe un comando, recibe resultados automáticos.

Ese es el poder de MCP: amplía tus agentes de IA con herramientas especializadas y acelera tus ciclos de desarrollo.

Puntos clave

  • Servidores MCP conectan agentes de IA a APIs externas: Implementa una vez y úsalo en Claude Code, Cursor y cualquier cliente MCP.
  • Tres herramientas cubren los flujos principales: run_test para ejecutar pruebas, validate_schema para validación OpenAPI, list_environments para descubrir entornos.
  • La validación Zod previene errores de parámetros: Las definiciones de herramientas seguras detectan problemas antes de invocar la API.
  • La configuración es específica por herramienta: Claude Code usa ~/.claude/settings.json, Cursor usa .cursor/mcp.json.
  • Para producción agrega manejo de errores: Implementa retries, rate limiting y almacenamiento seguro de claves.

Preguntas frecuentes

¿Qué es MCP en IA?

MCP (Model Context Protocol) es un protocolo estandarizado para que los agentes de IA accedan a herramientas y fuentes de datos externas, similar a un sistema de plugins.

¿Cómo creo un servidor MCP para Apidog?

Instala @modelcontextprotocol/sdk, define herramientas con Zod, implementa manejadores que llamen a la API de Apidog y conecta usando StdioServerTransport.

¿Puedo usar esto con Cursor?

Sí, agrega la configuración MCP en .cursor/mcp.json. El mismo servidor funciona tanto en Claude Code como en Cursor y otros clientes MCP.

¿Qué herramientas debo exponer?

Comienza con run_test (ejecución de pruebas), validate_schema (validación OpenAPI) y list_environments (consulta de entornos).

¿El servidor MCP de Apidog está listo para producción?

El código presentado es un punto de partida. Agrega retries, limitación de velocidad, manejo de errores robusto y almacenamiento seguro de claves antes de usarlo en producción.

¿Necesito una clave API de Apidog?

Sí. Define APIDOG_API_KEY como variable de entorno. El servidor la usará para autenticar las peticiones a la API.

¿Puedo compartir este servidor MCP con mi equipo?

Sí, publícalo en npm (privado), documenta las variables de entorno necesarias e incluye ejemplos de configuración MCP.

Top comments (0)