DEV Community

Cover image for AIエージェントAPIテスト機能を備えたMCPサーバーの構築方法
Akira
Akira

Posted on • Originally published at apidog.com

AIエージェントAPIテスト機能を備えたMCPサーバーの構築方法

要点

TypeScriptでMCPサーバーを構築し、run_testvalidate_schemalist_environmentsの3つのツールを公開します。Claude Codeの場合は~/.claude/settings.json、Cursorの場合は.cursor/mcp.jsonで設定します。これにより、AIエージェントはチャットインターフェースを離れることなく、Apidogテストの実行、OpenAPIスキーマの検証、環境の取得が可能になります。全ソースコードは約150行で、@modelcontextprotocol/sdkパッケージを使用しています。

今すぐApidogを試す

Claude Code、Cursor、およびその他のAIエージェントが、チャットインターフェースを離れることなく、Apidog APIテストの実行、スキーマの検証、応答の比較を行えるMCPサーバーを構築します。

💡 ユースケース例:

AIエージェントがAPIエンドポイントの構築を終えた後、コマンド一発でApidogテストの実行・検証が可能。Apidogを手動で開く必要はありません。

これこそが、モデルコンテキストプロトコル(MCP)が実現することです。MCPは、AIエージェントが標準化されたインターフェースを介して外部ツールにアクセスすることを可能にします。Apidog用のMCPサーバーを構築すれば、AIエージェントはコンテキストを切り替えることなく、テストの実行、スキーマの検証、環境の取得を行うことができます。

MCPとは何か?

MCP(モデルコンテキストプロトコル)は、AIエージェントが外部ツールやデータソースにアクセスするためのプロトコルです。Claude Code、Cursor、およびその他のMCP互換クライアント間で動作するプラグインシステムと考えることができます。

MCPサーバーは、ツール(エージェントが呼び出せる関数)とリソース(エージェントが読み取れるデータ)を公開します。Apidog MCPサーバーは、APIテスト用のツールを公開します。

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

ステップ1: プロジェクトのセットアップ

新しい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

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

package.jsonにビルド&起動スクリプトを追加:

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

ステップ2: MCPサーバーのスケルトンを作成する

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

// 後でツールを定義

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

これでMCPサーバーが標準入出力(stdio)トランスポートにバインドされ、AIエージェントと通信できるようになります。

ステップ3: run_testツールの定義

APIテストコレクションを実行するツールを追加します。

// 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"
        }]
      };
    }

    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

ステップ4: validate_schemaツールの追加

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

ステップ5: list_environmentsツールの追加

利用可能なテスト環境を取得するツールを追加します。

// 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

ステップ6: ビルドとテスト

ビルドします。

npm run build
Enter fullscreen mode Exit fullscreen mode

MCPクライアントでローカルテストを行うには、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}`);
});

// Send a test message
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

ステップ7: Claude Codeの構成

~/.claude/settings.jsonにMCPサーバーを追加します:

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

Claude Codeを再起動し、APIテストのヘルプを求めるとApidogツールが利用可能になります。

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

ステップ8: Cursorの構成

Cursorでは、プロジェクト直下に.cursor/mcp.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

Cursorでの使用例:

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

完全なソースコード

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

構築したもの

コンポーネント 目的
MCPサーバー AIエージェントとApidog APIを連携させる
run_test テストコレクションをプログラムで実行する
validate_schema デプロイ前にOpenAPIエラーを捕捉する
list_environments 利用可能なテスト環境を検出する
Zod検証 型安全なパラメータ処理
標準入出力トランスポート Claude Code、Cursor、任意のMCPクライアントで動作する

次のステップ

サーバーの拡張:

  • 環境間のテスト結果を比較するcompare_responsesツールを追加
  • 過去のテスト実行履歴を取得するget_test_historyを追加
  • モックエンドポイントを開始/停止するtrigger_mock_serverを追加

本番環境での考慮事項:

  • 不安定なネットワークリクエストのためのリトライロジックを追加
  • APIスロットリングを避けるためにレート制限を実装
  • 失敗したツール呼び出しのデバッグのためにログを追加
  • APIキーを環境変数の代わりにセキュアなボールトに保存

チームとの共有:

  • @your-org/apidog-mcp-serverとしてnpmに公開
  • 必要な環境変数を文書化
  • 一般的なクライアント向けのMCP設定例を含める

一般的な問題のトラブルシューティング

Claude CodeでMCPサーバーがロードされない場合:

  • ~/.claude/settings.json内のパスが絶対パスであることを確認
  • nodeコマンドがPATHに存在するか: which node
  • ビルド済みdist/index.jsが存在するか: ls -la dist/
  • Claude CodeのMCPログでエラーを確認

設定後にツールが表示されない場合:

  • Claude Codeを完全に再起動
  • npm run buildでTypeScriptがコンパイルされているか確認
  • server.connect()の前に3つすべてのツールが定義されていることを確認
  • サーバーが正常に起動するか: node dist/index.js

APIリクエストが401で失敗する場合:

  • APIDOG_API_KEYが正しく設定されているか確認
  • キー値の余分なスペースや引用符を除去
  • ApidogアカウントでAPIアクセスが有効か確認
  • キーを手動でテスト: 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

Zod検証エラーの場合:

  • パラメータ名がスキーマと一致しているか
  • 必須フィールドが入力されているか
  • オプションフィールドは.optional()を使っているか
  • エラーメッセージの内容を確認

TypeScriptコンパイルエラーの場合:

  • すべての依存をnpm installでインストール
  • TypeScriptのバージョン確認: npx tsc --version(5.x推奨)
  • rm -rf dist && npm run buildで再ビルド
  • 型不一致発生時はas型アサーションを活用

MCPサーバーをローカルでテストする

本番展開前に、ローカルでサーバーを手動テストできます。

標準入出力での動作確認:

# サーバー起動
node dist/index.js

# 別ターミナルからツール一覧リクエスト
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
Enter fullscreen mode Exit fullscreen mode

期待される出力例:

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

ツール呼び出しテスト:

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

→ これでAIエージェントから直接Apidogテスト機能を利用できます。チャットとブラウザ間のコピー&ペーストや手動テストは不要です。

MCPの力でAIエージェントをドメイン固有ツールで強化し、より高速な開発・フィードバックを実現しましょう。

主要なポイント

  • MCPサーバーはAIエージェントと外部APIを連携

     一度構築すれば、Claude Code、Cursor、その他のMCP互換クライアントで利用可能

  • 3つのツールでAPIテストニーズをカバー

    実行にはrun_test、OpenAPI検証にはvalidate_schema、環境検出にはlist_environments

  • Zod検証で不正パラメータを防止

    型安全なツール定義によりAPI呼び出し前のエラーを捕捉

  • 設定ファイルはクライアントごとに異なる

    Claude Codeは~/.claude/settings.json、Cursorは.cursor/mcp.jsonを利用

  • 本番運用ではエラーハンドリング必須

    リトライロジック、レート制限、セキュアなキー保存を追加してから運用

FAQ

AIにおけるMCPとは?

MCP(モデルコンテキストプロトコル)は、AIエージェントが外部ツールやデータソースにアクセスできるようにする標準化されたプロトコルです。AIエージェント用のプラグインシステムと考えることができます。

Apidog用のMCPサーバーを作成するには?

@modelcontextprotocol/sdkをインストールし、Zod検証でツールを定義し、Apidog APIを呼び出すハンドラーを実装し、StdioServerTransport経由で接続します。

Cursorで利用できますか?

はい。プロジェクトルートの.cursor/mcp.jsonにMCPサーバー設定を追加してください。同じサーバーがClaude Code、Cursor、その他MCPクライアントで利用可能です。

どのようなツールを公開すべき?

まずはテストコレクション実行用run_test、OpenAPI検証用validate_schema、利用可能な環境取得用list_environmentsが基本です。

Apidog MCPサーバーは本番対応?

チュートリアルコードはスタートポイントです。本番利用時はリトライ、レート制限、エラー処理、セキュアなAPIキー保存などを実装してください。

Apidog APIキーは必要?

はい。APIDOG_API_KEYを環境変数として設定してください。サーバーはこれを使ってAPIリクエストを認証します。

このMCPサーバーをチームで共有できますか?

はい。プライベートnpmパッケージ化、必須環境変数やMCP設定例のドキュメント化を行いましょう。

Top comments (0)