본문 바로가기

나만의 MCP 서버 직접 만들기 — Python·TypeScript로 최소 서버 만들고 Claude Code에 연결하기

MCP 공식 SDK로 최소 동작하는 나만의 서버를 Python과 TypeScript 두 가지 방식으로 처음부터 만들고, claude mcp add 명령으로 Claude Code에 연결해 실제로 도구가 호출되는 모습까지 확인하는 실습형 가이드입니다.

글

MCP(Model Context Protocol — Claude 같은 AI가 외부 도구·데이터에 연결하는 공식 표준 규약) 서버를 직접 만들면, 남이 만든 서버를 설치하는 것을 넘어 내가 원하는 기능을 Claude Code에 도구로 붙일 수 있습니다. 이 글에서는 공식 SDK를 이용해 Python과 TypeScript 두 가지 방식으로 아무 외부 의존성 없이 동작하는 최소 MCP 서버를 만들고, claude mcp add 명령으로 Claude Code에 연결해 실제로 도구가 호출되는 것까지 확인합니다. 처음부터 끝까지 따라 하면 대략 30~40분 정도 걸립니다(개인 환경에 따라 다를 수 있습니다).

🟢 현행 모델 라인업 일치 · 모델 안내 · Fable 구독 안내
🟢 현행 모델 라인업 일치 · Claude Opus 5.5 / Claude Sonnet 5 / Claude Haiku 4.5 (상위 티어: Claude Fable 5.1). 이 안내는 새 모델이 출시될 때만 바뀝니다.

Fable 5·5.1 구독 안내(2026년 9월 7일 갱신): 2026년 9월 1일 출시된 Claude Fable 5.1이 현행 Fable 모델이고, Fable 5는 레거시로 전환됐습니다. 구독 조건은 두 모델이 같습니다 — Max·Team Premium 플랜은 주간 사용 한도의 50% 범위에서 포함되고, Pro·Team Standard 플랜은 사용량 크레딧(입력 100만 토큰당

🟢 현행 모델 라인업 일치 · Claude Opus 5.5 / Claude Sonnet 5 / Claude Haiku 4.5 (상위 티어: Claude Fable 5.1). 이 안내는 새 모델이 출시될 때만 바뀝니다.
0, 출력 $50)으로 이용합니다. 일회성
🟢 현행 모델 라인업 일치 · Claude Opus 5.5 / Claude Sonnet 5 / Claude Haiku 4.5 (상위 티어: Claude Fable 5.1). 이 안내는 새 모델이 출시될 때만 바뀝니다.
00 크레딧은 Fable 5 전환 당시에만 지급됐고 5.1에는 없습니다. 일부 코딩·디버깅 요청은 보안 분류기에 의해 Opus 모델로 대체 응답될 수 있습니다(두 모델 공통). 자세한 내용은 Fable 5.1 가이드와 Fable 5 재개 안내를 참조하세요.

Claude Code (MCP 클라이언트) 내가 만든 MCP 서버 (Python 또는 TypeScript) 외부 시스템 (API·DB·파일 등) 도구 호출/응답 API 호출

MCP 서버는 정확히 무엇을 만드는 걸까요?

MCP 서버는 Claude Code 같은 AI 클라이언트가 호출할 수 있는 "도구(tool)" 함수를 담은 작은 프로그램입니다. 공식 문서에 따르면 MCP 서버는 크게 세 가지를 제공할 수 있습니다: 도구(tool — LLM이 사용자 승인을 받아 호출하는 함수), 리소스(resource — 파일처럼 읽을 수 있는 데이터), 프롬프트(prompt — 미리 만들어둔 작업 템플릿). 이 글은 가장 자주 쓰이는 도구 만들기에 집중합니다. 서버와 Claude Code는 표준입출력(stdio — 터미널의 표준 입력/출력 통로)을 통해 JSON-RPC(구조화된 요청/응답 메시지 형식)로 대화하며, 이 방식 덕분에 Python으로 만든 서버든 TypeScript로 만든 서버든 Claude Code 입장에서는 똑같이 취급됩니다.

시작하기 전에 준비할 것

다음 항목이 갖춰져 있어야 막히지 않고 따라 할 수 있습니다.

  • Claude Code CLI가 설치되어 있고 로그인까지 마친 상태(터미널에서 claude 명령이 실행되는 상태)
  • 터미널(명령 프롬프트) 사용에 기초적으로 익숙할 것 — 폴더 이동, 명령어 실행 정도
  • Python 트랙을 따라 하려면 Python 3.10 이상, TypeScript 트랙을 따라 하려면 Node.js 20 이상
  • 텍스트 에디터(VS Code 등) 하나

두 트랙 모두 만들어볼 필요는 없습니다. 평소 더 익숙한 언어 하나만 골라서 따라 하면 됩니다.

용어 빠른 풀이

  • MCP(Model Context Protocol) — AI 애플리케이션이 외부 도구·데이터에 연결하는 공식 개방형 표준 규약
  • SDK(Software Development Kit) — 특정 기능을 쉽게 구현하도록 미리 만들어진 코드 도구 모음. 여기서는 MCP 서버를 만들기 위한 공식 라이브러리를 뜻합니다
  • stdio(standard input/output) — 프로그램이 터미널과 데이터를 주고받는 표준 통로. MCP에서 가장 기본적인 연결 방식입니다
  • 도구(tool) — Claude 같은 AI가 호출할 수 있도록 서버가 등록해 둔 함수 하나하나
  • uv — Python 프로젝트 생성·가상환경·패키지 설치를 한 번에 처리하는 공식 문서 권장 도구

Python(mcp 패키지)으로 최소 서버 만들기

먼저 Python 트랙입니다. 공식 문서가 권장하는 uv 도구로 프로젝트를 만듭니다.

  1. uv 설치(이미 설치되어 있다면 건너뜁니다). 터미널에서 실행합니다.

    curl -LsSf https://astral.sh/uv/install.sh | sh

    설치 후 터미널을 껐다 다시 켜야 uv 명령이 인식됩니다.

  2. 프로젝트 생성과 SDK 설치. 원하는 폴더에서 실행합니다.

    uv init hello-mcp
    cd hello-mcp
    uv venv
    source .venv/bin/activate
    uv add "mcp[cli]"
    touch hello.py

    이렇게 보이면 성공: 에러 없이 명령이 끝나고, hello-mcp 폴더 안에 hello.py 파일이 생깁니다.

  3. hello.py 작성. 아래 내용을 그대로 붙여 넣습니다. 외부 API 없이도 동작하도록 인사말 도구와 덧셈 도구, 두 개만 넣었습니다.

    from mcp.server import MCPServer
    
    mcp = MCPServer("hello-server")
    
    @mcp.tool()
    def greet(name: str) -> str:
        """이름을 받아 인사말을 돌려줍니다.
    
        Args:
            name: 인사할 대상의 이름
        """
        return f"안녕하세요, {name}님! MCP 서버가 정상적으로 응답하고 있습니다."
    
    @mcp.tool()
    def add_numbers(a: float, b: float) -> str:
        """두 숫자를 더한 결과를 돌려줍니다.
    
        Args:
            a: 첫 번째 숫자
            b: 두 번째 숫자
        """
        return f"{a} + {b} = {a + b}"
    
    if __name__ == "__main__":
        mcp.run(transport="stdio")

    주의: stdio 방식 서버에서는 print()를 절대 쓰면 안 됩니다. print()는 표준출력에 글자를 쓰는데, MCP는 그 표준출력 통로로 JSON-RPC 메시지를 주고받기 때문에 print() 한 줄만 있어도 메시지가 깨져 서버가 먹통이 됩니다. 로그를 남기고 싶다면 logging 모듈을 쓰세요(표준에러로 나가서 안전합니다).

  4. 로컬에서 실행 확인.

    uv run hello.py

    이렇게 보이면 성공: 에러 없이 실행되고, 터미널이 멈춘 것처럼 조용히 대기합니다. 이는 정상입니다 — 서버가 클라이언트(Claude Code)의 연결을 기다리는 중입니다. Ctrl+C로 종료하세요.

Claude Code에 연결하고 확인하기 (Python 서버)

Claude Code CLI의 claude mcp add 명령으로 로컬 stdio 서버를 등록합니다. 실행 명령에 절대경로가 필요하므로, 먼저 프로젝트 폴더에서 pwd를 실행해 전체 경로를 복사해 두세요.

1 프로젝트 초기화 SDK 설치 2 도구(tool) 함수 작성 3 claude mcp add로 연결 4 /mcp · list로 연결 확인
  1. 서버 등록. /절대/경로/hello-mcp 부분을 방금 확인한 실제 경로로 바꿔서 실행합니다.

    claude mcp add --transport stdio hello-mcp -- uv --directory /절대/경로/hello-mcp run hello.py

    이렇게 보이면 성공: Added로 시작하는 줄이 출력됩니다. 이는 설정이 저장됐다는 뜻이지, 연결 성공을 보장하지는 않습니다.

  2. 연결 상태 확인.

    claude mcp list

    이렇게 보이면 성공: hello-mcp 옆에 ✔ Connected 표시가 뜹니다. ✘ Failed to connect가 뜨면 아래 "자주 막히는 지점" 항목을 확인하세요.

  3. Claude Code 안에서 실제로 호출해보기. Claude Code 세션을 시작한 뒤 자연어로 요청합니다.

    hello-mcp 서버의 greet 도구로 "우주"에게 인사해줘

    Claude가 greet 도구를 호출하고, 서버가 만든 인사말 문장을 그대로 답변에 반영하면 성공입니다.

TypeScript(공식 SDK)로 최소 서버 만들기

같은 서버를 TypeScript로 만들어 봅니다. 이미 Python 트랙을 완료했다면 이 섹션은 건너뛰어도 됩니다.

  1. Node.js 확인. 20 이상인지 확인합니다.

    node --version
    npm --version
  2. 프로젝트 생성과 SDK 설치.

    mkdir hello-mcp-ts
    cd hello-mcp-ts
    npm init -y
    npm install @modelcontextprotocol/server zod
    npm install -D @types/node typescript
    mkdir src
    touch src/index.ts
  3. package.json 수정. 최상위에 "type": "module"과 scripts.build를 추가합니다.

    {
      "type": "module",
      "scripts": {
        "build": "tsc && chmod 755 build/index.js"
      }
    }
  4. tsconfig.json 생성. 프로젝트 루트에 새 파일로 만듭니다.

    {
      "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "types": ["node"],
        "outDir": "./build",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }
  5. src/index.ts 작성.

    import { McpServer } from "@modelcontextprotocol/server";
    import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
    import { z } from "zod";
    
    const server = new McpServer({
      name: "hello-server",
      version: "1.0.0",
    });
    
    server.registerTool(
      "greet",
      {
        description: "이름을 받아 인사말을 돌려줍니다",
        inputSchema: z.object({
          name: z.string().describe("인사할 대상의 이름"),
        }),
      },
      async ({ name }) => {
        return {
          content: [
            {
              type: "text",
              text: `안녕하세요, ${name}님! MCP 서버가 정상적으로 응답하고 있습니다.`,
            },
          ],
        };
      },
    );
    
    async function main() {
      const transport = new StdioServerTransport();
      await server.connect(transport);
      console.error("hello-server MCP 서버가 stdio로 실행 중입니다");
    }
    
    main().catch((error) => {
      console.error("서버 실행 중 오류:", error);
      process.exit(1);
    });

    주의: Python과 마찬가지로 console.log()는 절대 쓰지 마세요. 표준출력이 깨져 JSON-RPC 통신이 망가집니다. 로그가 필요하면 console.error()(표준에러로 나감)를 쓰세요.

  6. 빌드.

    npm run build

    이렇게 보이면 성공: 에러 없이 끝나고 build/index.js 파일이 생성됩니다. 이 빌드 단계를 건너뛰면 다음 단계에서 연결이 실패합니다.

Claude Code에 연결하고 확인하기 (TypeScript 서버)

Python 때와 마찬가지로 절대경로가 필요합니다. hello-mcp-ts 폴더에서 pwd로 경로를 확인하세요.

  1. 서버 등록.

    claude mcp add --transport stdio hello-mcp-ts -- node /절대/경로/hello-mcp-ts/build/index.js
  2. 연결 상태 확인.

    claude mcp list

    이렇게 보이면 성공: hello-mcp-ts 옆에 ✔ Connected가 뜹니다. Claude Code 세션 안에서는 /mcp를 입력해도 같은 상태를 확인할 수 있습니다.

  3. 실제로 호출해보기. Python 트랙과 같은 방식으로 자연어 요청을 해봅니다.

    hello-mcp-ts 서버의 greet 도구로 "우주"에게 인사해줘
구분PythonTypeScript
필요 버전Python 3.10 이상Node.js 20 이상
패키지 관리uvnpm
핵심 SDK 설치uv add "mcp[cli]"npm install @modelcontextprotocol/server zod
서버 클래스MCPServerMcpServer
로컬 실행 명령uv run hello.py빌드 후 node build/index.js

자주 막히는 지점과 해결

  • claude mcp list에서 ✘ Failed to connect가 뜬다: claude mcp add에 넣었던 실행 명령(uv --directory ... run hello.py 또는 node .../build/index.js)을 터미널에서 그대로 직접 실행해 보세요. 그 자리에서 나는 에러 메시지가 원인을 정확히 알려줍니다.
  • 서버가 아예 응답하지 않거나 연결이 끊긴다: Python의 print(), TypeScript의 console.log()가 코드 어딘가에 남아 있지 않은지 확인하세요. stdio 서버에서는 이 둘이 JSON-RPC 메시지를 깨뜨리는 가장 흔한 원인입니다.
  • 경로 문제로 연결이 안 된다: claude mcp add에는 반드시 절대경로를 넣어야 합니다. 상대경로는 실행 위치에 따라 달라져 실패하기 쉽습니다. 프로젝트 폴더에서 pwd로 정확한 경로를 확인하세요.
  • 서버 자체 옵션이 Claude CLI 옵션으로 오인된다: claude mcp add 명령에서 서버 실행 명령 앞에 --(더블 대시)를 반드시 넣으세요. 이게 없으면 서버에 전달하려던 인자를 Claude CLI가 자기 옵션으로 잘못 해석합니다.
  • TypeScript 서버 연결이 안 된다: npm run build를 건너뛰지 않았는지, build/index.js 파일이 실제로 생성됐는지 확인하세요.

응용 및 다음 단계

동작 확인이 끝났다면 같은 파일에 @mcp.tool()(Python) 또는 server.registerTool(...)(TypeScript) 블록을 추가해 원하는 기능(파일 읽기, 사내 API 호출 등)을 도구로 늘려갈 수 있습니다. 팀원과 함께 쓰고 싶다면 claude mcp add에 --scope project를 붙여보세요. 이 경우 설정이 프로젝트 루트의 .mcp.json 파일에 저장되어 버전 관리 시스템으로 팀 전체와 공유할 수 있습니다. 반대로 이미 만들어진 서버를 찾아 쓰고 싶을 때는 완성된 서버를 고르는 관점의 글을 참고하는 편이 더 빠릅니다.

자주 묻는 질문

Q. MCP 서버는 Python이나 TypeScript로만 만들 수 있나요?
아니요. 공식 SDK는 Python, TypeScript 외에도 Java, Kotlin, C#, Ruby 등 여러 언어로 제공됩니다. 이 글은 가장 널리 쓰이는 Python과 TypeScript를 다뤘습니다.

Q. 만든 서버를 팀원과 함께 쓰려면 어떻게 하나요?
claude mcp add에 --scope project 옵션을 붙이면 설정이 프로젝트 루트의 .mcp.json에 저장되어 버전 관리로 공유할 수 있습니다. 다만 팀원마다 서버를 최초 1회 승인하는 절차가 필요합니다.

Q. 도구를 더 추가하고 싶으면 어떻게 하나요?
같은 파일 안에 Python이면 @mcp.tool() 데코레이터가 붙은 함수를, TypeScript면 server.registerTool(...) 호출을 하나 더 작성하면 됩니다. 서버를 다시 등록할 필요 없이 재시작만 하면 새 도구가 반영됩니다.

Q. 서버가 계속 연결 실패로 뜨는데 원인을 못 찾겠어요.
claude mcp add 명령에 넣었던 실행 명령을 터미널에서 그대로 직접 실행해 보세요. 그때 나오는 에러 메시지가 가장 정확한 단서입니다.

관련 글

이 글이 도움이 됐나요?

이어서 읽어보세요