DEV Community

Cover image for Hướng Dẫn Tạo MCP Server Cho AI Agent Kiểm Thử API Hiệu Quả
Sebastian Petrus
Sebastian Petrus

Posted on • Originally published at apidog.com

Hướng Dẫn Tạo MCP Server Cho AI Agent Kiểm Thử API Hiệu Quả

Tóm tắt

Xây dựng một máy chủ MCP bằng TypeScript để hiển thị ba công cụ: run_test, validate_schemalist_environments. Cấu hình nó trong ~/.claude/settings.json cho Claude Code hoặc .cursor/mcp.json cho Cursor. Các tác nhân AI của bạn sau đó có thể chạy các bài kiểm tra Apidog, xác thực lược đồ OpenAPI và tìm nạp môi trường mà không cần rời khỏi giao diện trò chuyện. Mã nguồn đầy đủ khoảng 150 dòng và sử dụng gói @modelcontextprotocol/sdk.

Dùng thử Apidog ngay hôm nay

Xây dựng một máy chủ MCP cho phép Claude Code, Cursor và các tác nhân AI khác chạy các bài kiểm tra API Apidog, xác thực lược đồ và so sánh phản hồi, tất cả mà không cần rời khỏi giao diện trò chuyện của chúng.

💡 Bạn đang ở giữa một phiên viết mã. Tác nhân AI của bạn vừa hoàn thành việc xây dựng một điểm cuối API. Thay vì sao chép mã, mở Apidog, tạo một bộ sưu tập kiểm tra và chạy xác thực thủ công, bạn muốn gõ một lệnh và nhận lại kết quả.

MCP (Model Context Protocol) cho phép các tác nhân AI truy cập các công cụ bên ngoài thông qua một giao diện chuẩn hóa. Khi xây dựng một máy chủ MCP cho Apidog, tác nhân AI có thể chạy kiểm thử API, xác thực lược đồ và tìm nạp môi trường dễ dàng hơn.

MCP là gì?

MCP (Model Context Protocol) là một giao thức để các tác nhân AI truy cập các công cụ và nguồn dữ liệu bên ngoài. Bạn có thể coi nó như một hệ thống plugin cho Claude Code, Cursor và các máy khách MCP khác.

Một máy chủ MCP sẽ hiển thị các công cụ (hàm mà tác nhân có thể gọi) và tài nguyên (dữ liệu mà tác nhân có thể đọc). Máy chủ MCP Apidog của bạn sẽ cung cấp các công cụ kiểm thử API.

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

Bước 1: Thiết lập dự án

Tạo một dự án TypeScript mới:

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

Tạo 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

Thêm script build/start vào package.json:

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

Bước 2: Tạo khung máy chủ MCP

Tạo file 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"
});

// Định nghĩa các tool ở đây

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

Khung này sẽ tạo một máy chủ MCP và kết nối với kênh stdio, xử lý giao tiếp với AI agent.

Bước 3: Định nghĩa công cụ run_test

Thêm công cụ đầu tiên vào src/index.ts:

// Tool: run_test
server.tool(
  "run_test",
  {
    projectId: z.string().describe("Apidog project ID (found in project URL)"),
    environmentId: z.string().optional().describe("Optional environment ID for test execution"),
    testSuiteId: z.string().optional().describe("Optional test suite ID to run specific suite")
  },
  async ({ projectId, environmentId, testSuiteId }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY environment variable not set"
        }]
      };
    }

    // Build API URL
    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: `API Error: ${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: `Request failed: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Lưu ý:

  • Đặt tên công cụ rõ ràng (run_test)
  • Sử dụng Zod để xác thực params
  • Xử lý lỗi API rõ ràng

Bước 4: Thêm công cụ validate_schema

Thêm công cụ xác thực lược đồ OpenAPI:

// Tool: validate_schema
server.tool(
  "validate_schema",
  {
    schema: z.object({}).describe("OpenAPI 3.x schema object to validate"),
    strict: z.boolean().optional().default(false).describe("Enable strict mode for additional checks")
  },
  async ({ schema, strict }) => {
    const apiKey = process.env.APIDOG_API_KEY;
    if (!apiKey) {
      return {
        content: [{
          type: "text",
          text: "Error: APIDOG_API_KEY environment variable not set"
        }]
      };
    }

    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: `Validation failed: ${JSON.stringify(result.errors, null, 2)}`
          }]
        };
      }

      return {
        content: [{
          type: "text",
          text: result.valid
            ? "Schema is valid OpenAPI 3.x"
            : `Warnings: ${JSON.stringify(result.warnings, null, 2)}`
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Validation failed: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Bước 5: Thêm công cụ list_environments

Thêm công cụ liệt kê môi trường kiểm thử:

// 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 environment variable not set"
        }]
      };
    }

    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: `API Error: ${response.status} ${error}`
          }]
        };
      }

      const environments = await response.json();
      return {
        content: [{
          type: "text",
          text: environments.length === 0
            ? "No environments found for this project"
            : environments.map((e: any) =>
                `- ${e.name} (ID: ${e.id})${e.isDefault ? " [default]" : ""}`
              ).join("\n")
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: `Request failed: ${error instanceof Error ? error.message : String(error)}`
        }]
      };
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

Bước 6: Xây dựng và kiểm tra

Build code:

npm run build
Enter fullscreen mode Exit fullscreen mode

Test máy chủ với một client MCP đơn giản (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}`);
});

// Gửi thông điệp test
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

Bước 7: Cấu hình cho Claude Code

Thêm máy chủ MCP vào cấu hình của Claude Code:

Tạo hoặc sửa ~/.claude/settings.json:

{
  "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

Khởi động lại Claude Code. Các công cụ Apidog sẽ xuất hiện khi bạn yêu cầu kiểm thử API.

Cách sử dụng trong Claude Code:

Use the run_test tool to run tests on my Apidog project.
Project ID: proj_12345
Environment: staging
Enter fullscreen mode Exit fullscreen mode
Validate this OpenAPI schema against Apidog rules:
[paste schema]
Enter fullscreen mode Exit fullscreen mode
List all environments for project proj_12345
Enter fullscreen mode Exit fullscreen mode

Bước 8: Cấu hình cho Cursor

Cursor sử dụng cấu hình MCP tương tự. Tạo .cursor/mcp.json trong dự án của bạn:

{
  "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

Cách sử dụng trong Cursor:

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

Mã nguồn hoàn chỉnh

Dưới đây là file src/index.ts hoàn chỉnh:

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?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: `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?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 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?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

Những gì bạn đã xây dựng

Thành phần Mục đích
Máy chủ MCP Kết nối các tác nhân AI với API Apidog
run_test Thực thi các bộ sưu tập kiểm tra theo lập trình
validate_schema Bắt lỗi OpenAPI trước khi triển khai
list_environments Khám phá các môi trường kiểm tra có sẵn
Xác thực Zod Xử lý tham số an toàn kiểu
Truyền tải Stdio Hoạt động với Claude Code, Cursor, bất kỳ máy khách MCP nào

Các bước tiếp theo

Mở rộng máy chủ:

  • Thêm công cụ compare_responses để so sánh kết quả kiểm tra giữa các môi trường
  • Thêm get_test_history để truy xuất lịch sử kiểm tra
  • Thêm trigger_mock_server để khởi động/dừng các endpoint giả lập

Lưu ý khi triển khai thực tế:

  • Thêm logic retry cho các request mạng không ổn định
  • Triển khai giới hạn tốc độ để tránh bị throttle bởi API
  • Thêm logging để gỡ lỗi công cụ
  • Lưu khóa API ở kho bảo mật, không dùng biến môi trường sản xuất

Chia sẻ với nhóm:

  • Xuất bản npm package riêng: @your-org/apidog-mcp-server
  • Tài liệu hóa biến môi trường bắt buộc
  • Kèm file cấu hình MCP mẫu cho các client phổ biến

Khắc phục sự cố thường gặp

Máy chủ MCP không tải trong Claude Code:

  • Đảm bảo đường dẫn trong ~/.claude/settings.json là tuyệt đối
  • Kiểm tra node có trong PATH: which node
  • Đảm bảo file dist/index.js tồn tại: ls -la dist/
  • Xem log MCP của Claude Code để tìm lỗi

Công cụ không xuất hiện sau khi cấu hình:

  • Khởi động lại hoàn toàn Claude Code
  • Chạy lại npm run build để TypeScript biên dịch code mới nhất
  • Đảm bảo định nghĩa đủ 3 tool trước server.connect()
  • Chạy thử node dist/index.js kiểm tra server khởi động không lỗi

Yêu cầu API lỗi 401:

  • Kiểm tra APIDOG_API_KEY đã set đúng trong cấu hình
  • Không có dấu cách hoặc dấu ngoặc kép thừa quanh API key
  • Tài khoản Apidog đã bật truy cập API
  • Kiểm tra key thủ công: 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

Lỗi xác thực Zod:

  • Tên tham số phải khớp lược đồ
  • Trường bắt buộc phải có, không sai chính tả
  • Trường tùy chọn dùng .optional()
  • Đọc kỹ thông báo lỗi Zod để biết trường nào sai

Lỗi biên dịch TypeScript:

  • Chạy npm install để đảm bảo đủ dependency
  • Kiểm tra version TypeScript: npx tsc --version (>=5.x)
  • Xóa folder dist và build lại: rm -rf dist && npm run build
  • Kiểm tra kiểu dữ liệu trả về từ fetch, thêm assert nếu cần

Kiểm tra máy chủ MCP của bạn cục bộ

Trước khi triển khai production, kiểm tra máy chủ MCP local:

Test thủ công với stdio:

# Start the server
node dist/index.js

# In another terminal, send a test message
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
Enter fullscreen mode Exit fullscreen mode

Output mẫu:

{
  "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

Test gọi công cụ cụ thể:

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

Các tác nhân AI của bạn giờ đã có quyền truy cập trực tiếp các khả năng kiểm thử của Apidog, không cần chuyển đổi giữa chat và browser, không phải chạy test thủ công nữa.

Những điểm chính

  • Máy chủ MCP kết nối các tác nhân AI với API bên ngoài — Xây dựng một lần, dùng được trên Claude Code, Cursor, và bất kỳ client MCP nào.
  • Ba công cụ đáp ứng hầu hết nhu cầu kiểm thử APIrun_test cho thực thi test, validate_schema xác thực OpenAPI, list_environments khám phá môi trường.
  • Xác thực Zod giúp ngăn lỗi tham số — Định nghĩa tool an toàn kiểu, bắt lỗi trước khi gọi API.
  • Cấu hình chuyên biệt cho từng công cụ — Claude Code dùng ~/.claude/settings.json, Cursor dùng .cursor/mcp.json.
  • Triển khai thực tế cần xử lý lỗi — Thêm retry, rate limit, quản lý key bảo mật trước khi production.

Câu hỏi thường gặp

MCP trong AI là gì?

MCP (Model Context Protocol) là một giao thức chuẩn hóa để các tác nhân AI truy cập công cụ và nguồn dữ liệu bên ngoài, coi như một hệ plugin cho tác nhân AI.

Cách tạo máy chủ MCP cho Apidog?

Cài @modelcontextprotocol/sdk, định nghĩa tool sử dụng Zod, hiện thực handler gọi API Apidog, kết nối bằng StdioServerTransport.

Có dùng được với Cursor không?

Có. Thêm cấu hình MCP server vào file .cursor/mcp.json trong root dự án. Một máy chủ dùng được cho cả Claude Code, Cursor, hoặc client MCP khác.

Nên hiển thị tool nào?

Bắt đầu với run_test để chạy bộ test, validate_schema xác thực OpenAPI, list_environments lấy danh sách môi trường test.

Máy chủ MCP Apidog đã production ready chưa?

Đây là mã tham khảo. Nên bổ sung retry, rate limit, xử lý lỗi, lưu API key an toàn trước khi dùng production.

Có cần API key Apidog không?

Cần. Đặt APIDOG_API_KEY làm biến môi trường cho máy chủ MCP.

Có thể chia sẻ máy chủ MCP này cho team không?

Có. Đóng gói npm private, tài liệu hóa biến môi trường cần thiết, kèm cấu hình mẫu cho client phổ biến.


Dùng thử Apidog ngay hôm nay: https://apidog.com/?utm_source=dev.to&utm_medium=wanda&utm_content=n8n-post-automation

Top comments (0)