MCP·Skill 운영 실습 예시

연결 장애 진단부터 트리거 디버깅, 보안 감사 후 팀 배포까지 — 운영 단계에서 실제로 마주치는 문제를 난이도순으로 따라가며 익힌다.  |  ← 레퍼런스 문서로 돌아가기

대상 버전/범위Claude Docs · Claude Code 2026-06 기준 (MCP 스펙 2025-11-25 / 프로토콜 2025-06-18)
이 파일의 목적운영 레퍼런스의 진단·배포 절차를 재현 가능한 시나리오로 구체화
레퍼런스 문서operations_Manual.html — 각 시나리오에서 링크로 연결됩니다
작성일2026년 6월 27일
● 초급 Getting Started 등록한 MCP 서버가 동작하지 않을 때 상태부터 로그까지 차근차근 짚어 나가는 첫 진단
G-1 초급 MCP 서버가 연결 안 될 때
claude mcp add로 로컬 stdio 서버를 방금 등록했는데, 대화 중에 그 서버의 도구가 전혀 호출되지 않는다. 등록은 됐는지, 프로세스가 제대로 떠 있는지, 어디서 막혔는지 확인하고 싶다. 추측 대신 상태 → 직접 실행 → 로그 순서로 좁혀 나간다.
단계별 실행
  1. 등록 상태와 연결 여부 확인

    먼저 claude mcp list로 등록된 서버 목록과 연결 상태를 본다. 이름이 보이지 않으면 등록 자체가 실패한 것이고, 이름은 있으나 연결에 실패했다면 명령·인자·전송 방식 문제다. claude mcp get <name>으로 실제 등록된 command/args/scope를 확인한다.

    claude mcp list
    claude mcp get my-server
  2. MCP Inspector로 서버를 직접 실행해 테스트

    Claude를 거치지 않고 서버를 단독으로 띄워 본다. Inspector는 등록 정보와 똑같은 실행 명령을 받아 서버를 기동하고, tools/list·resources·prompts를 직접 호출해 응답을 보여 준다. 여기서 도구 목록이 정상적으로 나오면 서버는 멀쩡하고 등록 설정 쪽이 문제다.

    npx @modelcontextprotocol/inspector python my_server.py
  3. 로그를 tail로 따라가며 실패 지점 확인

    Inspector에서도 서버가 죽거나 응답이 없다면 로그를 본다. macOS에서 Claude Desktop의 MCP 로그는 ~/Library/Logs/Claude/mcp*.log로 쌓인다. 실행 중 새로 들어오는 줄을 보려고 tail -f로 따라가며 다시 연결을 시도해, 초기화 단계에서 어떤 오류가 나는지 잡아낸다.

    tail -f ~/Library/Logs/Claude/mcp*.log
MCP 클라이언트는 서버와 연결할 때 initialize 요청/응답으로 protocolVersioncapabilities를 협상한 뒤에야 tools/list로 도구 목록을 받아 온다. 이 초기화 핸드셰이크가 실패하면 도구는 하나도 노출되지 않는다. 그래서 "상태 → 단독 실행 → 로그" 순서로 보면, 협상 단계와 서버 자체 동작을 분리해 어느 쪽이 깨졌는지 가려낼 수 있다.
대부분의 stdio 서버 연결 실패는 실행 환경 차이에서 온다. 등록한 command가 PATH에 없거나, 가상환경 밖의 인터프리터를 가리키거나, 상대 경로를 써서 실행 디렉터리에 따라 깨지는 경우가 흔하다. claude mcp get에 찍힌 명령을 터미널에 그대로 붙여 손으로 실행해 보면 원인이 빠르게 드러난다.
● 중급 Daily Workflow 만들어 둔 Skill이 정작 필요한 순간에 자동으로 불려 나오지 않을 때의 트리거 디버깅
D-1 중급 Skill이 트리거되지 않을 때
.claude/skills/에 SKILL.md를 두고 작업을 시켰는데, 분명 해당 Skill이 다뤄야 할 요청인데도 Claude가 그 절차를 쓰지 않고 그냥 일반적으로 답한다. 파일은 인식됐는지, description이 발화와 맞물리는지, 호출 자체는 되는지를 하나씩 분리해 확인한다.
단계별 실행
  1. description에 사용자 발화 키워드가 들어 있는지 점검

    Skill 자동 호출은 frontmatter의 description만 보고 결정된다. 본문은 트리거된 뒤에야 로드되므로, "무엇을 + 언제 사용"이 description에 없으면 절대 불려 나오지 않는다. 사용자가 실제로 쓰는 표현(예: "보고서를 엑셀로", "PR 리뷰")이 description에 3인칭으로 구체적으로 담겼는지 확인한다.

    ---
    name: excel-report
    description: Generates .xlsx spreadsheets from tabular data.
      Use when the user asks to export results to Excel, build a
      report sheet, or convert a table into a spreadsheet.
    ---
  2. claude --debug로 YAML 파싱 확인

    description이 멀쩡해 보여도 frontmatter YAML이 깨졌으면 Skill은 메타데이터 단계에서 아예 로드되지 않는다. claude --debug로 띄우면 Skill을 읽어 들이는 과정과 YAML 파싱 결과가 로그에 찍힌다. 들여쓰기 오류, 누락된 --- 구분선, 64자/1024자 제한 위반 등을 여기서 잡는다.

    claude --debug
  3. 직접 호출로 격리 테스트

    로드는 됐지만 자동 트리거가 안 되는지, 아니면 Skill 본문 자체에 문제가 있는지 가르려면 슬래시 명령으로 직접 불러 본다. 직접 호출에서는 잘 동작하는데 자연어로는 안 불려 나온다면 원인은 본문이 아니라 description의 트리거 표현에 있다.

    /excel-report 분기 매출 표를 스프레드시트로 만들어줘
  4. description 수정 후 재확인

    격리 테스트로 "본문은 정상, 트리거가 문제"임이 확인되면 description을 손본다. 사용자가 실제로 쓰는 동사·명사를 더 넣고, 모호한 일반어 대신 구체적인 상황을 적는다. 수정 후 같은 발화로 자동 호출이 되는지 다시 검증한다.

    description: ... Use when the user mentions Excel,
      xlsx, spreadsheet, 매출표, 보고서 시트, or asks to
      export a table to a workbook.
progressive disclosure 구조상 Level 1(name + description)만 항상 컨텍스트에 올라가 있고, 본문(Level 2)과 번들 리소스(Level 3)는 트리거된 뒤에야 로드된다. 즉 자동 호출 판단에 쓰이는 정보는 오직 description뿐이다. 그래서 "본문을 아무리 잘 써도" description이 부실하면 Skill은 영영 불려 나오지 않는다. 디버깅의 핵심은 트리거 실패(description)와 실행 실패(본문)를 분리하는 것이다.
트리거가 안 된다고 description에 키워드를 무작정 늘어놓으면 엉뚱한 상황에서 과잉 호출되는 역효과가 난다. 또한 name에 예약어인 anthropic·claude를 쓰거나 64자·1024자 제한을 넘기면 로드 자체가 막힌다. 키워드는 "이 Skill이 진짜 담당하는 상황"으로 한정해 추가한다.
● 고급 Power User 외부에서 받은 MCP 서버·Skill 번들을 보안 감사한 뒤 팀 전체에 안전하게 배포하는 운영 절차
P-1 고급 보안 감사 후 팀 배포
팀 표준 도구로 서드파티 MCP 서버 한 개와 Skill 번들 하나를 도입하려 한다. 둘 다 외부 출처여서 임의 코드 실행·데이터 탈출 위험이 있다. 그대로 배포하기 전에 코드와 설정을 감사하고, 비밀키를 분리하고, 알려진 공격 표면을 점검한 뒤 .mcp.json과 플러그인 경로로 일괄 배포한다.
단계별 실행
  1. 번들 코드와 도구 설명을 직접 검토

    MCP 서버 소스와 Skill의 SKILL.md·scripts/를 사람이 읽어 본다. tool 설명(inputSchema 포함)에 숨은 악성 지시가 없는지(prompt injection), 외부 URL로 데이터를 빼돌리는 호출이 없는지, 파일 삭제·셸 실행 등 권한 상승 동작이 없는지 확인한다. 임의 코드가 들어갈 수 있는 스크립트는 한 줄씩 본다.

    grep -rEn "https?://|curl|wget|subprocess|os\.system|eval|exec" server/ skill/
  2. 비밀키를 env로 분리

    API 키·토큰을 소스나 인자에 박지 않고 환경변수로 주입한다. 원격 HTTP 전송 서버는 인증 토큰을 --header(예: Authorization: Bearer $TOKEN)로 분리하고, stdio 서버의 경우에만 env 블록에 키를 두어 각자의 셸 환경이나 비밀 관리 도구에서 값을 채운다. 그래야 공유 설정 파일(.mcp.json)을 git에 올려도 비밀이 새지 않는다.

    claude mcp add --transport http team-api https://api.internal.example.com \
      --header "Authorization: Bearer $TEAM_API_TOKEN"
  3. SSRF·injection 등 공격 표면 점검

    원격 HTTP 서버라면 SSRF를 막는다. 내부 IP 대역과 클라우드 메타데이터 주소(169.254.169.254)로의 요청을 차단하는지 확인한다. 더불어 OAuth confused deputy, 비결정적 session id를 통한 세션 하이재킹, tool 설명을 통한 prompt injection도 점검 항목에 넣는다. 실행 전 동의 프롬프트를 끄지 않는다.

    curl -s http://169.254.169.254/latest/meta-data/  # 서버 경유 시 차단되어야 정상
  4. .mcp.json과 플러그인으로 배포

    감사를 통과한 MCP 서버는 프로젝트 루트의 .mcp.json에 넣어 git으로 공유하면 팀원이 같은 설정으로 연결된다. Skill 번들은 마켓플레이스 등록 후 플러그인으로 설치하거나 .claude/skills/에 커밋해 배포한다.

    /plugin marketplace add our-org/claude-tools
    /plugin install team-skills@our-org
MCP 서버와 Skill은 신뢰 모델이 다르다. MCP 서버는 별도 프로세스로 돌며 네트워크·파일시스템에 직접 접근하므로 SSRF·세션·인증 위주로 본다. Skill은 모델의 코드 실행 환경에서 스크립트를 돌리고 번들 리소스를 읽으므로 임의 코드 실행과 데이터 탈출 위주로 본다. 두 축을 따로 감사한 뒤, 비밀키 분리와 실행 전 동의를 공통 안전장치로 두고 배포 채널(.mcp.json / 플러그인)에 올리면 팀 전체가 동일한 검증본을 쓰게 된다.
토큰 비용 관점도 함께 본다. MCP tool 정의(inputSchema)는 매 요청 컨텍스트를 차지하므로, 감사 후 실제로 쓰는 도구만 남기고 불필요한 tool은 비활성화한다. Skill은 메타데이터만 상시 로드되므로 부담이 적지만, description을 너무 늘리지 않는 편이 깔끔하다.
검토하지 않은 서드파티 MCP 서버나 Skill 번들을 팀에 그대로 배포하지 않는다. 한 사람이 신뢰한 도구가 .mcp.json·플러그인을 통해 팀 전원에게 퍼지면, 악성 코드 한 줄의 영향 범위가 조직 전체로 확대된다. 감사·키 분리·공격 표면 점검을 모두 통과한 뒤에만 공유 채널에 올린다.

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