Claude Code × MCP | 직접 제작 서버 구현부터 등록 및 연결 실패 원인 분석까지
요약
본 문서는 Claude Code 환경에서 MCP(Model Context Protocol) 서버를 직접 구축하고 등록하는 과정을 상세히 안내합니다. TODO/FIXME 검색 같은 프로젝트 전용 툴을 로컬 서버로 구현하고, 표준 입출력(stdio) 기반으로 안정화하며, 실제 개발 프로젝트에 연결하여 사용하는 방법을 다룹니다.
핵심 포인트
- MCP 서버는 수십 줄의 TypeScript로도 충분히 제작 가능합니다.
- 표준 출력을 이용할 경우 로그를 남기면 메시지가 손상되므로 주의해야 합니다.
- 작업 디렉토리를 제한하여 외부 접근을 막고 보안성을 확보해야 합니다.
- MCP Inspector를 통해 실제 Claude Code 연결 전에 서버 단독 동작을 반드시 검증해야 합니다.
“MCP 서버는 기성품을 사용하는 것이라고 생각했습니다. 제 리포지토리에 전용 툴을 만드는 것은 과장된 것 아닌가요?”
이 느낌은 맞습니다. 다만, 수십 줄의 TypeScript로 충분히 구현할 수 있는 수준까지 작게 만들면 이야기가 달라집니다. 이 글에서는 TODO/FIXME를 찾아내는 MCP 서버를 작성하고, Claude Code에 등록하며, 연결되지 않을 때의 문제 해결 방법까지 순차적으로 진행합니다.
Claude Code는 grep도 읽을 수 있지만, 프로젝트 고유의 "찾아보는 방식"은 매번 프롬프트로 설명해야 합니다.
- "TODO는
node_modules와dist를 제외하고, 파일명과 줄 번호가 포함되도록" - "결과는 50개로 자르고"
이것을 툴로 고정하면 호출할 때마다 설명을 할 필요가 없어지고, 출력 형태도 안정화됩니다. 표준 입출력(stdio)으로 작동하는 로컬 서버라면 네트워크 연결이나 인증 과정도 필요 없습니다.
mkdir todo-finder && cd todo-finder
pnpm init
pnpm add @modelcontextprotocol/sdk zod
...
package.json에 "type": "module"을 추가하고, tsconfig.json은 다음의 최소 구성으로 만듭니다.
{
"compilerOptions": {
"target": "ES2022",
...
그리고 src/index.ts 파일입니다. 포인트는 두 가지가 있습니다.
- stdio 환경에서는 표준 출력이 곧 프로토콜 자체이므로, 로그를 남기면 메시지가 손상되어 연결이 끊어집니다. 로그는
console.log대신console.error를 사용해야 합니다. - 읽을 범위를 작업 디렉토리 하위로 제한합니다.
dir은 모델이 구성하는 인자이므로,../../와 같은 경로가 들어와도 외부로 나가지 않도록 해야 합니다.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { readdir, readFile } from "node:fs/promises";
...
SDK 버전에 따라 registerTool 대신 server.tool(name, schema, handler) 형태일 수 있습니다. 사용 중인 타입 정의에 맞게 조정해 주세요.
빌드를 진행합니다.
pnpm exec tsc
Claude Code에 연결하기 전에, MCP Inspector를 사용하여 서버 단독의 동작을 확인합니다. 여기서 작동하지 않는 것은 Claude Code와 연결해도 작동하지 않습니다.
pnpm dlx @modelcontextprotocol/inspector node dist/index.js
브라우저에서 find_todos를 실행하고, file:line 목록이 반환되면 성공입니다. 확인이 끝났다면, 실제로 사용할 프로젝트 측에서 등록합니다.
cd ~/Developer/my-project
claude mcp add --scope project todo-finder -- node /절대경로/todo-finder/dist/index.js
claude mcp list
--scope project를 붙이면 프로젝트 직하위의 .mcp.json 파일에 기록됩니다. 팀원과 공유하고 싶다면 이 방식이 적합합니다. 개인용이라면 기본 스코프를 그대로 사용해도 무방합니다. 실행 후에는 /mcp로 연결 상태를 확인할 수 있습니다.
실제로 자주 겪을 만한 순서대로 정리했습니다.
| 증상 | 원인 | 확인 사항 |
|---|---|---|
failed가 표시됨 | 표준 출력에 불필요한 문자열이 포함됨 | 코드 내의 console.log를 grep으로 수정 |
| 실행 직후 연결 끊김 | 상대 경로로 등록함 | claude mcp list의 command가 절대 경로인지 확인 |
| 툴이 보이지 않음 | dist 파일이 오래됨 | tsc를 재실행하여 다시 연결 |
| 예상치 못한 곳을 읽음 | 현재 작업 디렉토리(cwd)가 다름 | 반환된 file:line의 기준점을 확인 |
가장 처음 '표준 출력(Standard Output)'이 가장 많이 걸립니다. 디버깅용으로 심어둔 console.log를 지우는 것을 잊으면, Inspector에서는 작동했는데 실제 환경에서 오류가 발생했다는 순서로 깨닫게 됩니다.
- 직접 만든 MCP 서버는
McpServer+StdioServerTransport+ Zod 세 가지 요소로 성립합니다 - stdio에서는console.log를 금지합니다. 로그는console.error를 사용해야 합니다. - 모델이 구성하는 인수는 신뢰하지 말고, 경로는 작업 디렉토리 하위에 제한합니다.
- 등록 전에 Inspector에서 단독으로 확인하고,
claude mcp list와/mcp로 연결 상태를 확인하세요.
다음 단계로는 find_todos에 git blame을 추가하여 담당자별로 반환하는 등 '해당 리포지토리에서만 의미를 갖는' 도구가 적합합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기