30분 만에 MCP 서버 만들기 입문: Claude Code와 연결하는 자체 구현 툴을 TypeScript로 실습하기
요약
본 글은 MCP(Model Context Protocol) 서버를 직접 구현하고 이를 Claude Code에 연결하는 과정을 단계별로 안내합니다. 사내 API 연동 등 독자적인 툴을 LLM 에이전트에 제공하기 위해, TypeScript와 `@modelcontextprotocol/sdk`를 사용하여 'TODO/FIXME 주석 일람' 기능을 가진 MCP 서버를 구축하는 실습 방법을 다룹니다.
핵심 포인트
- MCP는 LLM과 외부 툴 연결의 표준 프로토콜입니다.
- 사내 API 연동을 위해서는 직접 MCP 서버 구현이 필수적입니다.
- 디버깅 시 `console.log()` 대신 `console.error()`를 사용해야 합니다.
- Claude Code에 등록 전, 공식 Inspector로 단독 테스트가 권장됩니다.
'MCP 서버, 결국 나도 만들 수 있는 거야?'
Claude Code에 MCP 서버를 연결하는 글은 자주 보지만, '사용'하는 측면 이야기만 많고 '만드는' 측면 정보는 의외로 적다. 필자는 자신의 프로젝트에서 사내 API 연동용 MCP 서버를 직접 구현하여 Claude Code와 연결한 경험이 있는데, 처음에 부딪힌 어려움은 구현의 난이도가 아니라 'console.log()'을 한 줄 작성했을 뿐인데 서버가 침묵하는' 사소한 함정이었다.
본문에서는 이러한 경험을 바탕으로 MCP 서버를 제로(zero)부터 구현하고, Claude Code에 등록하여 실제로 호출할 때까지 과정을 코드를 복사-붙여넣기 할 수 있도록 단계화한다. 소요 시간은 환경 구축 포함 약 30분 정도가 걸린다.
배경: 왜 직접 만들 가치가 있는가
MCP(Model Context Protocol)는 LLM과 툴/데이터 소스를 연결하는 표준 프로토콜로, Anthropic이 제안했으며 현재 Claude뿐만 아니라 여러 클라이언트에서 채택되고 있다. 공식 TypeScript SDK인 @modelcontextprotocol/sdk는 2026-08 기준으로 1.30.0이 최신 안정 버전(latest 태그)으로 공개되어 있다(npm). 기성 MCP 서버는 Slack이나 GitHub 같은 범용 서비스를 위한 것이 중심이라, 사내 API, 자체 스크립트, 독자적인 집계 로직 등 '우리만의 툴'을 LLM에 제공하려면 직접 만들 수밖에 없다. 여기가 직접 구현해야 하는 가장 큰 동기이다.
구현 절차
1. 프로젝트 만들기
mkdir my-mcp-server && cd my-mcp-server
pnpm init
pnpm add @modelcontextprotocol/sdk zod
...
tsconfig.json은 ESM + Node18에 맞춰 최소한으로 설정한다.
{
"compilerOptions": {
"target": "ES2022",
...
}
2. 서버 본체 작성하기
이번 실습 주제는 '지정 디렉터리 아래의 TODO / FIXME 주석을 일람하는 툴'로 한다. 사소하지만 AI 에이전트에게 제공하면 실제로 유용하게 쓰이는 실용적인 예시이다.
// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
...
여기서 처음에 언급했던 함정이 작용한다. stdio transport는 프로세스의 stdout을 그대로 JSON-RPC 통신에 사용한다. 디버깅 목적으로 console.log()를 심어두면, 그 출력이 프로토콜 메시지에 섞여 클라이언트 측이 파싱 에러로 침묵하게 된다. 로그를 출력하고 싶을 때는 반드시 console.error() (stderr)를 사용해야 한다. 이는 MCP 서버 구현에서 초보자들이 가장 많이 걸리는 지점이다.
3. 로컬에서 단독 동작 확인하기
Claude Code에 연결하기 전에, 공식 MCP Inspector로 단독 테스트하는 것이 빠르다.
npx @modelcontextprotocol/inspector npx tsx src/index.ts
브라우저가 열리며 list_todos 툴의 스키마와 반환 값을 그 자리에서 테스트해 볼 수 있다. 여기서 기대한 대로 JSON이 반환되지 않는다면, Claude Code에 연결하기 전에 수정해야 한다.
4. Claude Code에 등록하기
claude mcp add todo-scanner -- npx tsx /absolute/path/to/my-mcp-server/src/index.ts
-- 뒤의 내용이 서버 실행 명령어이며, Claude Code는 세션 시작 시 이를 자식 프로세스로 spawn하고 stdio를 통해 툴 목록을 문의한다. 등록된 내용은 claude mcp list로 확인할 수 있다.
5. 실제로 호출해 보기
Claude Code의 채팅에서 '이 리포지토리의 src/ 아래 TODO를 일람해 줘'와 같이 요청하면, list_todos
도구가 자동으로 선택되어 호출됩니다. 도구의 description은 LLM이 언제 이 도구를 사용해야 할지 판단하는 자료가 되므로, 여기는 생략하지 않고 구체적으로 작성하는 것이 정확도에 직결합니다.
어려움을 겪기 쉬운 포인트 요약
- : stdio 서버에서는 stdout은 프로토콜 전용입니다. 로그는
console.log대신console.error를 사용해야 합니다. - : 타입이 느슨하면 클라이언트 측의 인자 생성(argument generation)이 안정적이지 않습니다.
inputSchema는 Zod로 엄격하게 정의하는 것이 좋습니다. - 상대 경로 전달에 주의:
claude mcp add에 전달하는 엔트리 포인트는 절대 경로로 지정해 두면, Claude Code의 시작 디렉토리에 의존하지 않고 작동합니다. - 프로세스가 남아있을 수 있음: 서버를 중지하지 않고 Claude Code를 종료하면 자식 프로세스(child process)가 잔류하는 경우가 있습니다. 개발 중에는
ps aux | grep tsx로 확인하는 습관을 들이면 안심할 수 있습니다.
요약
MCP 서버를 직접 만드는 것은 SDK가 McpServer + registerTool + StdioServerTransport라는 세 가지 조합으로 집약되어 있기 때문에, 생각보다 크게 겁먹을 필요는 없습니다. 이번의 list_todos와 같은 작은 도구라도, 자신들의 개발 흐름에 맞춰 LLM에게 전달할 수 있는 정보를 늘릴 수 있습니다. 우선 하나의 도구만 가진 최소 서버를 만들어 claude mcp add로 연결해 보는 것부터 시작하는 것을 추천합니다.
Sources:
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기