Lab 06. MCP 실습
이 랩에서 다루는 것
- Database MCP: 읽기 전용으로 PostgreSQL 을 붙여 자연어로 조회
- 내 MCP 서버 만들기: FastMCP 로 직접 만들어 Claude Code 에서 호출하며 원리를 체득
- 이중 방어: MCP 레이어 + 계정 권한
- 관리 & 보안 체크리스트: 끝나고 무엇을 정리하나
claude mcp add 문법 복습
claude mcp add [옵션] <이름> -- <실행명령> [인자...]- 환경변수는
--env KEY=value(공식 문법) - 전송은 기본 stdio(로컬 프로세스), 원격 HTTP 는
--transport http - 비밀값이 들어가는 서버는
local(기본) 또는userscope 로 (커밋되는.mcp.json금지)
확인·삭제.
claude mcp list # 연결 상태
claude mcp remove <이름> # 삭제 핸즈온 A: Database MCP (PostgreSQL, 읽기 전용)
자연어를 SQL 로 바꿔 DB 를 조회합니다. 읽기 전용으로 붙이는 게 안전의 핵심입니다.
강사가 배포한 접속 문자열을 사용합니다. 비밀값이 들어가므로 local scope(기본)로 붙입니다.
claude mcp add postgres \
--env DATABASE_URI="postgresql://student:READONLYPASS@<RDS엔드포인트>:5432/shopdb?sslmode=require" \
-- docker run -i --rm -e DATABASE_URI crystaldba/postgres-mcp --access-mode=restricted--access-mode=restricted: 읽기 전용 트랜잭션 + 실행시간 제한- Docker 대신 Python 이면 마지막 부분만
-- uvx postgres-mcp --access-mode=restricted로 교체
🐧 WSL2 · Linux 사용자 (1회 설정): 위 명령은
sudo없이docker를 호출합니다.permission denied ... /var/run/docker.sock오류가 나면 현재 사용자를docker그룹에 한 번 추가하세요. (Docker Desktop · macOS 사용자는 불필요)
sudo usermod -aG docker $USER # docker 그룹에 현재 사용자 추가
newgrp docker # 새 그룹 권한을 현재 셸에 즉시 적용 (재로그인 대체)연결을 확인하고 세션을 엽니다.
claude mcp list # postgres: connected
claude세션에서 이렇게 질문해 봅니다.
“주문이 가장 많은 도시 top 3 을 알려줘.” “월별 매출(주문금액 합계) 추이를 표로 보여줘.” “가장 많이 팔린 상품 top 3 은?”
에이전트가 SELECT 를 작성·실행하고 결과를 요약합니다.
🔒 이중 방어: 읽기 전용은 MCP 레이어(
restricted) + DB 계정 권한(SELECT only) 두 겹으로 막습니다. 접속 문자열은projectscope(.mcp.json)에 넣지 마세요(커밋되어 유출).
-
claude mcp list에postgres: connected표시 - 세 가지 질의 중 하나 이상을 실행해 결과를 받았다
핸즈온 B: 내 MCP 서버 직접 만들기
지금까지는 남이 만든 MCP 를 붙였습니다. 이번엔 직접 만들어 원리를 안에서 봅니다. 외부 인증·계정이 필요 없습니다.
사전 요구: Python 3.10+ 와 uv. 서버는 FastMCP 로 작성합니다.
1. 서버 파일 작성
my_mcp.py 한 파일이면 됩니다. 도구(tool) 두 개를 노출합니다.
# my_mcp.py — 내 첫 MCP 서버
from fastmcp import FastMCP
mcp = FastMCP("my-first-mcp")
@mcp.tool()
def course_secret() -> str:
"""이 수업의 비밀 코드를 반환한다. 모델은 이 값을 추측할 수 없다."""
return "NXT-MCP-2026"
@mcp.tool()
def add(a: int, b: int) -> int:
"""두 정수를 더한다."""
return a + b
if __name__ == "__main__":
mcp.run() # 기본 stdio 전송 (Lab 05 의 그 stdio)2. 등록
claude 세션 밖, my_mcp.py 가 있는 디렉터리에서 붙입니다. 로컬 프로세스이므로 local scope(기본)면 충분합니다.
claude mcp add my-first-mcp -- uv run --with fastmcp python "$(pwd)/my_mcp.py"uv run --with fastmcp: fastmcp 를 즉석 설치해 실행(별도 설치 불필요)"$(pwd)/my_mcp.py": 등록 시점에 절대경로로 고정
3. 확인 & 호출
claude mcp list # my-first-mcp: connected
claude세션에서 이렇게 요청합니다.
“이 수업의 비밀 코드를 알려줘.” “17 더하기 25는?”
에이전트가 내 서버의 course_secret · add 도구를 직접 호출해 답합니다.
💡 호출을 눈으로 확인:
course_secret값(NXT-MCP-2026)은 모델이 추측할 수 없습니다. 이 값이 돌아왔다면 Claude 가 내 서버를 실제로 호출했다는 증거입니다. 방금 만든 게 Lab 05 의 Server, Claude Code 가 Host + Client,mcp.run()이 stdio 전송입니다.
-
claude mcp list에my-first-mcp: connected표시 - 세션에서 비밀 코드(
NXT-MCP-2026)를 받아 봤다 (= 내 서버가 호출됨) - Host · Client · Server 가 각각 무엇이었는지 말할 수 있다
마무리: 관리 & 보안 체크리스트
claude mcp list # playwright · postgres · my-first-mcp 확인
claude mcp remove <이름> # 정리보안 체크리스트
- 비밀값은
local/userscope 에만 (.mcp.json커밋 금지) - DB 는 읽기 전용 (MCP
restricted+ 계정 SELECT only) - 브라우저는 신뢰된 사이트만 (간접 인젝션 주의)
- 외부 서버는 신뢰할 수 있는 것만 (archived/취약 서버 금지)
- 수업 후 정리: 실습 MCP 제거(
claude mcp remove), DB 접속 정보 폐기·회전
한 문장: MCP 는 강력하지만 기본 인증이 없다. 그래서 ‘무엇을 연결하느냐’만큼 ‘어떤 권한으로 연결하느냐’가 중요하다.
마무리
여기까지 오면 Claude Code 의 한 바퀴를 다 돈 것입니다.
- 생태계 에서 Claude Code 의 자리를 잡고
- 설치 & Bedrock 인증 으로 내 머신에 올리고
- 기본 동작법 으로 세션·권한·CLAUDE.md 를 다루고
- MCP 를 체험 → 이론 → 실습으로 붙여 외부 세계와 연결했습니다
다음으로: 본인 업무에서 자주 쓰는 외부 도구·데이터 하나를 골라 MCP 로 붙여 보세요. ‘무엇을, 어떤 권한으로’ 를 먼저 정하는 습관이 그대로 이어집니다.
NxtCloud Workshop