MCP 서버 직접 만들기-Node.js 최소 예제로 배우는 구조와 연결 방법

8/16/2026 AI실험실
공식 MCP TypeScript SDK·Claude Desktop 공식 문서 대조 확인
MCP 서버 직접 만들기
Node.js 최소 예제로 배우는
구조와 연결 방법

도구(tool) 하나만 노출하는 MCP 서버를 Node.js로 처음부터 작성하고, Claude Desktop에 연결해 실제로 동작하는 것까지 확인하는 최소 단위 예제입니다. 공식 SDK 문서를 기준으로 코드를 검증했습니다.

⏱️ 읽는 시간 약 12분 🧩 Node.js 기초 문법을 아는 분 대상 📅 2026년 8월 최종 업데이트
🔬 확인 방법 · Verification Method
  • 대조 대상: 공식 MCP TypeScript SDK 저장소(GitHub modelcontextprotocol/typescript-sdk)와 npm 패키지 페이지(@modelcontextprotocol/sdk), Anthropic 공식 문서(docs.claude.com)의 MCP 관련 페이지
  • 확인 시점: 2026년 8월 16일 기준 위 공식 저장소·문서 페이지
  • 확인 항목: SDK의 클래스명·임포트 경로·도구 등록 메서드 시그니처, Claude Desktop 설정 파일의 키 구조
  • 비교 기준: SDK는 v1(안정 버전, npm 배포 버전 기준 1.29.0 확인)과 2026-07-28 스펙에 맞춘 v2 라인이 함께 존재합니다. 이 글은 현재 가장 널리 쓰이는 v1(@modelcontextprotocol/sdk) 기준으로 작성했으며, 이 차이는 Section 3과 한계 섹션에서 다시 명시합니다.
📷 MCP 서버·클라이언트·호스트 3자 구조 다이어그램 MCP 서버·클라이언트·호스트 3자 구조 다이어그램

1 왜 MCP 서버를 직접 만들어야 하는가 — 원리

MCP(Model Context Protocol)는 AI 애플리케이션이 외부 데이터와 도구에 연결하는 방식을 표준화한 개방형 프로토콜입니다. Claude Desktop, Claude Code, VS Code, Cursor 같은 호스트는 이 프로토콜을 구현한 클라이언트를 내장하고 있고, 개발자가 만드는 서버는 이 클라이언트에 연결되어 도구(tool)·리소스(resource)·프롬프트(prompt)를 제공합니다.

이미 만들어진 MCP 서버(파일시스템, GitHub, 데이터베이스 등)를 연결해 쓰는 것만으로도 대부분의 요구는 해결됩니다. 다만 사내 API, 자체 데이터베이스, 개인 프로젝트의 커스텀 로직처럼 공개 서버가 존재하지 않는 대상을 Claude가 다루게 하려면 직접 서버를 작성해야 합니다.

💡 "도구 하나짜리" 최소 예제로 시작해야 하는 이유 — 원리

MCP 서버는 도구·리소스·프롬프트·샘플링·태스크 등 여러 기능을 한 번에 구현할 수 있지만, 처음부터 여러 기능을 동시에 붙이면 어느 부분에서 오류가 나는지 구분하기 어렵습니다. 서버 초기화 → 트랜스포트 연결 → 도구 1개 등록이라는 최소 골격을 먼저 완성하고 정상 동작을 확인한 뒤 기능을 하나씩 늘려가는 방식이, 실제로 문제가 생겼을 때 원인을 좁히는 데 유리합니다.

📎
공식 출처 — Model Context Protocol TypeScript SDK MCP의 구조와 SDK가 지원하는 기능(도구·리소스·프롬프트·stdio/HTTP 트랜스포트)은 공식 GitHub 저장소(modelcontextprotocol/typescript-sdk)SDK 공식 문서를 기준으로 확인했습니다.

2 개발 환경 준비 — Node.js 프로젝트 설정

Node.js가 설치돼 있다면(LTS 버전 권장) 새 폴더에서 아래 순서로 프로젝트를 준비합니다. 이 예제는 TypeScript 없이 순수 JavaScript(ESM)로 작성해 컴파일 단계를 생략했습니다.

터미널 — 프로젝트 초기화mkdir hello-mcp-server cd hello-mcp-server npm init -y npm install @modelcontextprotocol/sdk zod

package.json"type": "module"을 추가해 ESM 문법(import)을 사용할 수 있게 합니다.

package.json{ "name": "hello-mcp-server", "version": "1.0.0", "type": "module", "main": "server.js", "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^3.23.0" } }
💡 zod가 함께 필요한 이유 — 원리

MCP 도구는 클라이언트(Claude 등)에게 "이 도구는 어떤 입력을 받는지"를 스키마 형태로 알려야 합니다. 공식 SDK는 이 입력 스키마를 zod 라이브러리의 타입으로 정의하도록 설계돼 있습니다. zod로 정의한 스키마는 SDK 내부에서 JSON Schema로 변환되어 클라이언트에 전달되고, 동시에 런타임에서 입력값을 검증하는 역할도 함께 수행합니다.

3 최소 MCP 서버 코드 작성 (stdio 방식)

아래는 두 숫자를 더하는 도구 하나만 노출하는 최소 서버입니다. 트랜스포트는 로컬 프로세스 간 통신에 쓰이는 stdio(표준 입출력) 방식을 사용했습니다. Claude Desktop처럼 로컬에서 서버를 자식 프로세스로 실행하는 호스트에 연결할 때 가장 단순한 방식입니다.

server.jsimport { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // 1. 서버 인스턴스 생성 — 이름과 버전은 클라이언트에 그대로 노출됩니다. const server = new McpServer({ name: "hello-mcp-server", version: "1.0.0", }); // 2. 도구 등록 — 이름, 설명, 입력 스키마, 실행 함수로 구성됩니다. server.registerTool( "add_numbers", { title: "두 숫자 더하기", description: "입력받은 두 숫자를 더한 값을 반환합니다.", inputSchema: { a: z.number().describe("더할 첫 번째 숫자"), b: z.number().describe("더할 두 번째 숫자"), }, }, async ({ a, b }) => { const sum = a + b; return { content: [ { type: "text", text: `${a} + ${b} = ${sum}`, }, ], }; } ); // 3. stdio 트랜스포트로 연결하고 서버를 시작합니다. const transport = new StdioServerTransport(); await server.connect(transport);
💡 registerTool의 세 인자가 각각 하는 역할 — 원리

첫 번째 인자(도구 이름)는 클라이언트가 이 도구를 호출할 때 사용하는 식별자입니다. 두 번째 인자(설정 객체)의 title·description은 모델이 "이 도구를 지금 써야 하는지"를 판단하는 근거가 되므로, 모호하게 쓰면 모델이 도구를 잘못된 상황에 호출하거나 아예 호출하지 않을 수 있습니다. 세 번째 인자(실행 함수)는 실제 로직이며, 반환값은 반드시 content 배열 형태를 지켜야 클라이언트가 결과를 정상적으로 렌더링합니다.

📎
공식 출처 — MCP TypeScript SDK 서버 예제 McpServer, registerTool, StdioServerTransport의 임포트 경로와 시그니처는 npm의 @modelcontextprotocol/sdk 패키지 문서공식 GitHub 저장소를 기준으로 확인했습니다.

터미널에서 아래 명령으로 서버가 오류 없이 실행되는지 먼저 확인합니다. 정상이라면 화면에는 아무것도 출력되지 않고 프로세스가 대기 상태로 멈춰 있습니다(stdio로 클라이언트의 입력을 기다리는 상태이므로 정상입니다). Ctrl + C로 종료합니다.

터미널 — 단독 실행 확인node server.js

4 Claude Desktop에 연결해 동작 확인하기

Claude Desktop은 설정 파일에 등록된 명령을 자식 프로세스로 실행해 stdio로 통신합니다. 설정 파일은 앱의 Settings → Developer → Edit Config 메뉴에서 열거나, 아래 경로를 직접 찾아 편집할 수 있습니다.

운영체제설정 파일 경로
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json

파일에 아래 내용을 추가합니다. args의 경로는 반드시 절대 경로로 지정해야 합니다.

claude_desktop_config.json{ "mcpServers": { "hello-mcp-server": { "command": "node", "args": ["/절대/경로/hello-mcp-server/server.js"] } } }
💡 절대 경로를 써야 하는 이유 — 원리

Claude Desktop이 서버를 자식 프로세스로 실행할 때의 작업 디렉터리는 사용자가 코드를 작성한 폴더가 아닙니다. 상대 경로를 쓰면 Claude Desktop이 엉뚱한 위치에서 파일을 찾으려다 실패합니다. 같은 이유로 command에 지정한 node가 시스템 PATH에 없는 경우(특히 nvm 등으로 Node를 관리하는 환경)에는 which node(macOS) 또는 where node(Windows)로 확인한 절대 경로를 command에 직접 넣어야 합니다.

설정 파일을 저장한 뒤 Claude Desktop을 완전히 종료했다가 다시 실행합니다(창을 닫는 것만으로는 설정이 반영되지 않습니다 — macOS는 Cmd+Q, Windows는 작업표시줄 아이콘 우클릭 후 종료). 재실행 후 채팅 입력창 근처에 도구 연결을 나타내는 아이콘이 보이면 연결이 성공한 것입니다. 채팅창에 "3과 5를 더해줘"처럼 물어보면 Claude가 add_numbers 도구를 호출하는 것을 확인할 수 있습니다.

📎
참고 — Claude Desktop 설정 파일 위치 및 재시작 방식 설정 파일 경로와 "완전 종료 후 재시작이 필요하다"는 동작 방식은 2026년 3~7월 사이에 작성된 다수의 커뮤니티 설치 가이드에서 공통적으로 확인됐습니다. Claude Desktop 앱 내 Settings → Developer → Edit Config 메뉴에서도 동일한 파일을 직접 열 수 있으므로, 정확한 경로가 헷갈릴 경우 앱 메뉴를 이용하는 편이 더 확실합니다.
📷 도구 등록부터 호출 응답까지 4단계 흐름 인포그래픽 도구 등록부터 호출 응답까지 4단계 흐름 인포그래픽

5 자주 발생하는 오류와 해결 방법

1) 도구 아이콘이 아예 나타나지 않는 경우

JSON 문법 오류가 가장 흔한 원인입니다. 쉼표 하나만 잘못 찍혀도 설정 파일 전체가 무시됩니다. JSON 유효성 검사 도구로 문법을 먼저 확인하고, 최상위 키가 mcpServers인지(다른 도구의 servers 키와 혼동하지 않았는지)도 함께 확인합니다.

2) 아이콘은 보이는데 도구 목록이 비어 있는 경우

node server.js를 터미널에서 직접 실행했을 때 에러 메시지 없이 대기 상태가 되는지 먼저 확인합니다. import 경로 오타(특히 .js 확장자 누락)나 "type": "module" 누락이 흔한 원인입니다.

3) 설정을 고쳤는데도 반영되지 않는 경우

창을 닫기만 한 경우 프로세스가 백그라운드에 남아 있어 이전 설정이 그대로 유지됩니다. macOS는 Cmd+Q로 완전히 종료하고, Windows는 작업표시줄 아이콘을 우클릭해 종료한 뒤 다시 실행합니다.

6 이 글을 만든 방식

이 포스트는 실제 사용자 다수를 대상으로 장기간 운영한 서버의 후기가 아니라, 2026년 8월 시점 공식 SDK 저장소·npm 문서·Anthropic 공식 문서를 직접 대조해 검증한 최소 예제 코드입니다. 아래는 그 과정을 레이어별로 정리한 내용입니다.

공식 SDK 저장소·npm 문서 대조 확인 완료 · 2026년 8월
⭐ Experience : 직접 확인한 과정

이 글의 코드는 공식 GitHub 저장소(modelcontextprotocol/typescript-sdk)와 npm 패키지 문서, 그리고 Anthropic 스킬 저장소(anthropics/skills)에 공개된 Node.js MCP 서버 참고 문서를 각각 열어 임포트 경로와 API 시그니처를 직접 대조했습니다. 이 과정에서 확인한 가장 중요한 지점은, SDK가 2026-07-28 스펙에 맞춘 v2 라인으로 전환 중이며 v1(@modelcontextprotocol/sdk)과 v2(@modelcontextprotocol/server 등 분리 패키지)의 임포트 방식이 서로 다르다는 점입니다.

❌ 흔히 보이는 방식

블로그나 튜토리얼의 예제 코드를 발행일 확인 없이 그대로 복사해 사용하는 경우, SDK 버전이 바뀌면서 임포트 경로나 메서드 이름이 달라져 오류가 나는 경우가 흔합니다.

✅ 이 포스트에서 적용한 방식

공식 저장소의 README와 npm 패키지 페이지에 실려 있는 예제 코드를 기준으로 삼고, 실제로 널리 배포된 안정 버전(1.29.0) 기준 임포트 경로를 명시했습니다.

※ 이 글은 다수 사용자 환경에서 장기간 운영해 얻은 성능 수치를 제시하지 않습니다. 정확하지 않은 수치를 만들어 넣지 않기 위한 의도적인 선택이며, 이 차이는 Section 7(한계)에서 다시 명시합니다.

🧠 Expertise : MCP 서버 예제 코드가 자주 틀리는 이유

MCP는 2026년 한 해에도 스펙 개정(2026-07-28)과 SDK 메이저 버전 전환이 함께 진행 중인 빠르게 변화하는 프로토콜입니다. 같은 검색어로 찾은 예제라도 작성 시점의 SDK 버전에 따라 임포트 경로(@modelcontextprotocol/sdk vs @modelcontextprotocol/server)와 메서드 이름이 달라질 수 있어, 코드 예제를 그대로 옮기기 전에 패키지 버전과 문서 발행일을 함께 확인해야 합니다.

💡 이 글이 v1 SDK를 기준으로 삼은 이유 — 원리

2026년 8월 시점에는 v2가 새로 나왔지만, 이 글을 작성한 시점 기준 npm에 배포된 안정 버전과 커뮤니티 튜토리얼·Anthropic 자체 참고 문서 다수가 여전히 v1(@modelcontextprotocol/sdk) 계열을 기준으로 하고 있는 것으로 확인됩니다. 처음 MCP 서버를 만들어 보는 입장에서는 자료가 더 풍부한 v1으로 구조를 익힌 뒤, 필요할 때 v2 마이그레이션 가이드를 참고하는 순서가 더 안전합니다.

📚 Authoritativeness : 이 포스트에서 연결한 공식 출처

코드와 설정 방법은 아래 공식·준공식 출처를 기준으로 작성했습니다.

📎
출처 1 — MCP TypeScript SDK 공식 GitHub github.com/modelcontextprotocol/typescript-sdk에서 서버 생성·도구 등록·트랜스포트 연결 예제를 확인했습니다.
📎
출처 2 — npm 패키지 문서 npmjs.com의 @modelcontextprotocol/sdk 페이지에서 패키지 설치 방법과 지원 트랜스포트 목록을 확인했습니다.
📎
출처 3 — Anthropic 공식 문서 및 스킬 저장소 docs.claude.com의 MCP 관련 문서anthropics/skills 저장소의 Node.js MCP 서버 참고 문서를 함께 대조했습니다.
🛡️ Trustworthiness : 이 글에서 직접 공개하는 한계와 작성 방식

이 포스트의 문장 구조는 Claude를 보조 도구로 사용해 초안을 잡았습니다. 다만 코드 예제의 임포트 경로·API 시그니처·설정 파일 구조는 AI가 생성한 내용을 그대로 옮긴 것이 아니라, 위에 명시한 공식 저장소·문서 3곳을 하나씩 확인한 결과이며, 실제로 값을 지어내지 않고 확인되지 않은 부분은 아래 한계 섹션에 별도로 남겨두었습니다.

⚠️ 이 포스트에서 확정하지 못한 항목

Claude Desktop의 설정 파일 경로와 재시작 방식은 Anthropic 공식 문서 페이지에서 직접 확인하지 못해, 다수의 2026년 작성 커뮤니티 가이드가 공통적으로 보고하는 내용을 준공식 정보로 표기했습니다. 또한 SDK의 정확한 최신 버전 번호는 배포 주기에 따라 이 글의 확인 시점 이후 바뀌었을 수 있으므로, 설치 전 npm 페이지에서 최신 버전을 다시 확인해야 합니다.

7 이 글에서 확인하지 못한 것 — 솔직한 한계

이 글은 공식 문서 대조를 기준으로 작성됐지만, 다음 한계를 명확히 알고 참고해야 합니다.

⚠️ 알고 참고해야 할 한계

이 글은 하나의 도구만 노출하는 최소 예제이며, 실제 서비스에 배포할 수준의 인증·오류 처리·로깅·다중 사용자 대응은 다루지 않습니다. 또한 로컬 stdio 연결만 다뤘고, 원격 서버를 위한 Streamable HTTP·OAuth 인증·배포 방식은 이 글의 범위 밖입니다. Claude Desktop 설정 파일의 정확한 경로와 재시작 절차는 Anthropic 공식 문서 페이지에서 직접 재확인하지 못해 커뮤니티 자료 기준으로 작성했다는 점도 다시 한번 밝혀 둡니다. SDK와 프로토콜 스펙 모두 개정 주기가 짧으므로, 코드를 그대로 옮기기 전에 반드시 공식 저장소의 최신 예제와 대조하는 것을 권장합니다.

이 글로 확인할 수 없는 것
  • 다중 사용자·프로덕션 배포 시의 안정성
  • 원격 HTTP 서버·OAuth 인증 구성 방법
  • Claude Desktop 공식 문서 페이지의 직접 인용
  • 향후 SDK v2 전환 이후의 정확한 마이그레이션 절차
이 글로 확인할 수 있는 것
  • 도구 1개짜리 stdio MCP 서버의 최소 동작 코드
  • 공식 저장소 기준 임포트 경로와 API 시그니처
  • Claude Desktop 연결에 필요한 설정 파일 구조
  • 연결 실패 시 확인해야 할 대표적인 원인 3가지

8 자주 묻는 질문 (FAQ)

Q1
MCP 서버는 반드시 TypeScript로 만들어야 하나요?
아닙니다. 공식 TypeScript SDK는 순수 JavaScript(ESM)에서도 그대로 사용할 수 있으며, 이 글의 예제도 컴파일 단계 없이 JavaScript로 작성했습니다. 다만 입력 스키마의 타입 안전성을 프로젝트 전체에서 활용하려면 TypeScript와 함께 쓰는 것이 유리합니다. Python으로 작성하고 싶다면 공식 Python SDK가 별도로 존재합니다.
Q2
stdio 방식과 HTTP 방식 중 어떤 것을 먼저 배워야 하나요?
로컬 개발용이나 Claude Desktop처럼 같은 컴퓨터에서 서버를 실행하는 경우 stdio가 더 단순합니다. 여러 사용자가 원격으로 접속하는 서버를 만들 계획이라면 결국 Streamable HTTP 방식을 익혀야 하지만, 프로토콜의 기본 구조(도구 등록, 스키마 정의, 응답 형식)는 stdio로 먼저 익히는 것이 학습 부담을 줄이는 방법입니다.
Q3
도구를 여러 개 추가하려면 어떻게 하나요?
같은 server 인스턴스에 대해 registerTool을 필요한 만큼 반복 호출하면 됩니다. 다만 도구가 많아질수록 각 도구의 description이 서로 겹치지 않고 명확히 구분되도록 작성해야 모델이 올바른 도구를 선택할 확률이 높아집니다.

9 결론 — 다음 단계로 넘어가기 전 체크

  • 단독 실행부터 확인: Claude Desktop에 연결하기 전에 node server.js로 서버가 오류 없이 대기 상태가 되는지 먼저 확인하십시오.
  • 절대 경로와 완전 재시작을 지키기: 설정 파일의 경로 오류와 앱 미종료가 연결 실패의 가장 흔한 두 가지 원인입니다.
  • 공식 저장소에서 최신 예제 재확인: SDK가 v2로 전환되는 과정이므로, 이 글의 코드가 동작하지 않는다면 설치된 @modelcontextprotocol/sdk 버전을 먼저 확인하십시오.

도구 하나짜리 최소 서버가 정상 동작하는 것을 확인했다면, 다음 단계는 리소스(resource)나 여러 개의 도구를 추가하며 실제 사용 목적에 맞는 서버로 확장하는 것입니다. MCP를 실제 워크플로우에 연결하는 다른 사례가 필요하다면 위 "이 글과 함께 보면 좋은 글"을 참고하십시오.

📅 업데이트 로그 — 2026년 8월: 최초 발행 (MCP TypeScript SDK 공식 GitHub 저장소·npm 문서·Anthropic 공식 문서 2026년 8월 16일 확인 기준)

※ 본 글의 SDK 버전·API·설정 방법은 공식 저장소·문서 기준으로 정리했으며, 이후 변경될 수 있습니다. 코드를 실제 환경에 적용하기 전 반드시 npm과 공식 GitHub 저장소에서 최신 버전을 다시 확인하십시오. 본 초안은 Claude를 보조 도구로 사용해 작성됐으며, 공식 문서 대조 확인과 편집 과정을 거쳐 발행됐습니다.