본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 27. 05:14

TypeScript로 첫 MCP 서버 구축하기: 30분 만에 끝내는 2026년형 설정 방법

요약

Model Context Protocol(MCP)을 사용하여 TypeScript 기반의 MCP 서버를 구축하는 방법을 설명합니다. MCP의 표준화된 구조인 리소스, 도구, 프롬프트의 개념을 다루며, 실제 작동하는 서버를 30분 만에 설정하는 튜토리얼을 제공합니다.

핵심 포인트

  • MCP는 AI 모델과 외부 데이터를 연결하는 표준 프로토콜입니다.
  • 리소스, 도구, 프롬프트라는 세 가지 핵심 요소를 사용합니다.
  • 한 번의 서버 구현으로 Claude Desktop, Cursor 등 다양한 클라이언트와 호환됩니다.
  • TypeScript와 @modelcontextprotocol/sdk를 사용하여 빠르게 구축 가능합니다.

TypeScript로 첫 MCP 서버 구축하기: 30분 만에 끝내는 2026년형 설정 방법.

Claude Desktop을 열어두었습니다. 채팅창에 스키마 덤프를 일일이 복사해서 붙여넣지 않고도 로컬 SQLite 데이터베이스를 쿼리할 수 있는 기능이 필요했습니다. 30분 후, 저는 작동하는 MCP 서버를 갖게 되었습니다. 시행착오를 제외하고 제가 거친 정확한 경로를 소개합니다.

요약 (TL;DR)

단계구축 내용소요 시간
프로젝트 설정npm 프로젝트, tsconfig, SDK 설치5분
...

MCP의 실제 정의

Model Context Protocol (MCP)은 AI 모델을 외부 데이터 및 도구와 연결하기 위한 표준입니다. 모델이 요청을 보내면, 귀하의 서버가 이를 처리하고, 그 결과가 모델이 이해할 수 있는 형식으로 반환됩니다. 이것이 핵심 아이디어입니다.

MCP 이전에는 모든 도구 통합이 맞춤형(custom)으로 이루어졌습니다. OpenAI는 함수 호출 (function calling) 기능이 있었고, Anthropic은 도구 사용 (tool use) 기능이 있었습니다. Cursor는 자체적인 플러그인 형식을 가지고 있었습니다. MCP는 와이어 프로토콜 (wire protocol)을 표준화하여, 귀하가 서버를 하나만 작성하면 Claude Desktop, Cursor, 또는 직접 만든 클라이언트와 같이 규격을 준수하는 어떤 클라이언트라도 이를 호출할 수 있게 합니다.

귀하가 주목해야 할 세 가지 기본 요소 (primitives)는 다음과 같습니다:

  • Resources (리소스): 파일이나 데이터베이스 행과 같이 모델이 가져올 수 있는 읽기 전용 데이터.
  • Tools (도구): 쿼리 실행이나 요청 전송과 같이 모델이 인자 (arguments)와 함께 호출할 수 있는 함수.
  • Prompts (프롬프트): 클라이언트가 사용자에게 보여줄 수 있는 재사용 가능한 프롬프트 템플릿.

이 튜토리얼에서는 도구 (tools)와 리소스 (resources)를 다룹니다. 프롬프트 (prompts)도 동일한 패턴을 따르며, 대부분의 서버에서는 필요하지 않을 것입니다.

1. 프로젝트 설정

Node 18 이상이 필요합니다. node --version으로 확인하세요.

mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
...

SDK 패키지는 @modelcontextprotocol/sdk입니다. 2026년 5월 기준 npm의 버전은 1.11.x입니다. Zod는 도구 입력에 대한 스키마 검증 (schema validation)을 처리합니다.

package.json을 다음 필드로 업데이트하세요:

{
  "type": "module",
  "scripts": {
...

tsconfig.json을 생성하세요:

{
  "compilerOptions": {
    "target": "ES2022",
...

2. 도구 구현

도구 (Tool)는 모델이 호출할 수 있는 함수입니다. 도구의 이름, 설명 (Description), 입력 스키마 (Input Schema), 그리고 핸들러 (Handler)를 정의합니다. 모델은 설명과 스키마를 읽고 언제, 어떻게 도구를 호출할지 결정합니다.

다음은 16진수 색상(Hex color)을 RGB로 변환하는 하나의 도구를 포함한 완전한 서버 예시입니다:

// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
...

주의해야 할 세 가지 사항이 있습니다:

설명 (Description) 문자열은 모델이 도구를 호출할지 여부를 결정하기 위해 읽는 내용입니다. 동료를 위해 JSDoc 주석을 작성하듯 명확하게 작성하세요. 모호한 설명은 호출 누락이나 잘못된 입력을 초래합니다.

server.tool()의 두 번째 인자는 설명입니다. 세 번째 인자는 Zod 스키마 객체입니다. SDK는 이를 JSON 스키마 (JSON Schema)로 변환하여 클라이언트가 모델에 전달합니다. 스키마는 엄격하게 유지하세요. 필수 필드만 포함하고, 출력을 변경하지 않는 선택적 필드 (Optional fields)는 제외하십시오.

반환 값 (Return value)은 반드시 content 배열을 가져야 합니다. 각 항목은 typetext (또는 바이너리의 경우 data)를 가집니다. JSON을 반환할 때는 텍스트 항목 내에 문자열 형태로 포함시키세요. 모델은 거기서 이를 파싱할 수 있습니다.

로컬에서 빌드 및 테스트하기:

npm run build
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node build/index.js

hex_to_rgb가 나열된 JSON-RPC 응답이 보여야 합니다. 이는 서버가 시작되었고 목록 요청에 응답하고 있음을 확인해 줍니다.

3. 리소스 (Resource) 구현

리소스 (Resources)는 모델이 필요할 때 가져올 수 있는 읽기 전용 데이터를 노출합니다. 일반적인 사용 사례로는 로컬 데이터베이스의 스키마를 노출하여, 모델이 쿼리를 작성하기 전에 테이블 구조를 알 수 있도록 하는 것이 있습니다.

전송 (Transport) 설정 전에 다음을 추가하세요:

server.resource(
  "db-schema",
  "sqlite:///local.db",
...

첫 번째 인자는 리소스 이름입니다. 두 번째 인자는 클라이언트가 이를 요청할 때 사용하는 URI입니다. 데이터에 적합한 URI 스킴 (URI scheme)을 선택하세요: file, sqlite, https, 또는 myapp://와 같은 사용자 정의 스킴을 사용할 수 있습니다.

리소스는 풀 기반 (pull-based)입니다. 모델은 리소스가 필요하다고 판단할 때 이를 요청합니다. 만약 모든 대화에 데이터를 자동으로 푸시 (push)하고 싶다면, 이는 다른 패턴 (리소스가 아닌 클라이언트 수준에서의 시스템 프롬프트 주입 (system prompt injection))입니다.

4. Claude Desktop에 연결하기

프로젝트를 빌드합니다:

npm run build

Claude Desktop 설정 파일을 엽니다. macOS의 경우:

~/Library/Application Support/Claude/claude_desktop_config.json

Windows의 경우:

%APPDATA%\Claude\claude_desktop_config.json

mcpServers 블록에 서버를 추가합니다:

{
  "mcpServers": {
    "color-tools": {
...

절대 경로 (absolute path)를 사용하세요. 상대 경로 (relative path)를 사용하면 오류 메시지 없이 실패하며, 이는 초보자들이 저지르는 가장 흔한 실수입니다. Claude Desktop을 완전히 재시작하세요 (단순히 창을 닫는 것이 아니라 메뉴 바에서 종료해야 합니다). 새로운 대화를 시작합니다. 입력창에 도구 사용이 가능하다는 것을 나타내는 망치 아이콘이 보여야 합니다. "convert #3b82f6 to RGB"라고 입력하고 도구가 호출되는 것을 확인하세요.

Cursor의 경우, 설정은 ~/.cursor/mcp.json에 위치하며 동일한 mcpServers JSON 구조를 사용합니다:

{
  "mcpServers": {
    "color-tools": {
...

범용 클라이언트 또는 테스트 용도: Anthropic에서 제공하는 MCP Inspector를 사용하면 Claude Desktop을 설정하지 않고도 웹 UI를 통해 도구 호출을 실행할 수 있습니다.

npx @modelcontextprotocol/inspector node /absolute/path/to/build/index.js

6274 포트에서 Inspector UI를 열면 수동으로 도구 호출을 실행하고 원시 JSON-RPC 트래픽을 검사할 수 있습니다.

5. 전송 방식 선택: stdio vs HTTP

위의 설정은 stdio 전송 (transport) 방식을 사용합니다. 클라이언트는 귀하의 서버를 자식 프로세스 (child process)로 시작하고 stdin/stdout을 통해 통신합니다. 이는 로컬 도구에 적합하며, Claude Desktop 및 Cursor를 사용하는 가장 저항이 적은 방법입니다.

두 개 이상의 클라이언트가 공유하는 원격 서버를 구축하려면 HTTP 전송 (HTTP transport) 방식이 필요합니다. SDK는 이를 위해 StreamableHttpServerTransport를 제공합니다. 이를 HTTP 프레임워크 (Hono, Express, Fastify)와 결합하여 세션을 관리해야 합니다. 이러한 설정은 상당한 복잡성을 추가하므로 별도의 문서로 다룰 가치가 있습니다. 첫날부터 공유 서비스를 구축하려는 것이 아니라면 stdio로 시작하세요.

두 방식 모두에 적용되는 한 가지 규칙이 있습니다: stdio 서버에서 console.log를 사용하여 stdout에 내용을 작성하지 마세요. MCP 프로토콜은 JSON-RPC 프레임을 위해 stdout을 사용합니다. 잘못된 로그 한 줄이 프레임 구조를 손상시키며, 클라이언트는 도움이 되는 메시지 없이 파싱 에러 (parse error)를 보게 됩니다. 디버깅 출력에는 console.error()를 사용하세요. stderr로 전송되는 모든 내용은 안전합니다.

6. 흔한 실수들

첫 MCP 서버를 구축할 때마다 공통적으로 발생하는 세 가지 실수입니다:

스키마 검증 (Schema validation)의 공백은 호출을 조용히 중단시킵니다. 만약 모델이 사용자의 Zod 스키마와 일치하지 않는 입력을 보내면, SDK는 일반적인 에러와 함께 이를 거부합니다. 모델은 동일한 잘못된 입력으로 재시도할 수 있습니다. 스키마를 좁게 작성하고, 각 필드에 .describe() 호출을 추가하여 모델이 어떤 값이 유효한지 이해할 수 있도록 돕도록 하세요.

// 모델이 무엇을 보내야 하는지 알 수 있도록 필드 수준의 설명을 추가합니다
{
  hex: z.string()
...

에러 응답은 올바른 형태를 갖춰야 합니다. 도구 핸들러 (tool handler)에서 예외가 발생할 때, 예외가 그대로 전파되도록 두지 말고 구조화된 에러를 반환하세요:

async ({ hex }) => {
  try {
    const r = parseInt(hex.slice(1, 3), 16);
...

isError: true 플래그는 클라이언트에 호출이 실패했음을 알려줍니다. 이를 통해 Claude Desktop에서 에러 텍스트가 포함된 성공 응답으로 표시되는 대신, 적절한 실패 상태로 나타나게 됩니다.

리소스 URI (Resource URIs)는 안정적이어야 합니다. 클라이언트가 리소스 URI를 캐싱했는데 서버가 재시작될 때 이를 변경한다면, 캐싱된 참조는 아무 곳도 가리키지 않게 됩니다. 리소스 URI를 공개 API 경로처럼 취급하세요. 파괴적 변경 (breaking change)을 의도할 때만 변경하고, 필요한 경우 버전을 관리하세요.

요약

MCP는 전체 생태계를 새로 배워야 하는 새로운 프로토콜이 아닙니다. SDK는 가볍습니다 (thin). 핸들러 함수 (handler function)를 작성하고, 스키마 (schema)를 부착하고, 콘텐츠 배열 (content array)을 반환하기만 하면 됩니다. 어려운 부분은 적절한 도구 (tools)를 설계하는 것입니다. 신뢰할 수 있을 만큼 충분히 좁으면서도, 유용할 만큼 충분히 넓어야 합니다. 명확한 입력 스키마를 가지고 한 가지 일만 수행하는 도구가, 6개의 선택적 필드 (optional fields)를 가진 범용 도구보다 언제나 더 뛰어난 성능을 발휘합니다.

위에서 만든 컬러 도구를 구축해 보세요. Claude Desktop에서 실행해 보세요. 그런 다음 16진수 (hex) 변환을 당신이 실제로 노출하고 싶은 데이터나 동작으로 교체하세요. 도구가 무엇을 하든 스캐폴딩 (scaffolding, 기본 구조)은 동일합니다.

만약 오늘 MCP 서버를 실행할 수 있다면, 당신은 무엇을 노출하시겠습니까?

GDS K S · thegdsks.com · X에서 팔로우 @thegdsks

스캐폴딩은 30분이면 충분하지만, 도구 설계가 실제 작업입니다.
monospace 폰트의 "resource". 멋진 티알 (teal)과 일렉트릭 블루 (electric blue) 팔레트, 미니멀함, 벡터 스타일의 깔끔함, 얼굴 없음, 로고 없음, 카드 라벨 이외의 텍스트 없음. 배경에 미묘한 그리드 오버레이 (grid overlay).

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0