Python으로 다중 기능 MCP 서버 엔지니어링

발행: (2025년 12월 20일 오전 04:58 GMT+9)
18 min read
원문: Dev.to

I’m happy to help translate the article, but I need the full text you’d like translated. Could you please paste the content (excluding the source line you’ve already provided) so I can translate it into Korean while preserving the formatting and code blocks?

챗봇 격리 시대의 종말

오랫동안 대형 언어 모델(LLM)은 울타리 안에서 살아왔습니다—채팅 인터페이스 뒤에 가두어진 뛰어난 추론 엔진으로, 로컬 파일에 접근하거나 데이터베이스에 접속하거나 머신에서 코드를 실행할 수 없었습니다. Model Context Protocol (MCP) 은 그 패러다임을 완전히 바꿉니다. 실제 작업이 이루어지는 시스템에 AI 어시스턴스를 연결하는 표준화된 방법을 제공합니다.

하지만 많은 개발자들이 MCP의 “Hello World” 수준에 머무릅니다—간단한 API 도구만 노출하는 것이죠. 유용하긴 하지만 프로토콜의 잠재력을 겨우 살짝 건드리는 수준입니다. 진정으로 견고하고 접근성 높은 서버는 단순히 도구를 제공하는 것이 아니라 Resources 를 통한 컨텍스트Prompts 를 통한 구조화된 워크플로우를 제공합니다.

이 가이드에서는 처음부터 포괄적인 Python 기반 MCP 서버를 설계합니다. 단순 스크립트를 넘어 다음을 포함하는 멀티‑툴 아키텍처를 구축할 것입니다:

  • 수학 기능
  • 문서 접근
  • 회의 분석을 위한 동적 프롬프트 템플릿

우리는 또한 최신 vibe‑coding 워크플로우—LLM을 사용해 LLM 도구를 구축하는 방식—를 채택하고, 종종 간과되는 MCP Inspector 를 활용한 디버깅 기술도 다룰 것입니다.

터미널을 열기 전에: 정말 이것을 직접 만들어야 할까요?

시니어 엔지니어링은 단순히 코드를 작성하는 것이 아니라 언제 하지 말아야 할지 아는 것입니다. 표준 서비스(예: Google Drive, Slack)만 통합하면 된다면, 커뮤니티 생태계에 이미 존재할 가능성이 높은 서버를 개발하는 것은 큰 의미가 없을 때가 많습니다. 중복은 효율성의 적입니다.

간단한 자동화의 경우, 저코드 솔루션(예: n8n)이 더 빠른 가치를 제공할 수 있습니다. 하지만 다음과 같은 경우에는 맞춤형 Python MCP 서버 구축이 필수적입니다:

이유적용 시점
복잡성표준 API가 제공하지 않는 특정하고 복잡한 로직(맞춤 계산, 데이터 변환)이 필요할 때.
컨텍스트로컬의 독점 문서(Resources)를 모델의 컨텍스트 윈도우에 공급해야 할 때.
표준화팀을 위한 특정 상호작용 패턴(Prompts)을 강제하고 싶을 때(예: 통합된 “회의 요약” 구조).

귀하의 사용 사례가 이러한 기준에 부합한다면, 이제 코딩을 시작할 때입니다.

“Vibe Coding” – LLM‑보조 개발 활용

모든 보일러플레이트 코드를 일일이 손으로 작성하던 시절은 지났습니다. 이제 1999년이 아닙니다. 이 서버를 효율적으로 구축하기 위해 우리는 vibe‑coding 방법론을 사용할 것이며, CursorClaude 통합 IDE를 활용해 고품질 문서를 기반으로 스캐폴딩을 자동 생성합니다.

사전 요구 사항

도구버전 / 비고
Python3.12 이상
패키지 관리자uv (빠르고 안정적인 의존성 관리)
SDKmcp (Python SDK)
프레임워크FastMCP (서버 생성을 단순화하는 고수준 래퍼)

AI 지원을 위한 컨텍스트 설정

  1. 문서 색인하기llms.txt(또는 유사 파일)를 생성하고 다음을 포함합니다:

    • 핵심 MCP 사양
    • Python SDK README
    • FastMCP 사용 가이드
  2. 컨텍스트를 Cursor에 전달하기 – IDE에서 이 파일들을 색인하여 모델이 사용 중인 정확한 SDK 버전을 이해하도록 합니다.

이러한 준비를 통해 모델에게 고수준 아키텍처 요청(예: “계산기 도구가 있는 서버 생성”)을 할 수 있어 구문 오류와 씨름할 필요가 없습니다.

Source:

도구: 우리 서버의 기반

도구는 LLM이 호출하여 작업을 수행할 수 있는 함수입니다. 우리는 계산기 서버를 만들 것이지만, 다양한 논리 연산을 처리할 수 있도록 구조를 잡을 것입니다.

구현 전략

FastMCP는 도구 정의를 겉보기와는 다르게 매우 간단하게 만들어 줍니다. 핵심은 설명문(docstring)이며, 이는 모델이 언제 도구를 호출해야 할지 판단하기 위해 읽는 API 문서가 됩니다.

from mcp.server.fastmcp import FastMCP
import math

# 서버 초기화
mcp = FastMCP("calculator-server")

@mcp.tool()
def add(a: float, b: float) -> float:
    """두 숫자를 더합니다."""
    return a + b

@mcp.tool()
def divide(a: float, b: float) -> float:
    """첫 번째 숫자를 두 번째 숫자로 나눕니다. 0 나눗셈 검사를 포함합니다."""
    if b == 0:
        return "Error: Cannot divide by zero"
    return a / b

핵심 인사이트 – docstring("""두 숫자를 더합니다.""")은 당신을 위한 것이 아니라 LLM을 위한 것입니다. 설명이 모호하면 모델이 기능을 착각하거나 필요할 때 도구를 호출하지 못할 수 있습니다.

이 패턴을 확장하여 뺄셈, 곱셈, 거듭제곱, 제곱근, 백분율 계산 등도 포함시킬 수 있습니다. 각 함수에 @mcp.tool()을 감싸면 프로토콜이 요구하는 JSON‑RPC 통신을 자동으로 처리합니다.

MCP Inspector로 디버깅하기

디버깅 도구 없이 MCP 서버를 프로그래밍하는 것은 눈을 가리고 비행하는 것과 같습니다. MCP Inspector는 백엔드 로직을 프런트엔드 클라이언트(Claude)와 분리하여 서버를 독립적으로 테스트할 수 있게 해줍니다.

Inspector 실행하기

uv run mcp-inspector server.py

이 명령은 로컬 웹 인터페이스(보통 http://localhost:)를 띄우며, 여기서 다음을 할 수 있습니다:

  • 도구 목록 – 서버가 실제로 작성한 함수들을 노출하고 있는지 확인합니다.
  • 실행 테스트 – 인자를 수동으로 입력(e.g., a=10, b=2)하고 원시 출력이나 오류 추적을 확인합니다.
  • 연결 확인 – 전송 프로토콜(stdio vs. HTTP)을 검증합니다.

보안 주의사항 – Inspector가 시작될 때 보안 토큰이 포함된 URL을 생성할 수 있습니다. 이 토큰이 없는 일반 localhost URL로 연결을 시도하면 연결이 거부됩니다. 터미널 로그에 표시된 특정 링크를 사용해 인증된 접근을 반드시 확보하세요.

Inspector를 활용해 0으로 나누기와 같은 에지 케이스를 서버를 실제 클라이언트에 연결하기 전에 철저히 테스트하십시오.

Source:

리소스: 모델에 읽기 전용 액세스 제공

도구는 모델이 동작하도록 합니다. 리소스는 모델이 읽을 수 있게 합니다.

LLM을 정적인 지식 베이스로만 취급하는 것이 흔한 실수입니다. 리소스를 통합하면 모델에게 머신에 있는 특정 데이터(로그, API 문서, 코드베이스 등)에 대한 직접적인 읽기 전용 접근 권한을 부여하게 됩니다.

파일 기반 리소스 구현

from mcp.server.fastmcp import FastMCP
from pathlib import Path

# Initialize the server (if not already done)
mcp = FastMCP("calculator-server")

# Register a file resource
@mcp.resource()
def documentation() -> str:
    """Read the local documentation file."""
    doc_path = Path("docs/mcp_specification.md")
    return doc_path.read_text(encoding="utf-8")

이제 LLM은 documentation()을 호출해 MCP 사양 전체 텍스트를 가져올 수 있으며, 최신 도메인‑특화 정보를 기반으로 추론할 수 있습니다.

모두 합치기

아래는 최소 실행 예제로, 도구, 리소스 및 인스펙터를 결합한 것입니다:

# server.py
from mcp.server.fastmcp import FastMCP
from pathlib import Path

mcp = FastMCP("calculator-server")

# ---- Tools ----
@mcp.tool()
def add(a: float, b: float) -> float:
    """두 숫자를 더합니다."""
    return a + b

@mcp.tool()
def divide(a: float, b: float) -> float:
    """첫 번째 숫자를 두 번째 숫자로 나눕니다. 0으로 나눌 경우 오류 문자열을 반환합니다."""
    if b == 0:
        return "Error: Cannot divide by zero"
    return a / b

# ---- Resources ----
@mcp.resource()
def documentation() -> str:
    """로컬 MCP 문서 파일을 읽습니다."""
    return Path("docs/mcp_specification.md").read_text(encoding="utf-8")

# 서버 실행 (선택 사항; 인스펙터가 서버를 시작할 수 있음)
if __name__ == "__main__":
    mcp.run()

디버깅을 시작하려면:

uv run mcp-inspector server.py

인스펙터 UI에서 할 수 있는 작업:

  1. add, divide, documentation 엔드포인트 목록 보기.
  2. add(a=5, b=7) 호출12 반환.
  3. divide(a=10, b=0) 호출"Error: Cannot divide by zero" 반환.
  4. documentation() 호출 → 사양 파일의 원시 마크다운 반환.

다음 단계

  • 도구 추가 (예: multiply, sqrt, percentage).
  • 보다 풍부한 리소스 생성 (예: JSON 구성 파일, CSV 데이터셋).
  • 프롬프트 설계 다중 도구 호출을 조정하도록 (예: “회의 노트를 요약하고 총 시간을 계산”).
  • 서버 보안 강화 (TLS, 인증 토큰) 외부 클라이언트에 노출하기 전에.

견고한 도구, 리소스, 프롬프트 기반을 갖추면, MCP 서버는 LLM 추론과 실제 시스템을 연결하는 강력한 다리가 됩니다. 즐거운 코딩 되세요!

MCP Resource Example

import Context, Resource

# Define the path to your knowledge base
resource_path = "./docs/typescript_sdk.md"

@mcp.resource("mcp://docs/typescript-sdk")
def get_typescript_sdk() -> str:
    """Provides access to the TypeScript SDK documentation."""
    with open(resource_path, "r") as f:
        return f.read()

이 코드를 추가하면 MCP Inspector에 새로운 Resources 탭이 표시됩니다. 실제 환경(예: Claude Desktop)에서는 사용자가 이제 이 리소스를 채팅에 첨부할 수 있습니다. 모델은 해당 파일의 컨텍스트를 즉시 획득하므로 프롬프트 창에 수천 단어를 복사‑붙여넣기 할 필요가 없습니다.

Strategic Value:
이렇게 하면 서버가 동적 라이브러리로 변합니다. 로컬 파일을 업데이트하면 모델의 지식도 즉시 업데이트됩니다.

Source:

프롬프트 레이어

도구는 반응형(모델이 사용을 결정)입니다.
프롬프트는 능동형—표준화된, 사용자가 시작하는 템플릿으로 특정 워크플로우를 강제합니다.

완벽한 사용 사례는 **“회의 요약”**입니다. 매번 긴 지시를 입력하는 대신, 그 구조를 서버에 내장합니다.

동적 프롬프트 템플릿 만들기

{{date}}, {{transcript}}) as our template.

템플릿 (prompt.md)

You are an executive assistant. Analyze the following meeting transcript.

**Date:** {{date}}
**Title:** {{title}}

**Transcript:**
{{transcript}}

Please provide a summary with:
1. Overview
2. Key Decisions
3. Action Items

구현

@mcp.prompt()
def meeting_summary(date: str, title: str, transcript: str) -> str:
    """Generates a meeting summary based on a transcript."""
    # Logic to read the template and replace placeholders
    # Returns the formatted prompt to the client
    return render_template(
        "prompt.md",
        date=date,
        title=title,
        transcript=transcript,
    )

프롬프트를 이용한 디버깅 여정

  • list_promptsget_prompt 기능은 이제 최신 FastMCP 프레임워크에 의해 자동으로 처리되어 중복과 충돌을 없앱니다.
  • LLM이 생성한 코드가 때때로 model이나 temperature와 같은 인자를 프롬프트 로직에 삽입하곤 합니다.
    • 통찰: 설정(사용할 모델, 온도 등)은 클라이언트 설정에 속하며, 프롬프트 템플릿에 포함되지 않아야 합니다. 깔끔한 코드는 이러한 환상을 제거합니다.

Inspector(그리고 최종적으로 Claude Desktop)에서 테스트하면, 이 기능은 폼 형태 UI를 생성합니다: 사용자는 “회의 요약”을 선택하고 필드를 채우면, LLM은 완벽하게 설계된 컨텍스트 패키지를 받게 됩니다.

Source:

서버와 클라이언트 연결하기

서버가 Tools, Resources, Prompts 를 보유하게 되면 claude_desktop_config.json 파일을 통해 클라이언트와 연결해야 합니다.

전송 프로토콜: stdio vs. HTTP

stdio (표준 입력/출력)

클라이언트가 서버 프로세스를 실행하고 터미널 스트림을 통해 통신합니다. 이는 안전하고 빠르며 로컬 개발에 최적입니다.

{
  "mcpServers": {
    "my-python-server": {
      "command": "uv",
      "args": ["run", "server.py"],
      "env": {
        "PYTHONPATH": "."
      }
    }
  }
}

HTTP (SSE – Server‑Sent Events)

규모를 확장하면서 서버를 네트워크를 통해 노출하고 싶을 수 있습니다. HTTP 기반 SSE는 서버의 수명 주기를 클라이언트와 분리시켜, 여러 클라이언트가 동일한 지속 서버 인스턴스에 연결할 수 있게 합니다.

진화에 대한 참고: 프로토콜은 이제 전송 유형을 구분합니다. SSE가 한때 독립적인 개념이었지만, 현대 구현에서는 보통 스트리밍 가능한 HTTP 엔드포인트(예: Starlette 또는 FastAPI 사용)를 포함합니다. 클라이언트는 http://localhost:8000/sse 에 연결합니다.

요약: MCP 서버 구축

Transitioning from a consumer of AI to an architect of AI workflows involves three core layers:

레이어모델에 제공되는 것예시
도구계산을 수행하는 손@mcp.tool functions
리소스로컬 문서를 읽는 눈@mcp.resource functions
프롬프트표준 운영 절차를 위한 플레이북@mcp.prompt templates

“바이브 코딩”에 속지 마세요. 엄격함은 다음에 있습니다:

  • 도구를 명확히 설명하기
  • 프롬프트를 신중하게 구조화하기
  • 리소스를 검증하기

추천 워크플로우:

  1. 단순함을 위해 stdio부터 시작하세요.
  2. 논리를 검증하기 위해 인스펙터를 철저히 사용하세요.
  3. 모든 것이 안정되면 일상 워크플로에 통합하세요.

코드는 쉬운 부분입니다. 진정한 엔지니어링은 컨텍스트 정의에 있습니다.

Back to Blog

관련 글

더 보기 »

창고 활용에 대한 종합 가이드

소개 창고는 근본적으로 3‑D 박스일 뿐입니다. Utilisation은 실제로 그 박스를 얼마나 사용하고 있는지를 측정하는 지표입니다. While logistics c...