Lab 03: MCP 서버 구현
초급
마감: 2026-03-24
1. MCP 서버 설정 —
섹션 제목: “1. MCP 서버 설정 — settings.json”
3. 커스텀 MCP 서버 —
섹션 제목: “3. 커스텀 MCP 서버 — custom_server.py”
custom_server.py
Terminal window
Terminal window
- FastMCP로 MCP 서버 구현 (Tool + Resource + Prompt 3대 프리미티브)
- MCP Inspector로 서버 검증
- 입력 검증과 경로 순회 방어 적용
- 파일시스템 + Git MCP 서버 구성
MCP 개요
섹션 제목: “MCP 개요”MCP는 AI 코딩 에이전트가 외부 도구·데이터 소스와 표준화된 방식으로 통신하는 프로토콜이다. 3대 프리미티브 — Tool(모델이 호출), Resource(앱이 제어), Prompt(사용자가 선택) — 를 통해 기능을 노출한다.
AI 코딩 에이전트
↓
MCP 클라이언트
↓
MCP 서버 (Tool + Resource + Prompt)
↓
파일시스템 / Git / 커스텀 API
구현 요구사항
섹션 제목: “구현 요구사항”1. MCP 서버 설정 — settings.json
섹션 제목: “1. MCP 서버 설정 — settings.json”AI 코딩 CLI의 설정 파일에 내장 서버를 추가한다.
설정 파일: ~/.claude/settings.json (또는 프로젝트별 .claude/settings.json)
설정 파일: ~/.gemini/settings.json
{ "mcpServers": { "filesystem": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-filesystem", "/home/[학번]/lab-03" ] }, "git": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-git", "--repository", "/home/[학번]/lab-03" ] } }}2. 환경 설정 및 서버 동작 확인
섹션 제목: “2. 환경 설정 및 서버 동작 확인”-
프로젝트 구조 및 환경 설정
Terminal window mkdir -p lab-03-mcp && cd lab-03-mcppython -m venv .venvsource .venv/bin/activate# uv 사용 시 (권장)uv add "mcp[cli]" fastmcp# pip 사용 시pip install fastmcplab-03-mcp/├── custom_server.py # FastMCP 서버 (Tool + Resource + Prompt)├── settings.json # MCP 설정└── test_sample.py # custom 서버의 run_pytest로 실행할 테스트 -
내장 서버 목록 확인
Terminal window claude mcp list# filesystem npx -y @modelcontextprotocol/server-filesystem ...# git npx -y @modelcontextprotocol/server-git ... -
파일시스템 서버 테스트
Terminal window claude "현재 디렉터리의 파일 목록을 보여줘."# filesystem 서버의 list_directory 도구가 호출되어야 함 -
Git 서버 테스트
Terminal window git init /home/[학번]/lab-03claude "최근 커밋 3개의 메시지를 요약해줘."
3. 커스텀 MCP 서버 — custom_server.py
섹션 제목: “3. 커스텀 MCP 서버 — custom_server.py”FastMCP로 3대 프리미티브(Tool + Resource + Prompt)를 모두 포함하는 서버를 구현한다.
import osimport subprocessimport sysfrom fastmcp import FastMCP
mcp = FastMCP("lab03-custom", description="Lab 03 실습 서버")
# === 허용 경로 설정 (경로 순회 방어) ===ALLOWED_BASE = os.path.realpath(os.path.dirname(__file__))
def _validate_path(path: str) -> str: """경로 순회 공격을 방어한다. 허용된 디렉터리 외부 접근을 차단.""" real_path = os.path.realpath(path) if not real_path.startswith(ALLOWED_BASE): raise ValueError( f"접근 거부: {path} — 허용 범위({ALLOWED_BASE}) 외부" ) return real_path
# === Tool 1: pytest 실행 ===@mcp.tool()def run_pytest(path: str) -> str: """지정한 디렉터리에서 pytest를 실행하고 결과를 반환한다.
Args: path: pytest를 실행할 디렉터리 경로 """ safe_path = _validate_path(path) try: result = subprocess.run( ["python", "-m", "pytest", safe_path, "-v", "--tb=short"], capture_output=True, text=True, timeout=60, ) return result.stdout + result.stderr except subprocess.TimeoutExpired: return "ERROR: pytest 실행 시간 초과 (60초)" except Exception as e: print(f"[ERROR] {e}", file=sys.stderr) return f"ERROR: {e}"
# === Tool 2: 라인 수 카운트 ===@mcp.tool()def count_lines(file_path: str) -> str: """파일의 라인 수를 반환한다.
Args: file_path: 라인을 셀 파일의 경로 """ safe_path = _validate_path(file_path) try: with open(safe_path, "r") as f: lines = f.readlines() return f"{len(lines)} lines" except FileNotFoundError: return f"ERROR: 파일을 찾을 수 없습니다 — {file_path}" except Exception as e: print(f"[ERROR] {e}", file=sys.stderr) return f"ERROR: {e}"
# === Resource: 프로젝트 통계 ===@mcp.resource("project://stats")def project_stats() -> str: """프로젝트 디렉터리의 파일 통계를 반환한다.""" py_files = [] for root, _dirs, files in os.walk(ALLOWED_BASE): for f in files: if f.endswith(".py"): py_files.append(os.path.join(root, f)) total_lines = 0 for fp in py_files: try: with open(fp) as f: total_lines += len(f.readlines()) except Exception: pass return ( f"Python 파일 수: {len(py_files)}\n" f"총 라인 수: {total_lines}\n" f"프로젝트 경로: {ALLOWED_BASE}" )
# === Prompt: 코드 리뷰 ===@mcp.prompt()def code_review(file_path: str) -> str: """코드 리뷰를 요청하는 구조화된 프롬프트 템플릿.
Args: file_path: 리뷰할 파일의 경로 """ return ( f"다음 파일을 코드 리뷰해 주세요: {file_path}\n\n" f"리뷰 항목:\n" f"1. 보안 취약점 (경로 순회, 명령 주입, 입력 검증)\n" f"2. 에러 핸들링 (예외 처리, 안전한 실패)\n" f"3. 코드 품질 (가독성, 네이밍, 구조)\n" f"4. 테스트 가능성 (테스트하기 쉬운 설계인가)" )
if __name__ == "__main__": mcp.run()4. 커스텀 서버 등록
섹션 제목: “4. 커스텀 서버 등록”settings.json에 커스텀 서버를 추가한다.
{ "mcpServers": { "filesystem": { "...": "..." }, "git": { "...": "..." }, "custom": { "command": "python", "args": ["/home/[학번]/lab-03-mcp/custom_server.py"] } }}5. MCP Inspector로 검증
섹션 제목: “5. MCP Inspector로 검증”# Inspector 실행npx @modelcontextprotocol/inspector python custom_server.py
# 브라우저에서 http://localhost:6274 접속 후:# 1. tools/list → run_pytest, count_lines 확인# 2. resources/list → project://stats 확인# 3. prompts/list → code_review 확인# 4. tools/call → run_pytest 실행, 결과 확인# 5. 스크린샷 캡처 (과제 제출용)6. 커스텀 도구 동작 확인
섹션 제목: “6. 커스텀 도구 동작 확인”claude "lab-03-mcp 디렉터리에서 pytest를 실행해줘."# run_pytest 도구가 호출되어야 함제출물
섹션 제목: “제출물”assignments/lab-03/[학번]/에 PR:
-
settings.json— filesystem, git, custom 세 서버가 등록된 설정 파일 -
custom_server.py— FastMCP 기반, 3대 프리미티브(Tool + Resource + Prompt) 구현 -
test_sample.py— custom 서버의run_pytest로 실행할 테스트 파일 (최소 3개 테스트) - Inspector 스크린샷 —
tools/list,resources/list,prompts/list확인 -
README.md— 각 MCP 서버의 동작 확인 결과, 보안 검증(경로 순회 차단 테스트), 트러블슈팅 기록