콘텐츠로 바로가기

anydding

프론트엔드 개발자를 위한 실전 기술 블로그

기본 메뉴
  • DEV
  • About
  • Contact
  • 홈
  • DEV
  • MCP 서버 직접 만들기: 내 도구를 Claude/Cursor에 연결하는 5단계 실전 가이드
  • DEV

MCP 서버 직접 만들기: 내 도구를 Claude/Cursor에 연결하는 5단계 실전 가이드

Python FastMCP와 TypeScript SDK로 30분 만에 MCP 서버 만들기. Claude Desktop, Cursor에 연결하는 설정 파일과 실전 함정 5가지까지, 2026년 4월 최신 기준으로 정리한 실전 가이드입니다.
anydding 2026-04-30
build-your-first-mcp-server-tutorial-cover

지난달 사이드 프로젝트의 GitHub 이슈를 Claude로 정리시키려다, 매번 이슈 본문을 복사해 채팅창에 붙여넣는 작업이 너무 번거로워졌습니다. 그러다 문득 “그럼 내가 직접 MCP 서버를 만들어서 Claude한테 내 레포를 직접 읽혀버리면 되잖아?”라는 생각이 들었고, 실제로 FastMCP로 약 30분 만에 동작하는 첫 MCP 서버를 만들어 Claude Desktop에 붙였습니다. 결과는 기대 이상이었습니다. 한 번 설정하니 이슈 정리, 라벨링, 주간 리포트 작성까지 채팅창 한 줄로 끝났거든요.

이 글은 그 경험을 바탕으로, MCP 서버를 처음 만드는 개발자가 30분 안에 첫 서버를 띄우고 Claude/Cursor에 연결하는 실전 절차를 정리한 글입니다. MCP가 무엇인지부터 궁금하다면 먼저 MCP 입문: AI 시대의 USB-C, 왜 표준이 됐을까?를 읽고 오시는 걸 추천합니다.

MCP 서버는 정확히 무엇을 노출하나요?

MCP 서버는 LLM에게 세 가지 종류의 능력을 노출합니다. 각각 역할이 명확히 다릅니다.

  • Tools: 부수 효과를 가진 실행 함수입니다. HTTP의 POST와 비슷합니다. 이메일 보내기, DB에 레코드 쓰기, 파일 생성 같은 작업이 여기 해당합니다.
  • Resources: 읽기 전용 데이터입니다. HTTP의 GET과 비슷합니다. 파일 내용, API 응답, DB 조회 결과처럼 LLM의 컨텍스트로 로드되는 데이터를 노출합니다.
  • Prompts: 재사용 가능한 프롬프트 템플릿입니다. 사용자가 특정 작업을 할 때 일관된 지시문을 자동으로 끼워 넣어줍니다.
MCP 서버가 노출하는 Tools, Resources, Prompts 세 가지 프리미티브와 호스트(Claude/Cursor) 간 통신 흐름을 보여주는 다이어그램
Tools는 실행, Resources는 데이터, Prompts는 템플릿 — 역할이 명확히 분리되어 있다.

처음에는 셋의 차이가 헷갈리지만, 실무에서는 거의 90%가 Tools입니다. 따라서 첫 서버를 만들 때는 Tools 하나만 만들어보는 것으로도 충분합니다.

또 하나 알아두면 좋은 사실이 있습니다. MCP는 JSON-RPC 2.0 기반의 오픈 사양으로, Anthropic이 2024년 11월 25일에 공개했습니다. 이후 OpenAI(2025년 3월), Microsoft Copilot, Google Gemini, Cursor, Windsurf, JetBrains AI 등이 모두 채택하면서 사실상의 업계 표준이 되었습니다. 따라서 한 번 만든 서버는 Claude뿐 아니라 Cursor, ChatGPT 등 어떤 호환 호스트에도 그대로 연결됩니다.

Python으로 30줄짜리 첫 MCP 서버를 만들어볼까요?

가장 빠른 길은 Anthropic 공식 Python SDK에 포함된 FastMCP를 쓰는 것입니다. uv 패키지 매니저 기준으로 진행합니다.

bash

# 프로젝트 초기화
uv init my-mcp-server
cd my-mcp-server
uv venv
source .venv/bin/activate

# MCP SDK 설치
uv add "mcp[cli]" httpx

이제 server.py 파일을 만들고 다음 코드를 작성합니다. 두 숫자를 더하는 단순한 도구와, 이름을 받아 인사하는 동적 리소스를 노출하는 서버입니다.

python

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-first-server")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers and return the result."""
    return a + b

@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Return a personalized greeting message."""
    return f"Hello, {name}!"

if __name__ == "__main__":
    mcp.run(transport="stdio")

여기서 핵심은 @mcp.tool() 데코레이터입니다. 함수의 타입 힌트와 docstring을 자동으로 읽어 JSON 스키마를 생성하므로, 별도로 스키마 파일을 작성할 필요가 없습니다. 실제로 제 첫 서버에서는 GitHub Issues API를 호출하는 도구를 만드는 데 코드 25줄로 충분했습니다.

TypeScript SDK는 어떻게 다른가요?

TypeScript는 Zod 스키마로 입력값을 검증한다는 점이 가장 큰 차이입니다. 공식 SDK 다운로드 수가 6,600만 건을 넘어, 가장 큰 생태계를 가진 언어이기도 합니다.

bash

mkdir my-ts-mcp && cd my-ts-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx

tsconfig.json에서 moduleResolution을 반드시 NodeNext로 설정해야 합니다. 이걸 놓치면 import 경로 해석에서 막혀 한참 헤매게 됩니다(저도 처음에 1시간을 버렸습니다).

typescript

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import { z } from "zod";

const server = new McpServer({ name: "ts-server", version: "1.0.0" });

server.tool(
  "add",
  { a: z.number(), b: z.number() },
  async ({ a, b }) => ({
    content: [{ type: "text", text: `Result: ${a + b}` }],
  })
);

const transport = new StdioServerTransport();
await server.connect(transport);

Python보다 보일러플레이트가 약간 많지만, 타입 안전성이 큰 무기입니다. 실제 사례로, 제가 만든 데이터 처리 서버에서 Claude가 userId를 숫자로 보낸 적이 있었는데 Zod가 즉시 거부해서 데이터 손상을 막아줬습니다. Python이라면 런타임에 가서야 터졌을 버그입니다.

Claude Desktop과 Cursor에는 어떻게 연결하나요?

Claude Desktop과 Cursor는 동일한 mcpServers JSON 포맷을 쓰기 때문에, 한 번 작성한 설정을 그대로 옮겨 쓸 수 있습니다. 이게 MCP 표준화의 가장 큰 실무적 이점입니다.

Claude Desktop 설정

Claude Desktop 메뉴 → Settings → Developer → Edit Config를 클릭하면 설정 파일이 열립니다. 파일 위치는 다음과 같습니다.

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

여기에 다음과 같이 작성합니다.

json

{
  "mcpServers": {
    "my-first-server": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/absolute/path/to/my-mcp-server",
        "python",
        "server.py"
      ]
    }
  }
}

저장 후 Claude Desktop을 완전히 종료하고 재시작합니다. macOS는 Cmd+Q, Windows는 트레이 아이콘에서 Quit을 선택해야 합니다. 단순히 창을 닫는 것으로는 적용되지 않습니다.

정상 등록 여부는 Settings → Extensions 패널에서 서버 토글이 활성 상태인지 확인하는 게 가장 확실합니다. 2026년 3월 업데이트 이후 입력창 하단의 도구 아이콘 위치가 변경되거나 사라진 케이스가 있어, 예전 가이드에 자주 등장하던 망치 아이콘만 보고 판단하면 오해할 수 있습니다. UI에 의존하지 않는 검증법은 새 채팅에서 “사용 가능한 도구 목록을 알려줘”라고 직접 요청해 도구가 호출되는지 확인하는 방법입니다.

Cursor 설정

Cursor는 ~/.cursor/mcp.json에 같은 포맷으로 저장합니다. 다만 Cursor는 설정 변경을 자동으로 감지하므로 재시작이 필요 없습니다. Settings → MCP 패널에서 연결 상태를 즉시 확인할 수 있습니다.

실전에서 막히기 쉬운 함정 5가지는 무엇인가요?

다음은 제가 직접 겪었거나 공식 SDK 이슈 트래커에서 자주 보고되는 문제들입니다.

  1. stdio 서버에서 절대 print()나 console.log()를 쓰지 마세요. 표준 출력은 JSON-RPC 메시지 통로입니다. 일반 로그를 stdout에 쓰면 프로토콜이 깨집니다. Python은 import sys; print(..., file=sys.stderr), TypeScript는 console.error()를 사용해야 합니다.
  2. 항상 절대 경로를 쓰세요. Claude Desktop은 최소한의 PATH로 서브프로세스를 띄우기 때문에, 터미널에서 잘 되던 npx나 uv도 실패할 수 있습니다. which uv로 확인한 절대 경로를 그대로 적는 게 안전합니다.
  3. 2026년 4월 기준 공식 원격 전송은 Streamable HTTP입니다. 예전 SSE 전송은 디프리케이트 진행 중이므로, 새로 만드는 서버는 처음부터 transport="streamable-http"를 선택하세요.
  4. JSON 후행 콤마를 조심하세요. mcpServers 마지막 항목 뒤에 콤마가 붙으면 모든 서버가 조용히 비활성화됩니다. 에러 메시지도 안 뜹니다.
  5. MCP Inspector로 먼저 검증하세요. npx @modelcontextprotocol/inspector python server.py로 띄우면 브라우저 UI에서 도구 호출을 직접 테스트할 수 있어 디버깅 시간이 절반으로 줄어듭니다.

자주 묻는 질문 (FAQ)

Q1. MCP 서버를 직접 만들어야만 Claude를 제대로 활용할 수 있나요?

아닙니다. Claude Desktop 기준으로 Desktop Extensions(.dxt 파일) 마켓플레이스가 2026년 1월부터 정식 운영 중이고, 공식 서버 레지스트리에는 GitHub, Slack, Notion, Figma 등 2,000개 이상의 사전 제작 서버가 등록되어 있습니다. 일반 사용자는 마켓에서 클릭 한 번으로 설치만 하면 됩니다. 직접 만드는 건 사내 도구나 본인의 사이드 프로젝트처럼 외부에 공개된 서버가 없는 경우에 의미가 있습니다.

Q2. MCP 서버의 보안은 어떻게 관리해야 하나요?

세 가지 원칙을 지키면 충분합니다. 첫째, 모든 도구 입력값을 신뢰할 수 없는 입력으로 간주하고 Zod나 Pydantic으로 엄격히 검증합니다. 둘째, API 키 같은 비밀값은 코드에 박지 말고 환경 변수로 분리합니다. 셋째, 원격 서버를 만들 때는 OAuth 2.1을 적용해 인증을 강제합니다. OWASP가 2026년에 발표한 MCP Security Cheat Sheet에 더 상세한 가이드가 있습니다.

Q3. 제가 만든 MCP 서버를 다른 사람과 공유하려면 어떻게 하나요?

세 가지 경로가 있습니다. GitHub 레포에 README와 설치 명령만 적어두는 방식이 가장 간단합니다. 둘째, PyPI나 npm에 패키지로 배포하면 사용자가 uvx your-server 또는 npx your-server로 바로 실행할 수 있습니다. 셋째, Claude Desktop 사용자에게 가장 친화적인 경로는 .dxt 패키지로 만들어 공식 디렉토리에 등록 신청하는 것입니다. 비개발자도 클릭 한 번으로 설치할 수 있다는 게 가장 큰 장점입니다.

마무리: 30분의 투자, 무한한 자동화

MCP의 핵심 매력은 한 번 만든 서버가 Claude, Cursor, ChatGPT, Gemini 모두에서 작동한다는 점입니다. 함수 호출 API를 벤더별로 다시 짜야 했던 과거와 비교하면 엄청난 진보입니다. 따라서 따라서 작은 도구 하나라도 직접 만들어보면 AI 도구 활용도가 훨씬 깊어집니다.

오늘 30분만 투자해서 본인이 매일 반복하는 작업 하나를 MCP 도구로 노출해보세요. 처음에는 단순한 “GitHub 이슈 가져오기” 정도면 충분합니다. 그 경험이 쌓이면, 곧 본인의 워크플로 전체가 채팅창 한 줄로 움직이기 시작합니다.

다음 글에서는 만든 MCP 서버를 Cloudflare Workers에 원격 배포하고 OAuth로 보호하는 방법을 다룰 예정입니다. 그 전까지는 Claude Dispatch 완전 가이드와 Claude Opus 4.7 핵심 정리도 함께 보시면 도움이 됩니다.


참고 자료

  • Build an MCP server — Model Context Protocol 공식 문서
  • modelcontextprotocol/python-sdk — GitHub
  • modelcontextprotocol/typescript-sdk — GitHub
  • Getting Started with Local MCP Servers on Claude Desktop — Anthropic 지원 센터
Tags: 2026 AI 에이전트 Claude Desktop Cursor FastMCP MCP Model Context Protocol Python SDK TypeScript SDK 개발자 도구

게시물 내비게이션

이전: CSS Scroll-Driven Animations로 JavaScript 없이 스크롤 애니메이션 만들기 (2026 가이드)
다음: Bun vs Node.js 2026: Anthropic 인수 후, 이제 정말 교체할 타이밍인가?

관련 소식

Bun과 Node.js 로고 비교 — 2026년 자바스크립트 런타임 마이그레이션 가이드 커버
  • DEV

Bun vs Node.js 2026: Anthropic 인수 후, 이제 정말 교체할 타이밍인가?

anydding 2026-05-05
CSS scroll-driven animations 코드와 데모를 보여주는 다크 터미널 스타일 커버
  • DEV

CSS Scroll-Driven Animations로 JavaScript 없이 스크롤 애니메이션 만들기 (2026 가이드)

anydding 2026-04-26
AI 모델과 외부 도구를 MCP 프로토콜로 연결하는 개념도
  • DEV

MCP 입문: AI 시대의 USB-C, 왜 표준이 됐을까?

anydding 2026-04-22

Recent Posts

  • Bun vs Node.js 2026: Anthropic 인수 후, 이제 정말 교체할 타이밍인가?
  • MCP 서버 직접 만들기: 내 도구를 Claude/Cursor에 연결하는 5단계 실전 가이드
  • CSS Scroll-Driven Animations로 JavaScript 없이 스크롤 애니메이션 만들기 (2026 가이드)
  • MCP 입문: AI 시대의 USB-C, 왜 표준이 됐을까?
  • Claude Opus 4.7 출시, 벤치마크·새 기능·마이그레이션 핵심 정리

Categories

  • DEV
  • 개인정보처리방침
  • 면책 조항
© anydding | AF themes의 MoreNews.