Starter Series의 일부 — AI에게 매번 CI/CD를 설명하지 마세요. 클론하고 시작하세요.
- MCP SDK —
mcp(FastMCP) + stdio 전송 - Python 3.11+ — 타입 힌트, async/await, hatchling 빌드
- MCP 3대 프리미티브 — Tools, Resources, Prompts 예제 전부 포함
- Safety Annotations — 모든 도구에 readOnly/destructive/idempotent 힌트
- 검증된 Prompt — pydantic
@validate_call로 핸들러 실행 전 인자 검증 - CI — gitleaks, ruff, 라이선스 검증, pytest (3.11/3.12/3.13)
- CD — OIDC trusted publishing으로 PyPI 배포 (시크릿 불필요)
- Dependabot — 의존성 + GitHub Actions 자동 업데이트
create-starter 사용 (권장):
gh repo create my-mcp-server --template starter-series/python-mcp-server-starter --clone
cd my-mcp-server
python3.12 -m venv .venv && source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'
python -m pytest또는 직접 클론:
git clone https://github.com/starter-series/python-mcp-server-starter my-mcp-server
cd my-mcp-server
python3.12 -m venv .venv && source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'
python -m pytestsrc/my_mcp_server/server.py에 직접 추가:
@mcp.tool(
annotations=ToolAnnotations(
readOnlyHint=True,
destructiveHint=False,
idempotentHint=True,
),
)
async def your_tool(input: str) -> str:
"""도구 설명."""
return f"처리 완료: {input}"Resource는 고정된 URI로 클라이언트에 데이터를 노출합니다 (동작을 수행하는 Tool과 대비).
예시: src/my_mcp_server/resources/server_info.py
from mcp.server.fastmcp import FastMCP
def register(mcp: FastMCP) -> None:
@mcp.resource(
"info://your/resource",
name="your-resource",
description="리소스가 노출하는 데이터.",
mime_type="application/json",
)
async def your_resource() -> str:
return "..." # str, bytes, 또는 JSON 직렬화 가능한 객체server.py에서:
from my_mcp_server.resources.your_resource import register as register_your_resource
register_your_resource(mcp)Prompt는 파라미터화된 재사용 가능한 메시지 템플릿입니다. pydantic으로 인자를 검증합니다.
예시: src/my_mcp_server/prompts/code_review.py
from typing import Annotated, Literal
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts.base import UserMessage
from pydantic import Field, validate_call
@validate_call
def your_prompt(
mode: Literal["short", "long"],
topic: Annotated[str, Field(min_length=1)],
) -> list[UserMessage]:
return [UserMessage(content=f"{topic}에 대한 {mode} 노트를 작성해주세요.")]
def register(mcp: FastMCP) -> None:
mcp.prompt(name="your-prompt", title="Your Prompt")(your_prompt)환경 변수:
| 변수 | 기본값 | 설명 |
|---|---|---|
MCP_DEBUG |
false |
디버그 로깅 활성화 |
LOG_LEVEL |
INFO |
로그 레벨 (DEBUG/INFO/WARNING/ERROR) |
직접 추가는 server.py에.
# 테스트 실행
python -m pytest -v
# 린트
python -m ruff check .
# 포맷 확인
python -m ruff format --check .
# 타입 확인
python -m mypy src/
# wheel + sdist 빌드
python -m build
# 실제 python -m 엔트리포인트 stdio smoke
python scripts/smoke_stdio.py
# 서버 실행 (stdio)
python -m my_mcp_server
# 설치된 console script로 동일 서버 실행
my-mcp-server
# 의존성 audit
pip-audit . --strict| 검사 | 도구 |
|---|---|
| 시크릿 스캔 | gitleaks |
| 대용량 파일 감지 | find (>5 MB) |
| 라이선스 검증 | pip-licenses (GPL/AGPL 차단) |
| 린트 + 포맷 | ruff |
| 테스트 | pytest (Python 3.11, 3.12, 3.13) |
pyproject.toml에서 버전 올리기- Actions → Publish to PyPI → Run workflow
- OIDC가 인증 처리 —
PYPI_TOKEN시크릿 불필요
설정 가이드: PyPI OIDC trusted publishing 문서
src/my_mcp_server/
├── __init__.py # 버전
├── __main__.py # python -m 진입점
├── server.py # FastMCP 서버 + 인라인 `greet` 툴 예시
├── resources/
│ ├── __init__.py
│ └── server_info.py # Resource 예시 (info://server/status)
└── prompts/
├── __init__.py
└── code_review.py # Prompt 예시 (인자 검증 포함)
tests/
├── test_tools.py # 툴 테스트
├── test_server_info.py # Resource 테스트
├── test_code_review.py # Prompt 테스트
├── test_runtime_contract.py # 시작/패키지 메타데이터 테스트
└── test_version_resolution.py # 버전 SSOT 테스트
.github/
├── workflows/
│ ├── ci.yml # 린트, 테스트, 보안
│ ├── cd.yml # PyPI OIDC 배포
│ ├── codeql.yml # 정적 분석
│ ├── stale.yml # Stale 이슈 관리
│ └── maintenance.yml # 주간 헬스 체크
└── dependabot.yml # 의존성 업데이트
python -m pip install -e ".[dev]" # dev 의존성 포함 설치
python scripts/smoke_stdio.py # MCP 클라이언트로 python -m my_mcp_server 실행
python -m my_mcp_server # 서버 실행
my-mcp-server # 설치된 console script로 서버 실행
python -m pytest -v # 테스트 실행
python -m ruff check . # 린트
python -m ruff format . # 포맷
python -m mypy src/ # 타입 확인
python -m build # wheel + sdist 빌드
pip-audit . --strict # 의존성 auditMIT