https://github.com/modelcontextprotocol/python-sdk
GitHub - modelcontextprotocol/python-sdk: The official Python SDK for Model Context Protocol servers and clients
The official Python SDK for Model Context Protocol servers and clients - modelcontextprotocol/python-sdk
github.com
Model Context Protocol(MCP) 서버를 개발할 때, FastMCP는 개발자의 생산성을 극대화해주는 강력한 도구이다. 복잡한 JSON 스키마를 직접 짤 필요없이, Python 함수에 Docstring과 Type Hint 만 잘 작성하면 나머지(Tool Definition)는 FastMCP가 알아서 처리해 준다. @mcp.tool()
+ langchain 의 @tool 로 mcp 도구를 정의해도 문법은 99% 동일함
⭐ FastMCP docstring rules ⭐
Input Description (Argument)
방법 1 : 표준 Docstring 포멧 사용 (Google Style 등)
@mcp.tool()
def send_email(recipient: str, subject: str, body: str) -> str:
"""
사용자에게 이메일을 전송합니다.
Args:
recipient: 이메일을 받을 수신자의 주소 (예: user@example.com)
subject: 이메일의 제목
body: 이메일 본문 내용
"""
# 이메일 전송 로직...
return "Email sent successfully"
- FastMCP는 파이썬의 표준 독스트링 포맷을 파싱하여 인자 설명을 추출합니다. (Google Style)
- 장점 : 뛰어난 가독성, 별도의 라이브러리 없이도 mcp tool로서 기능할 수 있음.
- 단점 : Docstring에 규칙(들여쓰기 등)이 맞지 않는 부분이 있으면 Error 발생
- 추천 상황 : 단순한 텍스트 입력이나, 복잡한 검증이 필요없는 일반적인 도구를 만들때
Input Description (Argument)
방법 2 : Annotated와 Field 사용
from typing import Annotated
from pydantic import Field
@mcp.tool()
def create_user(
username: Annotated[str, Field(description="사용자의 고유 ID, 5자 이상이어야 함")],
age: Annotated[int, Field(description="사용자의 나이", ge=18)]
) -> str:
"""새로운 사용자를 시스템에 등록합니다."""
return f"User {username} created."
- Pydantic의 Field를 사용하면 설명뿐만 아니라 제약 조건(최소값, 길이 등)까지 스키마에 포함
- 장점 : 강력한 제약조건을 통해 LLM에게 형식에 맞지 않는 값을 보내는 것을 원천 차단
- 단점 : 지저분한 코드, Annotated와 Field 라이브러리 사용법을 익혀야 함
- 추천 상황 : 결제 금액, ID, 날짜 등 형식이 틀리면 안 되는 중요한 데이터를 다루거나, LLM이 자꾸 엉뚱한 값을 넣을 때
⭐ Concept's Detail ⭐
Google Style Detail
def get_techtree_path(track_name: str) -> Dict[str, Any]:
"""
(기본 설명 생략...)
Args:
track_name: Exact name of the track.
Returns:
Dictionary containing the roadmap.
Notes:
**IMPORTANT FOR LLM:**
- Use this structured data to create...
- Focus on Sequence...
"""
- 표준 Docstring 포멧은 약속된 해더(Args, Returns, 등) 만을 사용해서 작성해야한다.
- (Top) : 함수(def)에 대한 기본 설명 (여기에 Notes 에 해당되는 내용을 넣어도 됨)
- Args: 입력되는 인자에 대한 설명 (':' 표시를 누락해서는 안됨)
- Returns: 출력 결과에 대한 형식 및 설명
- Notes: 추가적인 설명
- 표준 섹션 헤더(Keywords) 종류
- Args:, Arguments:, Returns:, Raises:, Yields:, Attributes:, Examples:, Note:, Notes:, Todo:, References:
Annotated & Field Library Detail
from typing import Annotated
from pydantic import Field
- Annotated : 변수에 추가정보(메타데이터)를 붙이기 위해 선언하는 포장지 역할
- Field : 설명(description), 제약조건(validation), 기본값 등을 정의하는 실제 내용물 역할
from typing import Annotated
from pydantic import Field
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("TechTree")
@mcp.tool()
def create_roadmap(
topic: Annotated[
str,
Field(
description="학습하고 싶은 기술 주제",
min_length=2,
max_length=50
)
],
level: Annotated[
int,
Field(
description="난이도 (1: 초급, 5: 전문가)",
ge=1,
le=5
)
],
language: Annotated[
str,
Field(
description="응답 언어 (kr 또는 en)",
pattern=r"^(kr|en)$"
)
] = "kr" # 기본값 설정
) -> str:
"""사용자 맞춤형 학습 로드맵을 생성합니다."""
return f"Generating {topic} roadmap (Level {level}) in {language}..."
- description : LLM에게 이 인자가 무엇인지, 어떤 값을 넣어야 하는지 자연어로 설명
- min_length / max_length : 문자열(str) 입력값의 글자 수 최소 및 최대 한계를 지정
- ge (greater or equal) / le (less or equal) : 숫자(int) 입력값의 최소값과 최대값의 범위를 지정
- pattern : 정규표현식(Regex)을 사용하여 특정 형식(예: kr 또는 en)만 입력되도록 강제
⭐ Structured Output ⭐
단순 텍스트 반환
: 가장 기본적인 형태. 사람이 읽기에는 좋지만 LLM이 데이터를 2차 가공하기엔 불편함.
@mcp.tool()
def simple_hello(name: str) -> str:
"""인사를 반환합니다."""
return f"Hello, {name}!"
- def def_name() -> str
- 단순 python 함수에서 : 단순히 사람을 위한 출력 타입 힌트 주석 (타입 에러 x)
- @mcp.tool() 사용시 : FastMCP가 내부적으로 Pydantic을 사용하여 유효성 검사 / 가능하면 타입 변환 시도
구조화된 데이터 반환 (Pydantic Model)
: 단순 문자열 대신 JSON 객체를 반환. LLM은 이 구조를 완벽하게 이해하고 필요한 데이터만 사용
from pydantic import BaseModel, Field
class RoadmapStep(BaseModel):
step_number: int
title: str
description: str
class RoadmapOutput(BaseModel):
topic: str
total_steps: int
steps: list[RoadmapStep] # 중첩 구조도 가능
estimated_weeks: int = Field(description="예상 소요 주(week)")
- 반환할 데이터의 구조(Schema) 정의 ; RoadSmapStep, RoadmapOutput
- pydantic.BaseModel을 상속받아 결과물의 "설계도"를 만듦
- Field 함수는 타입 힌트 외에도 내용이나 규칙에 대한 description을 추가 하고 싶을 때 사용
@mcp.tool()
def create_roadmap(...) -> RoadmapOutput: # <--- 핵심 포인트!
# ... 로직 ...
- 함수 반환 타입(Type Hint) 명시 : FastMCP에게 스키마를 생성하라는 의미
- "-> " 뒤에 위에서 만든 모델 클래스를 적어줌 ; RoadmapOutput로 정의된 구조
# ... (로직 수행 후)
return RoadmapOutput(
topic="Python AI",
total_steps=3,
steps=[
RoadmapStep(step_number=1, title="Basic", description="Syntax..."),
RoadmapStep(step_number=2, title="Advanced", description="OOP...")
],
estimated_weeks=4
)
- 객체 생성 및 반환 함수 내부에서 모델의 인스턴스를 생성해서 리턴
- RoadmapOutput 구조 클래스에 대한 인스턴스를 생성하여 리턴
- RoadmapStep 은 RoadmapOutput 내부 데이터의 구조 인스턴스로서 사용됨
-------------------------------------------------
- Gemini 3 model (Pro)의 도움을 받아 작성되었습니다.
-------------------------------------------------
'프로그래밍 > AI' 카테고리의 다른 글
| [Search] Tavily API (*Domain Control*) (0) | 2026.01.08 |
|---|---|
| [Agent] LCEL(a.k.a. Langchain pattern) (0) | 2025.12.28 |
| [Agent] ReAct (Agent Prompt format) (0) | 2025.12.21 |
| [Agent] LangChain for AI agent (Intro) (0) | 2025.12.16 |
| [Agent] In-Context Learning (feat. prompt) (0) | 2025.12.16 |