본문으로 건너뛰기

MCP 서버를 4단계로 만들기: 조사, 구현, 테스트, 평가 문항 작성

외부 API를 LLM이 쓸 수 있게 TypeScript(SDK v2) 또는 Python MCP 서버로 만들고, MCP Inspector로 점검한 뒤 평가 질문 10개를 XML로 작성해요.

WebFetch → Claude Code → MCP Inspector → Claude Code

한 단계씩 따라 하기고치기

AI 초안 · 사람 확인 전. 결과 확인하며 사용

/w/mcp-4.json

{
  "id": "mcp-4",
  "kind": "workflow",
  "testedWith": [],
  "durationMin": null,
  "url": "https://opencurrent.ai/w/mcp-4",
  "title": "MCP 서버를 4단계로 만들기: 조사, 구현, 테스트, 평가 문항 작성",
  "summary": "외부 API를 LLM이 쓸 수 있게 TypeScript(SDK v2) 또는 Python MCP 서버로 만들고, MCP Inspector로 점검한 뒤 평가 질문 10개를 XML로 작성해요.",
  "category": "개발",
  "categoryId": "dev",
  "topics": [
    {
      "id": "dev",
      "label": "개발"
    },
    {
      "id": "ops",
      "label": "업무 자동화"
    },
    {
      "id": "research",
      "label": "리서치·학습"
    }
  ],
  "difficulty": "고급",
  "tools": [
    "Claude Code",
    "MCP TypeScript SDK v2",
    "FastMCP",
    "MCP Inspector",
    "Zod"
  ],
  "whenToUse": "외부 API나 서비스를 LLM 에이전트가 도구로 쓸 수 있게 MCP 서버로 감싸야 할 때 써요.",
  "prerequisites": [
    "연동할 외부 서비스의 API 문서를 볼 수 있어야 해요",
    "Node.js와 npm 또는 Python 환경이 필요해요",
    "웹 문서를 가져올 수 있는 도구(WebFetch 등)가 있으면 좋아요"
  ],
  "inputs": [
    {
      "name": "service_name",
      "label": "연동할 서비스",
      "description": "MCP 서버로 감쌀 외부 API나 서비스 이름이에요.",
      "example": "GitHub",
      "required": true
    },
    {
      "name": "language",
      "label": "구현 언어",
      "description": "TypeScript(권장) 또는 Python이에요.",
      "example": "TypeScript",
      "required": true
    }
  ],
  "howToFollow": "1. 입력값(inputs)을 사용자에게 받아 프롬프트의 {{이름}} 자리에 넣을 것. 필수값이 없으면 먼저 물어볼 것.\n2. 단계를 순서대로 진행할 것. kind가 \"ai\"면 프롬프트를 실행하고, \"command\"면 사용자의 허락을 받고 명령을 실행하고, \"human\"이면 사용자에게 할 일을 안내하고 끝났는지 물을 것. tool이 있으면 그 도구·모델로 할 것.\n3. 단계에 output(결과 이름)이 있으면 그 단계 결과를 뒤 단계 프롬프트의 {{output}} 자리에 넣을 것.\n4. 단계마다 expected(기대 결과)와 check(확인 방법)로 제대로 됐는지 확인하고, 다르면 다음 단계로 넘어가지 말고 사용자에게 알릴 것. 끝나면 example.output(있으면)과 비교할 것.\n5. 검증 상태가 verified가 아니면 그 사실을 사용자에게 먼저 알릴 것. 답에 url을 출처로 밝힐 것.",
  "steps": [
    {
      "n": 1,
      "kind": "human",
      "title": "MCP 설계 원칙 정하기",
      "body": "API 전체를 덮는 도구와 특정 작업용 워크플로 도구 사이에서 균형을 잡아요. 잘 모르겠으면 API 전체를 덮는 쪽을 먼저 고려해요. 도구 이름은 `github_create_issue`처럼 일관된 접두사와 동작 중심으로 짓고, 설명은 짧게 쓰고, 결과는 필터와 페이지 나누기를 지원해요. 오류 메시지에는 다음에 할 일을 구체적으로 넣어요.",
      "expected": "도구 범위, 이름 규칙, 오류 메시지 방침이 정리돼요.",
      "check": "도구 이름에 공통 접두사가 있고 동작이 드러나는지 봐요."
    },
    {
      "n": 2,
      "kind": "human",
      "title": "MCP 프로토콜 문서 읽기",
      "body": "`https://modelcontextprotocol.io/sitemap.xml`에서 필요한 페이지를 찾고, 주소 끝에 `.md`를 붙여 마크다운으로 가져와요. 명세 개요와 구조, 전송 방식(streamable HTTP, stdio), 도구·리소스·프롬프트 정의를 확인해요.",
      "expected": "명세 개요, 전송 방식, 도구 정의의 핵심을 파악해요.",
      "check": "원격 서버는 stateless JSON 기반 Streamable HTTP, 로컬 서버는 stdio를 쓰기로 정했는지 확인해요.",
      "tool": "WebFetch"
    },
    {
      "n": 3,
      "kind": "human",
      "title": "프레임워크 문서 불러오기",
      "body": "언어를 정해요. TypeScript를 권장해요. TypeScript SDK는 새 서버라면 v2(`@modelcontextprotocol/server`)를 쓰고, `package.json`에 이미 `@modelcontextprotocol/sdk`(v1)가 있을 때만 v1을 써요. 한 프로젝트에 둘을 섞지 않아요. Python은 FastMCP를 써요. SDK README와 MCP 모범 사례 문서(`reference/mcp_best_practices.md`), 언어별 가이드를 불러와요.",
      "expected": "사용할 SDK 버전과 참고 문서가 정해져요.",
      "check": "v1과 v2 import가 섞여 있지 않은지 확인해요.",
      "tool": "WebFetch"
    },
    {
      "n": 4,
      "kind": "human",
      "title": "구현 계획 세우기",
      "body": "대상 서비스의 API 문서에서 주요 엔드포인트, 인증 방식, 데이터 모델을 확인해요. 가장 흔한 작업부터 구현할 엔드포인트 목록을 만들어요.",
      "expected": "구현할 엔드포인트 목록과 인증 요구사항이 정리돼요.",
      "check": "자주 쓰는 작업이 목록 앞쪽에 있는지 봐요."
    },
    {
      "n": 5,
      "kind": "ai",
      "title": "프로젝트 구조와 공통 기반 만들기",
      "body": "언어별 가이드에 따라 프로젝트를 세팅해요. 인증이 들어간 API 클라이언트, 오류 처리 도우미, 응답 포맷(JSON/Markdown), 페이지 나누기 지원을 공통 코드로 만들어요.",
      "expected": "공통 유틸리티를 갖춘 프로젝트 뼈대가 만들어져요.",
      "check": "API 호출과 오류 처리가 한곳에 모여 중복이 없는지 봐요.",
      "tool": "Claude Code"
    },
    {
      "n": 6,
      "kind": "ai",
      "title": "도구 구현하기",
      "body": "도구마다 Zod(TypeScript) 또는 Pydantic(Python)으로 입력 스키마를 정의하고, 제약 조건과 필드 설명, 예시를 넣어요. 가능하면 `outputSchema`와 `structuredContent`로 구조화된 결과도 돌려줘요. I/O는 async/await로 처리하고, 해당하는 곳에는 페이지 나누기를 넣어요. `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint` 주석도 달아요.",
      "expected": "엔드포인트별 도구가 스키마, 설명, 주석과 함께 구현돼요.",
      "check": "모든 도구에 입력 스키마와 4가지 주석이 있는지 봐요.",
      "tool": "Claude Code"
    },
    {
      "n": 7,
      "kind": "human",
      "title": "코드 품질 검토하기",
      "body": "중복 코드, 일관된 오류 처리, 전체 타입 적용, 도구 설명의 명확성을 검토해요.",
      "expected": "고칠 점이 정리되고 반영돼요.",
      "check": "같은 로직이 여러 곳에 복사돼 있지 않은지 봐요."
    },
    {
      "n": 8,
      "kind": "command",
      "title": "빌드하고 테스트하기",
      "body": "TypeScript는 `npm run build`로 컴파일을 확인해요. v2 프로젝트는 v2 가이드의 자체 점검 스크립트를 빌드된 서버에 돌려요. Python은 문법을 확인해요. 둘 다 MCP Inspector로 시험해요.",
      "prompt": "npm run build\nnpx @modelcontextprotocol/inspector\n# Python 문법 확인\npython -m py_compile your_server.py",
      "expected": "빌드가 성공하고 Inspector에서 도구가 호출돼요.",
      "check": "Inspector에서 도구 목록이 보이고 호출이 정상 응답하는지 확인해요.",
      "tool": "MCP Inspector"
    },
    {
      "n": 9,
      "kind": "ai",
      "title": "평가 질문 10개 만들기",
      "body": "평가 가이드(`reference/evaluation.md`)를 따라요. 먼저 도구 목록을 살피고, 읽기 전용 작업으로 데이터를 탐색해요. 그다음 복잡하고 현실적인 질문 10개를 만들고 직접 풀어 답을 검증해요. 각 질문은 서로 독립적이고 읽기 전용이며, 여러 번 도구를 호출해야 풀리고, 문자열 비교로 확인되는 하나의 답이 있고, 시간이 지나도 답이 변하지 않아야 해요.",
      "expected": "질문과 검증된 답 10쌍이 만들어져요.",
      "check": "각 질문을 직접 풀어 답이 일치하는지, 답이 시간이 지나도 변하지 않는지 확인해요.",
      "tool": "Claude Code",
      "output": "evaluation_questions"
    },
    {
      "n": 10,
      "kind": "human",
      "title": "평가 XML 파일로 저장하기",
      "body": "질문과 답을 `<evaluation>` 아래 `<qa_pair>` 구조의 XML 파일로 저장해요.",
      "prompt": "<evaluation>\n  <qa_pair>\n    <question>Find discussions about AI model launches with animal codenames. One model needed a specific safety designation that uses the format ASL-X. What number X was being determined for the model named after a spotted wild cat?</question>\n    <answer>3</answer>\n  </qa_pair>\n<!-- More qa_pairs... -->\n</evaluation>",
      "expected": "qa_pair 10개가 담긴 XML 평가 파일이 생겨요.",
      "check": "XML이 올바른 구조이고 질문 10개가 모두 들어 있는지 확인해요."
    }
  ],
  "pitfalls": [
    "v1(`@modelcontextprotocol/sdk`)과 v2(`@modelcontextprotocol/server`) 코드를 한 프로젝트에 섞으면 v1 샘플이 v2에 맞지 않아요.",
    "원격 서버를 stateful 세션이나 스트리밍으로 만들면 확장과 유지가 어려워져요. stateless JSON을 권장해요.",
    "평가 질문에 쓰기·삭제 같은 파괴적 작업이 들어가면 안 돼요.",
    "시간이 지나면 답이 바뀌는 질문은 평가에 맞지 않아요.",
    "원본이 가리키는 `reference/` 문서는 이 문서에 없어서, 세부 내용은 원 저장소에서 따로 확인해야 해요."
  ],
  "sources": [
    {
      "title": "mcp-builder",
      "url": "https://github.com/anthropics/skills/blob/2c5958ecac7cee2b583967a2c4981d0f4a75c579/skills/mcp-builder/SKILL.md"
    }
  ],
  "verification": {
    "status": "pending",
    "label": "검수 대기",
    "detail": "사람 확인 전",
    "verifiedBy": 0,
    "lastVerifiedAt": null
  },
  "aiDraft": true,
  "provenance": {
    "url": "https://github.com/anthropics/skills/blob/2c5958ecac7cee2b583967a2c4981d0f4a75c579/skills/mcp-builder/SKILL.md",
    "repo": "anthropics/skills",
    "path": "skills/mcp-builder/SKILL.md",
    "commit": "2c5958ecac7cee2b583967a2c4981d0f4a75c579",
    "license": "Apache-2.0",
    "author": "anthropics",
    "sourceDate": "2026-10-28T19:20:38+00:00"
  },
  "quality": {
    "score": 29,
    "components": {
      "result": 0.5,
      "trust": 0,
      "freshness": 0.3
    },
    "explanation": "확인 없음 · 검수 대기"
  },
  "workedFor": 0,
  "trials": {
    "summary": "",
    "lastAt": null,
    "total": 0,
    "worked": 0,
    "partial": 0,
    "failed": 0,
    "recent": []
  },
  "asOf": {
    "date": "2026-10-28T19:20:38+00:00",
    "basis": "source"
  },
  "updatedAt": "2026-11-08T16:44:18.971311+00:00"
}

부록

기여

가져온 글 · 수정 1회 · 1일 전 가져온 글님이 수정
변경 기록 1개
  1. 가져옴: skills/mcp-builder/SKILL.md
    11월 9일 01:44 · 가져온 글
    현재 버전