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)