요약 (TL;DR)
run_test, validate_schema, list_environments 세 가지 도구를 노출하는 TypeScript MCP 서버를 빠르게 구축하세요. Claude Code는 ~/.claude/settings.json, Cursor는 .cursor/mcp.json에 MCP 서버를 등록합니다. 그러면 AI 에이전트가 채팅 인터페이스 내에서 Apidog 테스트 실행, OpenAPI 스키마 검증, 환경 목록 조회를 자동화할 수 있습니다. 전체 소스 코드는 약 150줄이며 @modelcontextprotocol/sdk 패키지를 활용합니다.
Claude Code, Cursor 및 기타 AI 에이전트가 채팅 인터페이스를 벗어나지 않고 Apidog API 테스트를 실행하고, 스키마를 검증하며, 응답을 비교할 수 있도록 MCP 서버를 직접 구축해보세요.
💡 실전 배경
코딩 세션 중에 AI 에이전트가 API 엔드포인트를 완성했다면, 복사-붙여넣기 없이 채팅에서 바로 Apidog 테스트를 실행하고 결과를 즉시 받아보고 싶을 것입니다.
이것이 바로 Model Context Protocol (MCP)의 역할입니다. MCP는 AI 에이전트가 표준 인터페이스로 외부 도구에 접근할 수 있도록 하며, Apidog MCP 서버를 사용하면 컨텍스트 전환 없이 테스트 실행, 스키마 검증, 환경 조회가 가능합니다.
MCP란 무엇인가요?
MCP(Model Context Protocol)는 AI 에이전트가 외부 도구 및 데이터 소스에 접근할 수 있도록 하는 표준 프로토콜입니다. Claude Code, Cursor 등 MCP 호환 클라이언트에서 동작하는 플러그인 시스템과 유사합니다.
MCP 서버는 도구(에이전트가 호출할 수 있는 함수)와 리소스(에이전트가 읽을 수 있는 데이터)를 노출합니다. 여기서는 API 테스트를 위한 Apidog MCP 서버의 도구 구현에 집중합니다.
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ AI 에이전트 │ │ MCP 서버 │ │ Apidog │
│ (Claude Code) │◄───────►│ (사용자 코드) │◄───────►│ API │
└─────────────────┘ JSON └──────────────────┘ HTTP └─────────────┘
1단계: 프로젝트 설정
새 TypeScript 프로젝트를 만듭니다.
mkdir apidog-mcp-server
cd apidog-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
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"]
}
package.json에 빌드 및 실행 스크립트 추가:
{
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
}
}
2단계: MCP 서버 스켈레톤 생성
src/index.ts 파일을 생성 후 기본 MCP 서버를 초기화합니다.
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: "AI 에이전트를 위한 Apidog API 테스트 도구"
});
// 도구는 아래에 정의합니다
const transport = new StdioServerTransport();
await server.connect(transport);
이 코드는 MCP 서버를 생성하고 stdio를 통해 에이전트와 통신할 준비를 마칩니다.
3단계: run_test 도구 정의
src/index.ts에 API 테스트 실행용 도구를 추가합니다.
server.tool(
"run_test",
{
projectId: z.string().describe("Apidog 프로젝트 ID (프로젝트 URL에서 찾을 수 있음)"),
environmentId: z.string().optional().describe("선택적 환경 ID"),
testSuiteId: z.string().optional().describe("선택적 테스트 스위트 ID")
},
async ({ projectId, environmentId, testSuiteId }) => {
const apiKey = process.env.APIDOG_API_KEY;
if (!apiKey) {
return {
content: [{ type: "text", text: "오류: APIDOG_API_KEY 환경 변수가 설정되지 않았습니다" }]
};
}
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: `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: `요청 실패: ${error instanceof Error ? error.message : String(error)}` }]
};
}
}
);
도구 정의 구성
-
이름:
run_test– 에이전트가 호출할 때 사용할 명확한 이름 - 파라미터 스키마: Zod로 유효성 검증. 설명 추가 권장
- 핸들러: Apidog API 호출 및 결과 반환
4단계: validate_schema 도구 추가
OpenAPI 3.x 스키마의 유효성을 검증하는 도구를 추가하세요.
server.tool(
"validate_schema",
{
schema: z.object({}).describe("유효성 검사할 OpenAPI 3.x 스키마 객체"),
strict: z.boolean().optional().default(false).describe("엄격 모드 사용 여부")
},
async ({ schema, strict }) => {
const apiKey = process.env.APIDOG_API_KEY;
if (!apiKey) {
return {
content: [{ type: "text", text: "오류: APIDOG_API_KEY 환경 변수가 설정되지 않았습니다" }]
};
}
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: `유효성 검사 실패: ${JSON.stringify(result.errors, null, 2)}` }]
};
}
return {
content: [{
type: "text",
text: result.valid
? "스키마가 유효한 OpenAPI 3.x입니다"
: `경고: ${JSON.stringify(result.warnings, null, 2)}`
}]
};
} catch (error) {
return {
content: [{ type: "text", text: `유효성 검사 실패: ${error instanceof Error ? error.message : String(error)}` }]
};
}
}
);
5단계: list_environments 도구 추가
프로젝트의 테스트 환경 목록을 조회하는 도구를 구현합니다.
server.tool(
"list_environments",
{
projectId: z.string().describe("Apidog 프로젝트 ID")
},
async ({ projectId }) => {
const apiKey = process.env.APIDOG_API_KEY;
if (!apiKey) {
return {
content: [{ type: "text", text: "오류: APIDOG_API_KEY 환경 변수가 설정되지 않았습니다" }]
};
}
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: `API 오류: ${response.status} ${error}` }]
};
}
const environments = await response.json();
return {
content: [{
type: "text",
text: environments.length === 0
? "이 프로젝트에 대한 환경을 찾을 수 없습니다"
: environments.map((e: any) =>
`- ${e.name} (ID: ${e.id})${e.isDefault ? " [기본값]" : ""}`
).join("\n")
}]
};
} catch (error) {
return {
content: [{ type: "text", text: `요청 실패: ${error instanceof Error ? error.message : String(error)}` }]
};
}
}
);
6단계: 빌드 및 테스트
서버 빌드:
npm run build
간단한 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(`서버 출력: ${data}`);
});
server.stderr.on("data", (data) => {
console.error(`서버 오류: ${data}`);
});
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");
7단계: Claude Code 구성
MCP 서버를 Claude Code에 등록하세요.
~/.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"
}
}
}
}
Claude Code를 재시작한 뒤, "API 테스트 지원"을 요청하면 Apidog 도구가 나타나야 합니다.
예시 사용법 (Claude Code):
run_test 도구를 사용하여 Apidog 프로젝트에서 테스트 실행
프로젝트 ID: proj_12345
환경: staging
이 OpenAPI 스키마를 Apidog 규칙에 따라 검증해줘
[스키마 붙여넣기]
proj_12345 프로젝트의 모든 환경을 나열해줘
8단계: Cursor 구성
Cursor는 .cursor/mcp.json으로 MCP 서버를 연결합니다.
{
"mcpServers": {
"apidog": {
"command": "node",
"args": ["/absolute/path/to/apidog-mcp-server/dist/index.js"],
"env": {
"APIDOG_API_KEY": "your-api-key-here"
}
}
}
}
예시 사용법 (Cursor):
@apidog run_test projectId="proj_12345" environmentId="staging"
완전한 소스 코드
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: "AI 에이전트를 위한 Apidog API 테스트 도구"
});
// run_test 도구
server.tool(
"run_test",
{
projectId: z.string().describe("Apidog 프로젝트 ID"),
environmentId: z.string().optional().describe("환경 ID"),
testSuiteId: z.string().optional().describe("테스트 스위트 ID")
},
async ({ projectId, environmentId, testSuiteId }) => {
const apiKey = process.env.APIDOG_API_KEY;
if (!apiKey) {
return {
content: [{ type: "text", text: "오류: APIDOG_API_KEY가 설정되지 않았습니다" }]
};
}
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: `요청 실패: ${error instanceof Error ? error.message : String(error)}` }]
};
}
}
);
// validate_schema 도구
server.tool(
"validate_schema",
{
schema: z.object({}).describe("OpenAPI 스키마"),
strict: z.boolean().optional().default(false)
},
async ({ schema, strict }) => {
const apiKey = process.env.APIDOG_API_KEY;
if (!apiKey) {
return {
content: [{ type: "text", text: "오류: APIDOG_API_KEY가 설정되지 않았습니다" }]
};
}
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
? "스키마가 유효합니다"
: `문제: ${JSON.stringify(result.errors || result.warnings, null, 2)}`
}]
};
}
);
// list_environments 도구
server.tool(
"list_environments",
{
projectId: z.string().describe("Apidog 프로젝트 ID")
},
async ({ projectId }) => {
const apiKey = process.env.APIDOG_API_KEY;
if (!apiKey) {
return {
content: [{ type: "text", text: "오류: APIDOG_API_KEY가 설정되지 않았습니다" }]
};
}
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 ? " [기본값]" : ""}`
).join("\n")
}]
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
구축한 것
| 구성 요소 | 목적 |
|---|---|
| MCP 서버 | AI 에이전트를 Apidog API에 연결 |
run_test |
테스트 컬렉션을 프로그램적으로 실행 |
validate_schema |
배포 전 OpenAPI 오류 포착 |
list_environments |
사용 가능한 테스트 환경 검색 |
| Zod 유효성 검사 | 타입 안정성 파라미터 처리 |
| Stdio 트랜스포트 | 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()전에 정의되어 있는지 확인 - 서버가 오류 없이 시작되는지 (
node dist/index.js)
API 요청 401 오류
-
APIDOG_API_KEY환경 변수 설정 확인 - 공백, 따옴표 등 오타 없는지 확인
- Apidog 계정에서 API 접근 권한 확인
- 키를 curl로 직접 테스트
curl -H "Authorization: Bearer $APIDOG_API_KEY" https://api.apidog.com/v1/user
Zod 유효성 검사 오류
- 파라미터 이름과 스키마 일치 확인
- 필수 필드 누락 없는지 확인
- 선택 필드는
.optional()사용 - Zod 오류 메시지를 꼼꼼히 확인
TypeScript 컴파일 오류
- 모든 의존성 설치 (
npm install) - TypeScript 5.x 버전 확인 (
npx tsc --version) - dist 폴더 삭제 후 재빌드 (
rm -rf dist && npm run build) - 타입 불일치시 as 어설션 활용
MCP 서버 로컬에서 테스트하기
운영 배포 전, MCP 서버를 수동으로 stdio를 통해 검증하세요.
# 서버 시작
node dist/index.js
# 다른 터미널에서 도구 목록 요청
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
예상 출력:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{ "name": "run_test", "description": "...", "inputSchema": {...} },
{ "name": "validate_schema", "description": "...", "inputSchema": {...} },
{ "name": "list_environments", "description": "...", "inputSchema": {...} }
]
}
}
도구 호출 테스트:
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_environments","arguments":{"projectId":"your-project-id"}}}' | node dist/index.js
이제 AI 에이전트가 Apidog의 테스트 기능에 직접 접근할 수 있습니다.
브라우저 전환과 복사-붙여넣기 없이, 채팅에서 명령만 입력하면 결과를 받을 수 있습니다.
이것이 바로 MCP의 힘입니다.
AI 에이전트를 도메인별 도구로 확장해, 개발자의 반복 작업을 자동화하세요.
핵심 요약
MCP 서버는 AI 에이전트를 외부 API에 연결
한 번 구축하면 Claude Code, Cursor, 기타 MCP 호환 클라이언트에서 사용 가능세 가지 도구로 대부분의 API 테스트 요구 충족
실행(run_test), OpenAPI 유효성 검증(validate_schema), 환경 조회(list_environments)Zod 유효성 검증으로 잘못된 파라미터 사전 차단
타입 안정성으로 API 호출 전에 오류 포착도구별 구성
Claude Code는~/.claude/settings.json, Cursor는.cursor/mcp.json사용운영 환경에선 오류 처리 필수
재시도, 속도 제한, 안전한 키 저장소 등 보강 필요
자주 묻는 질문 (FAQ)
Q. AI에서 MCP란 무엇인가요?
A. MCP(Model Context Protocol)는 AI 에이전트가 외부 도구/데이터 소스에 접근할 수 있도록 하는 표준 프로토콜입니다. 플러그인 시스템과 유사합니다.
Q. Apidog용 MCP 서버는 어떻게 생성하나요?
A. @modelcontextprotocol/sdk 설치 → Zod로 도구 파라미터 정의 → Apidog API 호출하는 핸들러 작성 → StdioServerTransport로 연결
Q. Cursor와 함께 사용할 수 있나요?
A. 네, 프로젝트 루트의 .cursor/mcp.json에 MCP 서버 구성을 추가하면 Claude Code, Cursor 등에서 동일하게 동작합니다.
Q. 어떤 도구를 노출해야 하나요?
A. 최소한 run_test(테스트 실행), validate_schema(OpenAPI 검증), list_environments(환경 조회)를 구현하세요.
Q. Apidog MCP 서버는 운영 환경에 준비되었나요?
A. 튜토리얼 코드는 시작점입니다. 운영에서는 재시도, 속도 제한, 오류 처리, 안전한 API 키 저장을 반드시 추가하세요.
Q. Apidog API 키가 필요한가요?
A. 네. APIDOG_API_KEY를 환경 변수로 지정해야 하며, 서버는 이를 사용해 Apidog API를 인증합니다.
Q. 이 MCP 서버를 팀과 공유할 수 있나요?
A. 네. npm에 비공개 패키지로 배포하고, 환경 변수 및 구성 예시를 문서화하세요.
Top comments (0)