DEV Community

Cover image for Como Criar um Servidor MCP para Capacitar Agentes de IA com Testes de API
Lucas
Lucas

Posted on • Originally published at apidog.com

Como Criar um Servidor MCP para Capacitar Agentes de IA com Testes de API

RESUMO

Crie um servidor MCP com TypeScript para expor três ferramentas essenciais: run_test, validate_schema e list_environments. Configure em ~/.claude/settings.json para Claude Code ou .cursor/mcp.json para Cursor. Com isso, seus agentes de IA poderão executar testes Apidog, validar esquemas OpenAPI e acessar ambientes diretamente do chat. O código é enxuto (~150 linhas) utilizando o pacote @modelcontextprotocol/sdk.

Experimente o Apidog hoje

Crie um servidor MCP para permitir que Claude Code, Cursor e outros agentes de IA executem testes de API Apidog, validem esquemas e consultem ambientes de forma automatizada, sem sair da interface de bate-papo.

💡 Cenário: Você está codificando e seu agente de IA acabou de criar um endpoint. Em vez de copiar código, abrir o Apidog, criar testes e validar manualmente, apenas digite um comando e veja o resultado imediatamente.

O Model Context Protocol (MCP) permite que agentes de IA acessem ferramentas externas por uma interface padronizada. Com um servidor MCP para Apidog, o agente executa testes, valida esquemas e consulta ambientes sem trocar de contexto.

O Que É MCP?

O MCP (Model Context Protocol) é um protocolo para agentes de IA acessarem ferramentas externas e fontes de dados. Funciona como um sistema de plugins compatível com Claude Code, Cursor e outros clientes MCP.

Um servidor MCP expõe ferramentas (funções que o agente pode chamar) e recursos (dados que o agente pode ler). O servidor MCP para Apidog expõe ferramentas para automação de testes de API.

┌─────────────────┐         ┌──────────────────┐         ┌─────────────┐
│  AI Agent       │         │  MCP Server      │         │  Apidog     │
│  (Claude Code)  │◄───────►│  (Your Code)     │◄───────►│  API        │
└─────────────────┘   JSON  └──────────────────┘  HTTP   └─────────────┘
Enter fullscreen mode Exit fullscreen mode

Passo 1: Configure o Projeto

Crie um novo projeto 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

Crie o arquivo 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

Adicione scripts ao package.json:

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

Passo 2: Crie o Esqueleto do Servidor MCP

Crie 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"
});

// As ferramentas serão definidas aqui

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

Esse esqueleto instancia o servidor MCP e conecta pelo transporte stdio, responsável pela comunicação entre o agente de IA e seu servidor.

Passo 3: Defina a Ferramenta run_test

Adicione em src/index.ts:

// Tool: run_test
server.tool(
  "run_test",
  {
    projectId: z.string().describe("ID do projeto Apidog (veja na URL do projeto)"),
    environmentId: z.string().optional().describe("ID do ambiente (opcional)"),
    testSuiteId: z.string().optional().describe("ID da suíte de teste (opcional)")
  },
  async ({ projectId, environmentId, testSuiteId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Erro: variável de ambiente APIDOG_API_KEY não definida"
        }]
      };
    }

    let url = `https://api.apidog.com/v1/projects/${projectId}/tests/run?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation`;
    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: `Erro da 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: `Falha na requisição: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Resumo:

  • Nome: run_test
  • Validação: Zod
  • Manipulador: Chama a API Apidog para execução de testes.

Passo 4: Adicione a Ferramenta validate_schema

Implemente validação de esquemas OpenAPI:

// Tool: validate_schema
server.tool(
  "validate_schema",
  {
    schema: z.object({}).describe("Objeto de esquema OpenAPI 3.x para validar"),
    strict: z.boolean().optional().default(false).describe("Modo estrito para validações adicionais")
  },
  async ({ schema, strict }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Erro: variável de ambiente APIDOG_API_KEY não definida"
        }]
      };
    }

    try {
      const response = await fetch("https://api.apidog.com/v1/schemas/validate?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation", {
        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: `Validação falhou: ${JSON.stringify(result.errors, null, 2)}`
          }]
        };
      }

      return {
        content: [{
          type: "text",
          text: result.valid
            ? "Schema válido OpenAPI 3.x"
            : `Avisos: ${JSON.stringify(result.warnings, null, 2)}`
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Validação falhou: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Passo 5: Adicione a Ferramenta list_environments

Permita consultar ambientes disponíveis:

// Tool: list_environments
server.tool(
  "list_environments",
  {
    projectId: z.string().describe("ID do projeto Apidog")
  },
  async ({ projectId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Erro: variável de ambiente APIDOG_API_KEY não definida"
        }]
      };
    }

    try {
      const response = await fetch(
        `https://api.apidog.com/v1/projects/${projectId}/environments?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation`,
        {
          headers: {
            "Authorization": `Bearer ${apiKey}`
          }
        }
      );

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

      const environments = await response.json();
      return {
        content: [{
          type: "text",
          text: environments.length === 0
            ? "Nenhum ambiente encontrado para este projeto"
            : environments.map((e: any) =>
                `- ${e.name} (ID: ${e.id})${e.isDefault ? " [default]" : ""}`
              ).join("\n")
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Falha na requisição: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Passo 6: Construa e Teste

Compile o servidor:

npm run build
Enter fullscreen mode Exit fullscreen mode

Teste com um cliente MCP básico (test-client.js):

import { spawn } from "child_process";

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

server.stdout.on("data", (data) => {
  console.log(`Saída do servidor: ${data}`);
});

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

// Mensagem de teste
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

Passo 7: Configure para Claude Code

Adicione o servidor MCP na configuração do Claude Code:

Crie/edite ~/.claude/settings.json:

{
  "mcpServers": {
    "apidog": {
      "command": "node",
      "args": ["/caminho/absoluto/para/apidog-mcp-server/dist/index.js"],
      "env": {
        "APIDOG_API_KEY": "sua-api-key-aqui"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Reinicie o Claude Code. As ferramentas Apidog já estarão disponíveis para comandos.

Exemplos de uso:

Use a ferramenta run_test para rodar testes no meu projeto Apidog.
Project ID: proj_12345
Environment: staging
Enter fullscreen mode Exit fullscreen mode
Valide este schema OpenAPI contra as regras do Apidog:
[cole o schema]
Enter fullscreen mode Exit fullscreen mode
Liste todos os ambientes do projeto proj_12345
Enter fullscreen mode Exit fullscreen mode

Passo 8: Configure para Cursor

No Cursor, configure .cursor/mcp.json:

{
  "mcpServers": {
    "apidog": {
      "command": "node",
      "args": ["/caminho/absoluto/para/apidog-mcp-server/dist/index.js"],
      "env": {
        "APIDOG_API_KEY": "sua-api-key-aqui"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Exemplo de uso:

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

Código-Fonte 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("ID do projeto Apidog"),
    environmentId: z.string().optional().describe("ID do ambiente"),
    testSuiteId: z.string().optional().describe("ID da suíte de teste")
  },
  async ({ projectId, environmentId, testSuiteId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Erro: APIDOG_API_KEY não definida"
        }]
      };
    }

    let url = `https://api.apidog.com/v1/projects/${projectId}/tests/run?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation`;
    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: `Falha na requisição: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);

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

    const response = await fetch("https://api.apidog.com/v1/schemas/validate?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation", {
      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 válido"
          : `Issues: ${JSON.stringify(result.errors || result.warnings, null, 2)}`
      }]
    };
  }
);

// Tool: list_environments
server.tool(
  "list_environments",
  {
    projectId: z.string().describe("ID do projeto Apidog")
  },
  async ({ projectId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Erro: APIDOG_API_KEY não definida"
        }]
      };
    }

    const response = await fetch(
      `https://api.apidog.com/v1/projects/${projectId}/environments?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation`,
      {
        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

O Que Você Construiu

Componente Propósito
Servidor MCP Conecta agentes de IA à API Apidog
run_test Executa coleções de teste programaticamente
validate_schema Valida esquemas OpenAPI antes da implantação
list_environments Consulta ambientes de teste disponíveis
Validação Zod Segurança de tipos para parâmetros
Transporte Stdio Compatível com Claude Code, Cursor, qualquer cliente MCP

Próximos Passos

Extensões sugeridas:

  • Implemente compare_responses para comparar ambientes.
  • Adicione get_test_history para histórico de execuções.
  • Inclua trigger_mock_server para controlar mocks.

Para produção:

  • Adicione retentativas para requisições instáveis.
  • Implemente rate limiting.
  • Inclua logging detalhado de falhas.
  • Armazene a chave da API em um cofre seguro (não em variáveis de ambiente).

Compartilhamento:

  • Publique como pacote npm privado.
  • Documente variáveis de ambiente.
  • Forneça exemplos de configuração MCP.

Solução de Problemas Comuns

Servidor MCP não carrega no Claude Code:

  • Confirme se o caminho em ~/.claude/settings.json é absoluto.
  • Verifique se o comando node está no PATH.
  • Assegure que dist/index.js existe após build.
  • Veja logs MCP do Claude Code para detalhes.

Ferramentas não aparecem:

  • Reinicie o Claude Code completamente.
  • Execute npm run build para compilar TypeScript.
  • Certifique-se de que todas as ferramentas estão definidas antes de server.connect().
  • Inicie manualmente: node dist/index.js para checar erros.

API retorna 401:

  • Confirme se APIDOG_API_KEY está configurada corretamente.
  • Remova espaços/extras na chave.
  • Verifique se sua conta Apidog tem acesso à API.
  • Teste com curl:
  curl -H "Authorization: Bearer $APIDOG_API_KEY" https://api.apidog.com/v1/user?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation
Enter fullscreen mode Exit fullscreen mode

Erro de validação Zod:

  • Parâmetros devem seguir o esquema exato.
  • Campos obrigatórios devem ser preenchidos.
  • Campos opcionais usam .optional() no Zod.
  • Leia a mensagem de erro retornada.

Compilação TypeScript falha:

  • Rode npm install para dependências.
  • Verifique a versão do TypeScript (use 5.x ou superior).
  • Limpe e reconstrua: rm -rf dist && npm run build.
  • Verifique tipos nas respostas do fetch.

Testando Seu Servidor MCP Localmente

Antes de implantar, teste localmente:

Teste manual via stdio:

# Inicie o servidor
node dist/index.js

# Em outro terminal, envie comando de listagem de ferramentas
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
Enter fullscreen mode Exit fullscreen mode

Saída 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

Testando chamada de ferramenta:

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

Seus agentes de IA agora acessam diretamente os recursos do Apidog, sem copiar e colar, nem execuções manuais. Apenas um comando no chat para rodar testes e validar APIs.

Principais Conclusões

  • Servidores MCP conectam agentes de IA a APIs externas — implemente uma vez e use em Claude Code, Cursor e qualquer cliente MCP.
  • Três ferramentas suprem a maioria dos casos de teste de API: run_test (execução), validate_schema (validação OpenAPI), list_environments (descoberta de ambientes).
  • Validação Zod previne parâmetros inválidos, capturando erros antes das chamadas de API.
  • Configuração específica para cada ferramenta: Claude Code via ~/.claude/settings.json, Cursor via .cursor/mcp.json.
  • Ambiente de produção exige tratamento de erros, retentativas, rate limiting e armazenamento seguro de credenciais.

Perguntas Frequentes

O que é MCP em IA?

MCP (Model Context Protocol) é um protocolo padronizado para agentes de IA acessarem ferramentas e dados externos, funcionando como um sistema de plugins.

Como crio um servidor MCP para Apidog?

Instale @modelcontextprotocol/sdk, defina as ferramentas com Zod, implemente handlers que usam a API Apidog e conecte via StdioServerTransport.

Posso usar com Cursor?

Sim — configure .cursor/mcp.json na raiz do projeto. O mesmo servidor MCP funciona em Claude Code, Cursor e outros clientes MCP.

Quais ferramentas devo expor?

Comece com run_test (execução de testes), validate_schema (validação OpenAPI) e list_environments (consulta de ambientes).

O servidor MCP Apidog é pronto para produção?

O tutorial fornece um ponto de partida. Para produção, implemente retentativas, rate limit, tratamento de erros e armazene a chave de API com segurança.

Preciso de uma API key do Apidog?

Sim, defina APIDOG_API_KEY como variável de ambiente. O servidor usa essa chave para autenticar as requisições.

Posso compartilhar este servidor MCP com a equipe?

Sim. Publique como pacote npm privado, documente variáveis de ambiente e forneça exemplos de configuração MCP.

Top comments (0)