MCP 서버 만들기 가이드 2026: Python SDK로 Claude Desktop 연동하고 필수 보안 설정·오류 해결까지

3줄 요약

  • MCP는 LLM에 파일/웹/깃/내부 API 같은 도구를 붙이는 표준 인터페이스입니다.
  • 핵심은 기능보다 권한 최소화(허용 경로/도메인)와 승인(HIL) 흐름입니다.
  • 처음엔 로컬에서 작게 붙이고, 검증 후에만 홈서버로 확장하는 게 안전합니다.

자주 막히는 지점(트러블슈팅)

  • 도구가 안 보임/호출이 안 됨 → 클라이언트 설정(JSON), 실행 경로, 포트/stdio 모드 불일치 확인
  • 권한 오류 → 접근 범위/토큰 노출 여부부터 차단하고 필요한 것만 허용
  • 느림/타임아웃 → 툴 호출을 작은 단위로 쪼개고, 네트워크 호출은 재시도/캐시 고려

결론/다음 단계

  • MCP가 붙으면: n8n/OpenClaw와 결합해 반복 작업을 실제로 줄일 수 있습니다.

같이 보면 좋은 글

이 글은 MCP(Model Context Protocol) 서버를 직접 만들어, Claude Desktop 같은 MCP 클라이언트에서 “도구 호출”이 실제로 동작하게 만드는 과정을 정리한다. 핵심은 코드 작성 자체보다 안전한 범위(권한/디렉터리/토큰)로 도구를 노출하고, 막혔을 때 로그로 진단하는 루틴을 갖추는 것이다.

이 글의 목표(성공 기준)

  • 로컬에서 MCP 서버가 정상 실행되고, MCP 클라이언트가 연결된다.
  • 예시 도구(파일 읽기/웹 fetch 등)가 실제로 호출되어 결과가 돌아온다.
  • 권한/보안(허용 경로/키 관리/외부 네트워크)을 최소로 설정하는 체크리스트가 정리된다.

AI 에이전트를 붙이다 보면 결국 같은 질문으로 돌아옵니다. “내 도구를 모델에 어떻게 안정적으로 연결하지?” 오늘은 그 답으로 mcp 서버 만들기를 처음부터 끝까지 정리합니다. Python SDK 기준으로 서버를 띄우고, Claude Desktop에 붙이고, 초보자가 가장 자주 막히는 오류까지 한 번에 해결하는 흐름입니다.

저도 처음에는 설치 자체보다 “연결은 되는데 왜 호출이 안 되지?” 구간에서 시간을 많이 썼습니다. 그래서 이 글은 단순 설치 절차보다 실행 후 확인 포인트필수 보안 설정에 무게를 뒀습니다. 한 번 세팅해 두면 이후에 파일 검색, DB 조회, 사내 API 호출 같은 자동화 확장이 훨씬 빨라집니다.

mcp 서버 만들기 공식 문서 화면
공식 문서 화면 일부 크롭. 출처: Model Context Protocol Docs

왜 지금 mcp 서버 만들기가 중요할까

MCP는 모델과 외부 시스템 사이의 공통 연결 규약입니다. 예전에는 툴마다 붙이는 방식이 달라서 에이전트 하나 바꿀 때마다 통합 코드를 다시 손봐야 했는데, MCP를 쓰면 도구 계층을 표준화할 수 있습니다. 특히 홈랩·셀프호스팅 환경에서는 서비스가 자주 늘어나기 때문에 이 표준화 효과가 생각보다 큽니다.

  • 파일/DB/내부 API를 에이전트에 일관된 방식으로 연결
  • stdio, Streamable HTTP 같은 전송 방식 선택 가능
  • 개발 단계(테스트)와 운영 단계(배포)를 분리하기 쉬움

오늘 만들 구성 (Python SDK 기준)

이번 가이드는 mcp[cli] 패키지와 FastMCP를 사용합니다. 먼저 로컬에서 툴 1개(시스템 상태 확인)를 노출한 뒤, Claude Desktop에서 실제 호출까지 확인합니다. 그다음 운영용으로 넘어갈 때 필요한 네트워크 제한·헤더 검증·비밀값 관리까지 바로 붙입니다.

항목개발 단계운영 단계
전송 방식stdio 또는 로컬 HTTPStreamable HTTP 권장
접속 범위로컬 PC내부망/리버스 프록시 뒤 제한
검증 포인트툴 호출 성공 여부Origin 검증, 인증, 로그 분리
문제 발생 시Inspector로 즉시 재현구조화 로그와 헬스체크로 추적

1) 프로젝트 생성과 의존성 설치

# 프로젝트 폴더를 만들고 이동합니다.
# 왜 필요? 서버 코드, 가상환경, 의존성 버전을 분리해야 충돌이 줄어듭니다.
# 확인 포인트: 폴더 안에 pyproject.toml 생성 여부
uv init mcp-server-demo
cd mcp-server-demo
# MCP CLI 포함 패키지를 설치합니다.
# 왜 필요? 서버 실행(mcp run/dev/install)과 SDK를 같이 사용하기 위해서입니다.
# 확인 포인트: uv pip list 또는 pyproject.toml에 mcp 항목
uv add "mcp[cli]"

여기서 자주 하는 실수는 전역 파이썬에 바로 설치하는 겁니다. 처음에는 빨라 보여도 나중에 버전 충돌로 다시 정리하게 됩니다. 저는 실제로 기존 자동화 환경과 섞이면서 CLI 호출이 꼬여서, 결국 프로젝트별 분리로 되돌아왔습니다.

2) FastMCP 서버 코드 작성

from mcp.server.fastmcp import FastMCP
import platform
# 서버 이름을 지정해 클라이언트 목록에서 구분하기 쉽게 만듭니다.
mcp = FastMCP("homelab-status", stateless_http=True, json_response=True)
@mcp.tool()
def host_summary() -> dict:
    """호스트 기본 정보를 반환합니다."""
    return {
        "system": platform.system(),
        "release": platform.release(),
        "machine": platform.machine(),
    }
if __name__ == "__main__":
    # 운영 전 단계에서는 streamable-http로 붙여 보는 편이 문제를 빨리 찾기 좋습니다.
    mcp.run(transport="streamable-http")

이 단계에서 핵심은 “도구를 크게 만들기”가 아니라 “작게 만들어 호출 왕복이 되는지 먼저 확인”입니다. 기능을 욕심내서 한 번에 5~6개 붙이면 어디서 깨졌는지 찾는 시간이 오래 걸립니다.

mcp 서버 만들기 python sdk 공식 저장소 화면
공식 Python SDK 저장소 화면 일부 크롭. 출처: modelcontextprotocol/python-sdk

3) 로컬 실행 후 Inspector로 호출 확인

# 서버 실행
# 확인 포인트: 기본적으로 /mcp 엔드포인트가 열리는지 로그 확인
uv run python server.py
# 별도 터미널에서 Inspector 실행
# 확인 포인트: 도구 목록에 host_summary 노출 여부
npx -y @modelcontextprotocol/inspector

Inspector에서 연결 URL은 보통 http://localhost:8000/mcp를 사용합니다. 여기서 제가 한 번 크게 헤맸던 부분이 /mcp를 빼먹은 케이스였습니다. 서버는 정상인데 클라이언트에선 404/연결 실패처럼 보이니, 먼저 엔드포인트 경로부터 확인하는 습관을 들이면 시간을 꽤 아낄 수 있습니다.

4) Claude Desktop에 붙여 실제 사용하기

# Claude Desktop에 MCP 서버 등록
# 왜 필요? 실제 에이전트 환경에서 도구 호출 성공 여부를 검증하기 위해서입니다.
# 확인 포인트: Claude의 MCP 서버 목록에 지정한 이름이 나타나는지
uv run mcp install server.py --name "homelab-status"
# 환경변수가 필요하면 .env 파일 방식 사용
# 확인 포인트: API 키 누락 에러 없이 서버가 시작되는지
uv run mcp install server.py -f .env

설치 후 Claude Desktop을 재시작하고, “host_summary 실행해줘”처럼 짧은 프롬프트로 첫 호출을 확인하세요. 이 한 번이 성공하면 이후 확장은 훨씬 단순해집니다. 반대로 첫 호출이 불안정한 상태에서 기능을 늘리면, 어떤 레이어에서 문제가 생겼는지 분리가 어려워집니다.

5) 초보자도 바로 적용할 필수 보안 설정

  • 로컬 바인딩 우선: 테스트 단계에서는 127.0.0.1에만 바인딩해 외부 노출을 막습니다.
  • Origin 검증: Streamable HTTP를 쓸 때는 요청 Origin 검증을 넣어 DNS rebinding 위험을 줄입니다.
  • 인증/토큰 분리: 공개 리포지토리에 키를 두지 말고 .env 또는 시크릿 매니저를 사용합니다.
  • stderr/stdout 분리: 프로토콜 메시지(stdout)와 디버그 로그(stderr)를 섞지 않습니다.

공식 스펙에서도 Streamable HTTP 사용 시 Origin 검증, 로컬 바인딩, 인증 적용을 권장합니다. “내부망이니까 괜찮겠지”라고 넘기기 쉬운 부분인데, 이 세 가지는 초기에 넣을수록 나중에 운영 부담이 적습니다.

mcp 서버 만들기에서 자주 막히는 오류 4가지

오류 1) 404 또는 연결 실패 (엔드포인트 경로 불일치)

증상: 서버는 켜졌는데 클라이언트에서 연결 실패. 원인: 접속 URL에 /mcp 누락. 조치: 서버 로그와 클라이언트 URL을 나란히 확인하고 경로를 정확히 맞춥니다.

오류 2) JSON-RPC 파싱 오류 (stdout 오염)

증상: 도구가 가끔만 호출되거나 파싱 오류 발생. 원인: 디버그 print()가 stdout으로 나가 프로토콜 메시지와 섞임. 조치: 디버그 로그는 logger/stderr로 보내고, stdout은 MCP 메시지 전용으로 유지합니다.

오류 3) 400 Bad Request (세션/헤더 불일치)

증상: 초기 연결은 되는데 이후 요청에서 400 발생. 원인: Streamable HTTP에서 세션 헤더(Mcp-Session-Id) 처리 누락 또는 CORS 헤더 미노출. 조치: 클라이언트/프록시 헤더 전달 정책을 점검합니다.

오류 4) 도구는 보이는데 실행 결과가 비어 있음

증상: 리스트에는 툴이 나오지만 결과가 비정상. 원인: 반환 타입과 실제 반환 데이터 구조 불일치. 조치: 우선 단순한 dict 반환으로 안정화한 뒤, 구조화 출력(Pydantic/TypedDict)을 단계적으로 적용합니다.

stdio vs Streamable HTTP, 무엇을 고를까

구분stdioStreamable HTTP
초기 난이도낮음중간
디버깅 속도빠름(로컬 단독)중간(네트워크 포함)
확장성낮음~중간높음
운영 적합성개인/단일 클라이언트다중 클라이언트/서비스 연동
권장 시점첫 프로토타입배포/팀 공유 단계

처음 mcp 서버 만들기를 시도한다면 stdio로 왕복 성공을 먼저 확인하고, 운영 전환 시 Streamable HTTP로 넘어가는 순서를 권장합니다. 기능보다 연결 안정성부터 확보하는 쪽이 결과적으로 더 빠릅니다.

실전 체크리스트 (복붙용)

  • 프로젝트 격리(uv/pipenv) 완료
  • 툴 1개로 최소 기능 검증 완료
  • Inspector 호출 왕복 성공
  • Claude Desktop 등록 후 실제 질의 성공
  • 로컬 바인딩/Origin 검증/인증 적용
  • stdout 로그 오염 없음

함께 보면 좋은 글

마무리

결국 mcp 서버 만들기의 핵심은 “복잡한 기능”이 아니라 “예측 가능한 연결”입니다. 작은 툴 하나를 안정적으로 붙이고, 그다음 범위를 넓히면 실패 비용이 크게 줄어듭니다. 다시 처음으로 돌아간다면, 저는 기능 욕심을 줄이고 첫날에는 엔드포인트·로그·보안 3가지만 완전히 통과시키는 방식으로 시작하겠습니다.

운영 전 최종 점검 시나리오

mcp 서버 만들기를 끝낸 뒤에는 실제 운영 상황을 가정한 점검을 10~15분만 돌려도 장애를 크게 줄일 수 있습니다. 저는 배포 전에 항상 “정상 호출 3회 → 의도적 실패 1회 → 복구 확인 1회” 순서를 반복합니다. 예를 들어 정상 요청에서 응답 시간이 1초 내인지 확인하고, 다음으로 잘못된 파라미터를 넣어 오류 메시지가 사용자에게 이해 가능한 문장으로 반환되는지 체크합니다. 마지막으로 서비스 재시작 후 동일한 도구 호출이 즉시 복구되는지 확인하면, 대부분의 초기 운영 이슈를 사전에 잡을 수 있습니다.

  • 응답 지연 체크: 같은 요청 3회 연속 실행 시 평균/최대 시간 기록
  • 오류 메시지 품질: 잘못된 입력에서 원인·해결 힌트가 드러나는지 확인
  • 로그 확인: stdout은 프로토콜 전용, 디버그는 stderr로 분리 유지
  • 재시작 복구: 프로세스 재시작 후 동일 시나리오 재실행

댓글 남기기

WordPress Appliance - Powered by TurnKey Linux