내 시스템을 Claude에 연결하기 | Custom MCP 서버 만들기
MCP Builder Skill로 날씨 API를 감싸는 MCP 서버를 직접 만들고, Tool 정의의 핵심 구조를 이해합니다
Overview
앞 레슨에서 Claude in Chrome을 붙여봤습니다. 공개된 MCP는 대부분 이렇게 설치만으로 바로 쓸 수 있습니다. 그런데 사내 API나 자체 데이터베이스처럼 세상에 공개된 MCP 서버가 없는 경우는 어떻게 할까요?
이번 레슨은 Anthropic의 MCP Builder Skill 로 MCP 서버 프로젝트를 자동 생성하고, 생성된 Tool 정의를 읽어보며 MCP 서버의 세 가지 핵심 원칙을 직접 익힙니다.
학습 목표
- MCP Builder Skill로 MCP 서버 프로젝트를 생성할 수 있습니다
- Tool 정의의 세 요소 (이름 · description · 입력 스키마) 를 읽고 이해합니다
- 직접 만든 MCP 서버를 Claude Code에 연결하고 동작을 확인합니다
시작하기 전 확인사항
- Node.js 20 이상 + Bun 설치 (
bun --version) - Claude Code 인증 완료 (
claude --version) - 이 실습은 기존 강의 프로젝트와 무관한 독립 프로젝트 로 시작합니다. 새 폴더에서 진행합니다
Step 1: 프로젝트 폴더 준비하기
MCP 서버는 자체 package.json 과 의존성을 갖춘 독립 프로세스입니다. 지금까지 쓰던 강의 프로젝트 (Todo 앱) 와 분리된 새 폴더에서 시작합니다.
- 찾기 쉬운 위치에
weather-mcp폴더 생성- macOS: Finder에서 홈 디렉토리 · 바탕화면 등에
⌘+⇧+N으로 새 폴더 - Windows: 탐색기에서 우클릭 → 새 폴더
- macOS: Finder에서 홈 디렉토리 · 바탕화면 등에
- VS Code에서 폴더 열기:
File > Open Folder(단축키: macOS⌘+O, WindowsCtrl+K Ctrl+O) → 방금 만든weather-mcp폴더 선택 - VS Code 터미널 열기:
⌃+(백틱) 또는 메뉴의Terminal > New Terminal
이제 이 폴더에서 MCP Builder Skill 설치와 Claude Code 실행을 이어갑니다.
Step 2: MCP Builder Skill 설치하기
MCP Builder는 Anthropic의 공식 Skills 저장소에서 Plugin으로 설치할 수 있는 Skill입니다. Claude Code에서 Plugin 마켓플레이스를 추가하고, example-skills 플러그인을 설치합니다.
/plugin marketplace add anthropics/skills
/plugin install example-skills@anthropic-agent-skills설치가 끝나면 /reload-plugins 로 새 플러그인을 현재 세션에 반영합니다. 이제 example-skills 플러그인 안의 mcp-builder Skill을 Claude Code에서 /mcp-builder 로 호출할 수 있습니다.
Step 3: MCP 서버 프로젝트 생성 요청하기
터미널에서 claude 로 Claude Code를 시작하고 다음과 같이 요청합니다.
/mcp-builder 도시 이름을 입력하면 현재 날씨 정보 (기온, 풍속, 습도) 를 반환하는 MCP 서버를 TypeScript 로 만들어줘. 프로젝트 폴더명은 weather-mcp-server 로 해줘. Open-Meteo API 를 사용하고 API 키 없이 동작해야 해.MCP Builder Skill이 지침을 따라 프로젝트를 자동으로 만듭니다. 결과 구조는 대략 이렇습니다.
src/index.ts가 MCP 서버 메인 파일입니다.
결과가 매번 다를 수 있습니다
AI가 생성하는 코드는 실행마다 세부 사항이 달라질 수 있습니다. 파일 구조나 변수 이름이 아래 예시와 달라도 정상입니다. 핵심 구조(Tool 정의 · 입출력 스키마 · 서버 연결)가 동일한지가 중요합니다.
Step 4: 생성된 Tool 정의 읽기
src/index.ts 의 Tool 정의가 MCP 서버의 핵심입니다.
server.registerTool(
"get-weather",
{
title: "Get Weather",
description: "도시 이름으로 현재 날씨를 조회합니다",
inputSchema: {
city: z.string().describe("도시 이름 (예: Seoul, Tokyo, New York)"),
},
},
async ({ city }) => {
// 1. 도시 이름 → 좌표 변환 (Geocoding)
// 2. 좌표 → 날씨 데이터 조회
// 3. content 배열로 결과 반환
}
);Tool 이름
Claude 가 이 도구를 식별하는 ID
동사 + 명사 형태로 명확하게
설정 객체
Tool 선택 기준과 입력 형식
description 이 가장 중요
실행 함수
실제 API 호출 · 데이터 가공
{ content: [...] } 표준 형식 반환
server.registerTool() 의 세 인자가 Tool 의 품질을 결정합니다server.registerTool() 은 세 개의 인자를 받습니다.
| 인자 | 역할 |
|---|---|
| 이름 | Claude가 이 도구를 식별하는 ID (get-weather) |
| 설정 객체 | title · description · inputSchema 를 담은 메타데이터 |
| 실행 함수 | 실제 동작. API 호출, 데이터 가공 후 결과 반환 |
Tool 정의의 세 요소가 품질을 결정합니다.
description: 이 Tool을 언제 호출할지 알려주는 한 줄 설명입니다. "데이터를 가져옵니다" 처럼 모호하면 Claude가 잘못된 Tool을 고릅니다. "도시 이름으로 현재 날씨를 조회합니다" 처럼 구체적이어야 합니다.inputSchema: Tool이 받을 입력 형태를 미리 선언하는 필드입니다. Zod는 TypeScript에서 입력값의 형태를 코드로 정의하고 검사하는 라이브러리입니다..describe()에 예시까지 넣으면 Claude가 자연어에서 올바른 값을 더 잘 추출합니다.- 실행 함수의 반환: 반드시
{ content: [{ type: "text", text: "..." }] }형식이어야 합니다. 이 표준 형식 덕분에 모든 MCP 서버의 응답을 Claude Code가 같은 방식으로 처리합니다.
Step 5: Claude Code에 MCP 서버 등록하기
MCP 서버 파일을 만들었지만, Claude Code는 아직 이 파일의 존재를 모릅니다. 한 번 등록해두면, Claude Code가 시작될 때마다 .mcp.json 에 적힌 명령어로 이 파일을 백그라운드에서 자동으로 실행해 둡니다. 이후 Tool을 호출할 때 Claude가 이 프로세스에 요청을 보내고, 돌려받은 응답을 사용합니다. Claude in Chrome 같은 공개 MCP와 작동 원리는 같고, 차이는 내 로컬 파일이라는 점 하나입니다.
다음과 같이 등록합니다.
claude mcp add weather -s project -- bun run "$(pwd)/weather-mcp-server/src/index.ts"
위 명령어로 현재 프로젝트에 MCP 서버를 등록해줘.명령어가 6 개 부분으로 나뉩니다.
| 부분 | 의미 |
|---|---|
claude mcp add | Claude Code에 MCP 서버를 등록하는 명령 |
weather | 서버 이름. /mcp 에 이 이름으로 표시됨 |
-s project | 스코프. project = 현재 프로젝트 루트의 .mcp.json 에 저장 |
-- | 구분자. 이 뒤가 서버 실행 명령어 |
bun run | Bun 런타임으로 파일 실행. TypeScript를 컴파일 없이 바로 돌림 |
"$(pwd)/weather-mcp-server/src/index.ts" | 서버 소스 파일 절대 경로 ($(pwd) 는 현재 폴더로 치환) |
Claude가 명령어를 실행하면 .mcp.json 에 서버 정보가 저장됩니다.
Step 6: 연결 확인하고 날씨 조회 테스트하기
Claude Code는 MCP 설정을 세션이 시작될 때 한 번만 읽습니다. Step 5에서 등록한 weather 서버를 새로 인식시키려면 세션을 껐다 켜야 합니다. /exit 로 나간 뒤 다시 claude 를 실행합니다.
/mcpweather 서버가 "Connected" 상태면 성공입니다.
이제 Claude에게 날씨를 물어봅니다.
서울 날씨 어때?Claude가 get-weather Tool을 호출해서 Open-Meteo API에서 실시간 데이터를 가져옵니다. 응답에 기온·풍속·습도가 포함되면 성공입니다.
한 단계 더 나아가 여러 도시를 비교합니다.
도쿄랑 뉴욕 날씨 비교해줘Claude가 get-weather 를 두 번 호출해 두 도시 결과를 가져오고 비교합니다. MCP 서버는 데이터만 가져오고, 비교·판단·표현은 Claude가 담당합니다. 이것이 MCP 서버의 역할 경계입니다.
좋은 MCP 서버의 세 가지 원칙
description이 Tool 선택을 결정하기
Claude는 사용자 질문과 여러 Tool의 description 을 비교해서 무엇을 호출할지 판단합니다. 내가 만든 get-weather 도 내장 Tool · 다른 MCP의 Tool과 같은 목록에서 함께 경쟁합니다. description에 "날씨" 라는 단어가 있어야 "서울 날씨 어때?" 에 이 Tool이 선택됩니다. 그래서 설명을 구체적으로 적을수록 올바른 Tool이 선택됩니다.
입력 스키마: Claude 와의 계약
z.string().describe("도시 이름") 이라고 정의하면, Claude는 사용자의 자연어에서 도시 이름을 추출해 문자열로 전달합니다. 스키마가 명확할수록 추출 정확도가 올라갑니다. .describe("도시 이름 (예: Seoul, Tokyo)") 처럼 예시까지 넣으면 추출 정확도가 더 올라갑니다.
복잡성은 서버 안에 숨기기
날씨 MCP는 내부적으로 API를 두 번 호출합니다 (Geocoding → Weather). 그러나 Claude가 보는 인터페이스는 city 하나뿐입니다. 좋은 MCP 서버는 외부 시스템의 복잡성(좌표 변환 · 호출 순서 · 에러 처리)을 감추고 Claude에게 단순한 인터페이스만 노출합니다.
핵심 포인트 정리
- MCP Builder Skill로 자동 생성: 만들고 싶은 서버를 설명하면 Claude가 프로젝트 구조 · SDK 설정 · Tool 정의까지 전체를 만듭니다. 개발자는 설계 의도만 전달합니다.
- Tool 정의의 세 요소:
description(Claude 선택 근거) ·inputSchema(Claude 와의 계약) ·content배열 출력(MCP 표준 형식) 이 셋이 명확할수록 Claude의 호출 정확도가 올라갑니다. claude mcp add한 줄로 연결: 절대 경로로 등록하고 새 세션에서 확인합니다..mcp.json에 저장되므로 팀원이 저장소를 받으면 같은 설정이 즉시 동작합니다.
FAQ
이어서 배울 내용
CLI, MCP, Custom MCP로 외부 시스템에 닿는 세 가지 길을 다 배웠습니다. 그런데 도구에 접근할 수 있는 것과, 그 도구를 매번 같은 방식으로 쓰는 것 은 다른 문제입니다. 다음 레슨에서는 외부 도구에 Skill을 결합해서 반복 워크플로우를 일관되게 만드는 방법을 배웁니다.
- 도구 (Capability) 와 사용법 (Procedure) 의 분리
- CLI + Skill 결합 워크플로우 사례
- MCP + Skill 결합 워크플로우 사례