MCP 서버·Skill 개발 실습 예시

SKILL.md 한 장에서 시작해 MCP tool 등록, 스크립트 번들 Skill의 eval까지 직접 만들어 보는 실습 가이드  |  ← 레퍼런스 문서로 돌아가기

대상 버전Claude Docs · Claude Code 2026-06 기준 (MCP 스펙 2025-11-25 / 프로토콜 2025-06-18)
이 파일의 목적레퍼런스에서 다룬 개발 개념을 실제로 손에 익히도록, 난이도별 재현 가능한 실습으로 보완합니다
레퍼런스 문서develop_Manual.html — 각 시나리오에서 링크로 연결됩니다
작성일2026년 6월 27일
● 초급 Getting Started 폴더 하나와 마크다운 한 장으로 첫 Skill을 만들고 트리거되는지 확인한다
G-1 초급 최소 Skill 만들기
커밋 메시지를 매번 직접 다듬는 게 번거롭다. 변경된 내용을 보고 일관된 형식으로 커밋 메시지 초안을 잡아 주는 작은 Skill을 만들어, 현재 프로젝트에서 동작하게 하려 한다. 외부 서버나 SDK 없이 SKILL.md 한 장으로 끝내는 것이 목표다.
단계별 실행
  1. Skill 폴더 만들기

    프로젝트 루트에서 실행한다. 프로젝트 범위 Skill은 .claude/skills/<name>/ 아래에 둔다. 폴더 이름은 frontmatter의 name과 맞춰 commit-helper로 한다.

    mkdir -p .claude/skills/commit-helper
  2. SKILL.md 작성

    frontmatter의 name(소문자·숫자·하이픈, 64자 이내)과 description(무엇을·언제 쓰는지, 1024자 이내)이 필수다. description에는 Claude가 자동으로 골라 쓰도록 트리거가 될 단어("커밋", "commit")를 담는다. 본문의 !`git diff HEAD`는 전송 직전에 실행되어 그 출력이 인라인으로 끼워진다.

    cat > .claude/skills/commit-helper/SKILL.md <<'EOF'
    ---
    name: commit-helper
    description: 스테이징·작업 트리의 변경을 보고 Conventional Commits 형식의 커밋 메시지 초안을 작성한다. 사용자가 "커밋 메시지 써줘", "commit message" 등을 요청할 때 사용한다.
    ---
    
    # Commit Helper
    
    아래는 현재 작업 트리의 변경 사항이다.
    
    !`git diff HEAD`
    
    위 diff를 바탕으로 커밋 메시지를 작성한다.
    
    - 첫 줄은 `type(scope): summary` 형식(50자 이내).
    - type은 feat / fix / docs / refactor / test / chore 중에서 고른다.
    - 본문에는 무엇을, 왜 바꿨는지 1~3개 항목으로 설명한다.
    - 추측한 변경 사항은 적지 않는다. diff에 보이는 것만 근거로 삼는다.
    EOF
  3. 트리거 확인

    새 세션에서 Claude Code를 실행하고 자연어로 요청한다. description이 요청과 맞아떨어지면 Claude가 commit-helper Skill을 스스로 불러온다. 의도대로 떴는지, 다른 작업에서 불필요하게 끼어들지는 않는지 본다.

    > 지금 변경한 내용으로 커밋 메시지 초안 잡아줘
Skill은 점진적 공개로 로드된다. 평소에는 namedescription(약 100토큰)만 항상 올라가 있다가, 요청이 description과 맞으면 그때 SKILL.md 본문이 컨텍스트로 들어온다. 본문이 로드되는 순간 !`git diff HEAD`가 실행되어 그 출력이 본문 안에 채워지므로, Claude는 "지금 이 저장소의 실제 변경"을 근거로 메시지를 쓴다.
트리거가 안 될 때는 본문이 아니라 description부터 손본다. "무엇을 하는지 + 언제 쓰는지"를 3인칭으로 구체적으로 쓰고 사용자가 실제로 입력할 법한 단어를 넣는다. YAML이 깨지면 아예 로드되지 않으니 claude --debug로 파싱 결과를 확인한다. 개인 전역으로 쓰려면 같은 폴더 구조를 ~/.claude/skills/에 두면 된다.
● 중급 Daily Workflow Python SDK로 tool 하나를 가진 MCP 서버를 만들고 Claude Code에 연결한다
D-1 중급 MCP 서버에 tool 하나 추가 (Python)
Claude가 외부 함수 하나를 호출할 수 있게 하고 싶다. 예시로 get_weather라는 tool을 가진 최소 MCP 서버를 Python으로 만들어, stdio로 실행하고 claude mcp add로 등록한다. 전제: Python 3.10+와 가상환경이 준비돼 있고, 현재 프로젝트 폴더에서 작업한다.
단계별 실행
  1. SDK 설치

    공식 Python SDK 패키지를 설치한다. 가상환경 안에서 설치해야 이후 claude mcp add에 넘길 실행 명령이 그 환경의 인터프리터를 가리킬 수 있다.

    pip install mcp
  2. 서버에 tool 등록

    FastMCP를 쓰면 @mcp.tool() 데코레이터 하나로 함수가 tool이 된다. 함수 시그니처의 타입 힌트가 inputSchema로, docstring이 tool 설명으로 변환된다. Claude는 이 설명과 스키마를 보고 호출 여부와 인자를 정한다.

    # weather_server.py
    from mcp.server.fastmcp import FastMCP
    
    mcp = FastMCP("weather")
    
    @mcp.tool()
    def get_weather(city: str) -> str:
        """주어진 도시의 현재 날씨를 한 줄로 반환한다.
    
        Args:
            city: 날씨를 조회할 도시 이름 (예: "Seoul")
        """
        # 실제로는 외부 날씨 API를 호출한다. 여기서는 예시 값.
        return f"{city}: 맑음, 24도, 습도 40%"
    
    if __name__ == "__main__":
        mcp.run(transport="stdio")
  3. Inspector로 단독 점검

    Claude에 붙이기 전에 서버가 tool을 제대로 노출하는지 확인한다. MCP Inspector를 띄우면 브라우저에서 tools/list로 목록을, tools/call로 실제 호출 결과를 직접 테스트할 수 있다.

    npx @modelcontextprotocol/inspector python weather_server.py
  4. Claude Code에 연결

    -- 뒤에 서버 실행 명령을 그대로 적는다. stdio 전송이므로 Claude가 이 명령으로 서버 프로세스를 띄우고 표준입출력으로 JSON-RPC를 주고받는다. 등록 후 list·get으로 상태를 확인한다.

    claude mcp add weather -- python weather_server.py
    claude mcp list
    claude mcp get weather
연결 시 Claude(Host)는 이 서버와 1:1로 붙는 MCP Client를 띄우고 initializeprotocolVersioncapabilities를 협상한다. 이후 tools/listget_weather의 이름·설명·inputSchema를 받아 두고, 사용자의 요청이 날씨와 닿으면 tools/call{ "city": "Seoul" } 같은 인자를 보내 결과를 받아온다. tool은 별도 프로세스에서 실행되므로, Skill처럼 모델의 코드 실행 환경 안에서 도는 것이 아니다.
등록한 tool의 inputSchema는 매 요청마다 컨텍스트를 차지한다. 쓰지 않는 tool이 많은 서버를 늘 켜 두면 토큰만 새므로 필요할 때만 붙이거나 불필요한 tool은 비활성화한다. 또한 로컬 stdio 서버는 파일 삭제·명령 실행까지 할 수 있으니 신뢰할 수 있는 코드만 등록하고, tool 설명에 악성 지시를 심는 prompt injection에 주의한다. 프로젝트 단위로 팀과 공유하려면 .mcp.json에 정의를 커밋한다.
● 고급 Power User 스크립트와 레퍼런스를 번들한 Skill을 만들고 도구 권한을 좁힌 뒤 eval로 검증한다
P-1 고급 스크립트 번들 Skill + eval
팀에 "릴리스 노트 검증" 같은 결정론적 절차가 있다. 매번 모델이 즉흥적으로 판단하기보다, 검증 로직은 스크립트로 고정하고 상세 규칙은 별도 문서로 분리한 자기완결형 Skill로 패키징하려 한다. 더불어 Skill이 의도대로 트리거·동작하는지 eval로 점검한다. 전제: 코드 실행이 가능한 Claude Code 환경, skill-creator 플러그인 설치.
단계별 실행
  1. 번들 구조 잡기

    SKILL.md 옆에 scripts/reference/를 둔다. SKILL.md는 짧게(500줄 이내) 유지하고, 길어지는 규칙·예외 목록은 reference/*.md로 빼서 필요할 때만 읽도록 한다. 이렇게 분리하는 것이 점진적 공개의 핵심이다.

    .claude/skills/release-validator/
    ├── SKILL.md
    ├── scripts/
    │   └── validate.py
    └── reference/
        └── rules.md
  2. 검증 스크립트 작성

    판정 로직은 모델이 아니라 코드가 책임진다. 스크립트는 통과/실패와 사유만 출력하면 된다. 점진적 공개에서 스크립트는 코드 전체가 컨텍스트에 올라오지 않고, 실행 결과(출력)만 모델에게 전달된다.

    # scripts/validate.py
    import sys, re, pathlib
    
    def main(path: str) -> int:
        text = pathlib.Path(path).read_text(encoding="utf-8")
        errors = []
        if not re.search(r"^## \[\d+\.\d+\.\d+\]", text, re.M):
            errors.append("시맨틱 버전 헤딩(## [x.y.z])이 없습니다.")
        if "TODO" in text:
            errors.append("미완성 표시 'TODO'가 남아 있습니다.")
        if errors:
            print("FAIL")
            for e in errors:
                print(f" - {e}")
            return 1
        print("PASS")
        return 0
    
    if __name__ == "__main__":
        sys.exit(main(sys.argv[1]))
  3. SKILL.md에서 권한 좁히고 리소스 연결

    allowed-tools로 이 Skill이 쓸 수 있는 도구를 검증에 필요한 최소로 제한한다. 본문에는 스크립트 실행 방법만 간단히 적고, 세부 규칙은 reference/rules.md를 "필요할 때 읽으라"고 가리킨다.

    ---
    name: release-validator
    description: CHANGELOG/릴리스 노트가 팀 규칙(시맨틱 버전 헤딩, 미완성 표시 없음)을 지키는지 검증한다. 사용자가 릴리스 노트나 CHANGELOG 검증을 요청할 때 사용한다.
    allowed-tools: Bash, Read
    ---
    
    # Release Validator
    
    릴리스 노트를 검증하려면 아래 스크립트를 실행한다.
    
    ```
    python scripts/validate.py <파일경로>
    ```
    
    - 출력이 `PASS`면 통과를 알린다.
    - `FAIL`이면 출력된 사유를 그대로 사용자에게 전달한다.
    - 규칙의 배경과 예외 처리는 `reference/rules.md`를 읽고 판단한다.
  4. skill-creator로 eval 실행

    skill-creator 플러그인은 Skill 작성과 평가를 돕는다. eval로 다양한 요청에서 의도대로 트리거되는지, 스크립트 호출과 응답이 일관적인지 점검하고 결과에 따라 description이나 본문을 다듬는다.

    # (마켓플레이스 미등록 시 먼저) /plugin marketplace add anthropics/claude-plugins-official
    /plugin install skill-creator@claude-plugins-official
    # 이후 skill-creator의 안내에 따라 release-validator에 대한 eval을 실행
이 Skill은 점진적 공개 3단계로 로드된다.
· Level 1name + description(약 100토큰)만 항상 상주.
· Level 2 — 요청이 트리거되면 SKILL.md 본문(보통 5K토큰 미만)이 로드.
· Level 3 — 본문이 가리킬 때에만 reference/rules.md를 읽고, scripts/validate.py는 코드가 아니라 실행 출력만 컨텍스트로 들어온다.
덕분에 규칙이 길고 로직이 복잡해도 평소 컨텍스트 비용은 메타데이터 수준으로 유지된다.
자유도는 일부러 낮춘 설계다. 결과가 정해져야 하는 검증은 텍스트 지시(자유도 높음)보다 스크립트(자유도 낮음)에 맡겨야 재현성이 생긴다. allowed-tools로 권한을 좁히면 의도치 않은 파일 수정·네트워크 접근을 막을 수 있다. 팀 배포는 .claude/skills를 git에 커밋하거나 플러그인 마켓플레이스(/plugin marketplace add <repo>)로 배포한다. 단, Skill은 Anthropic 제품 전용이라 다른 클라이언트에서는 재사용되지 않는다.

Claude Docs · Claude Code 2026-06 기준 (MCP 스펙 2025-11-25 / 프로토콜 2025-06-18) | 2026년 6월 27일 작성
← 개발 레퍼런스