공공 API MCP 서버 만들기: data.go.kr을 Python으로 Claude에 연결하기
data.go.kr 공공 API를 Python(FastMCP)으로 MCP 서버로 래핑해 Claude Desktop에 연결하는 전 과정을 코드와 함께 단계별로 안내합니다. 인증키 발급부터 XML 처리, 오류 해결까지 실전 위주로 정리했습니다.
한국 공공데이터포털(data.go.kr)에는 부동산 실거래가, 날씨, 법령, 사업자등록 진위 등 수천 개의 무료 API가 공개돼 있습니다. 문제는 이 데이터를 Claude가 직접 쓸 수 없다는 점입니다. API를 MCP 서버로 한 번 래핑해 두면, 그 다음부터는 채팅창에서 “사업자번호 진위 확인해줘” 같은 말 한마디로 Claude가 알아서 공공데이터를 조회하고 결과를 해석합니다.
이 글은 그 래핑 작업을 Python으로 처음부터 만드는 실전 가이드입니다. 별도 서버나 클라우드 없이, 로컬에서 Claude Desktop과 연결하는 가장 단순한 구성을 목표로 합니다. 예제로는 국세청 사업자등록 진위 확인 API를 다루지만, 같은 패턴으로 data.go.kr의 어떤 API든 동일하게 도구화할 수 있습니다.
직접 만들기 전에: 3가지만 확인하세요
본격적인 개발에 들어가기 전, 아래 세 가지를 점검하면 시행착오를 크게 줄일 수 있습니다.
- 이미 만들어진 서버가 있는지 확인 — 부동산 실거래가, 국민연금·국세청 등 자주 쓰이는 공공 API는 이미 오픈소스 MCP 서버로 공개돼 있습니다. (아래 목록 참고)
- 연결 방식 선택 — Claude Desktop과 1:1 로컬 연동이면
stdio로 충분합니다. 원격 배포나 다중 클라이언트가 필요해질 때만 SSE(Streamable HTTP)를 고려하세요. - 응답 포맷 확인 — data.go.kr API는 JSON과 XML이 섞여 있습니다. 대상 API가 어느 쪽인지 서비스 문서에서 먼저 확인해 두면 파싱 코드를 미리 준비할 수 있습니다.
왜 공공 API를 MCP 서버로 만드나요?
MCP(Model Context Protocol)는 외부 데이터 소스나 도구를 표준화된 방식으로 LLM에 연결하는 프로토콜입니다. 공공 API를 MCP 서버로 래핑하면 데이터 조회 → 가공 → 해석이 하나의 대화 흐름 안에서 처리됩니다.
사용자 질문
↓
Claude (LLM)
↓ MCP 도구 호출 (stdio)
MCP 서버 (Python)
↓ HTTP 요청
data.go.kr 공공 API
↓ JSON/XML 응답
MCP 서버 (파싱 · 가공)
↓ 도구 결과 반환
Claude → 사용자에게 답변
기성 챗봇 플러그인 대신 직접 개발할 때의 차이는 다음과 같습니다.
| 구분 | 직접 MCP 서버 개발 | 기존 챗봇 플러그인 |
|---|---|---|
| 데이터 범위 | data.go.kr 전체 API 선택 가능 | 플러그인이 지원하는 것만 |
| 응답 가공 | 자유롭게 포맷·필터링 | 정해진 스키마 |
| 비용 | 공공데이터는 무료 | 유료 API 사용 시 과금 |
| 유지보수 | 직접 관리 | 제공자 의존 |
준비물
- Python 3.10 이상 (3.11 권장)
- uv 또는 pip (패키지 관리)
- 공공데이터포털 API 인증키 (data.go.kr 무료 발급)
- Claude Desktop (MCP 클라이언트로 사용)
단계별 공공 API MCP 서버 개발
1단계: data.go.kr API 키 발급
data.go.kr에 로그인한 뒤, 사용하고 싶은 API 서비스 페이지로 이동해 ‘활용신청’ 버튼을 누릅니다. 목적 설명을 간단히 작성하면 대부분 즉시 인증키가 발급됩니다. (일부 API는 기관 검토로 1~3일이 걸립니다.)
발급된 키는 두 종류로 제공됩니다. 어느 쪽을 쓰느냐에 따라 코드가 달라지므로 처음에 확실히 구분해 두세요.
- 일반 인증키: 퍼센트 인코딩된 문자열. URL에 직접 붙일 때 추가 인코딩 주의 필요
- UTF-8 인증키: 디코딩된 원문.
httpx등에서 파라미터로 그대로 전달 가능
이 가이드는 UTF-8 인증키를 사용합니다. httpx가 파라미터를 자동 인코딩하므로 이쪽이 다루기 쉽습니다. 발급된 키는 코드에 하드코딩하지 말고 환경 변수로 관리하세요.
2단계: Python 환경 및 의존성 설치
# uv를 사용하는 경우 (권장)
uv init public-api-mcp
cd public-api-mcp
uv add mcp httpx python-dotenv
# pip를 사용하는 경우
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install mcp httpx python-dotenv
세 패키지의 역할은 다음과 같습니다. mcp는 MCP 서버 SDK, httpx는 비동기 HTTP 호출, python-dotenv는 .env 파일 로딩용입니다.
프로젝트 루트에 .env 파일을 만들어 API 키를 저장합니다.
# .env
PUBLIC_DATA_API_KEY=여기에_발급받은_UTF8_인증키_입력
.env는 인증키가 들어가므로 반드시.gitignore에 추가해 저장소에 올라가지 않도록 하세요.
3단계: MCP 서버 기본 골격 작성
server.py 파일을 생성합니다.
# server.py
import os
import asyncio
import httpx
from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP
load_dotenv()
API_KEY = os.getenv("PUBLIC_DATA_API_KEY", "")
BASE_URL = "https://apis.data.go.kr"
mcp = FastMCP("공공데이터 MCP 서버")
FastMCP는 Anthropic의 공식 Python MCP SDK에 포함된 고수준 헬퍼 클래스입니다. @mcp.tool() 데코레이터만 붙이면 함수가 자동으로 MCP 도구로 등록되고, 함수의 타입 힌트와 docstring으로 도구 스키마가 생성됩니다.
4단계: 공공 API 호출 도구 구현
예시로 국세청 사업자등록 진위 확인 API를 도구로 노출해 보겠습니다. 실제 엔드포인트와 파라미터는 data.go.kr 해당 서비스 문서를 기준으로 맞춰야 합니다.
# server.py (이어서)
@mcp.tool()
async def check_business_registration(business_number: str) -> dict:
"""
국세청 사업자등록 진위 확인 API를 조회합니다.
business_number: 하이픈 없이 10자리 사업자등록번호 (예: 1234567890)
"""
endpoint = "/nts-businessman/v1/status"
params = {
"serviceKey": API_KEY,
"b_no": business_number,
}
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.get(BASE_URL + endpoint, params=params)
response.raise_for_status()
data = response.json()
return data
if __name__ == "__main__":
mcp.run(transport="stdio")
코드의 핵심 포인트는 세 가지입니다.
async def+httpx.AsyncClient— 네트워크 대기 중 다른 작업을 막지 않도록 비동기로 호출합니다.timeout=10.0— 공공 API가 응답하지 않을 때 무한 대기하지 않고 끊습니다.raise_for_status()— HTTP 오류(4xx/5xx)를 즉시 예외로 올려 디버깅을 쉽게 만듭니다.
JSON이 아니라 XML을 반환하는 API라면 응답 본문을 아래처럼 파싱해 딕셔너리 리스트로 변환합니다.
import xml.etree.ElementTree as ET
# response.text가 XML일 때
root = ET.fromstring(response.text)
items = root.findall(".//item")
result = []
for item in items:
row = {child.tag: child.text for child in item}
result.append(row)
return result
5단계: Claude Desktop에 서버 등록
Claude Desktop의 설정 파일을 열어 서버를 추가합니다.
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"public-api-mcp": {
"command": "python",
"args": ["/절대경로/public-api-mcp/server.py"],
"env": {
"PUBLIC_DATA_API_KEY": "여기에_인증키_입력"
}
}
}
}
경로는 반드시 절대 경로로 적어야 합니다. Claude Desktop은 상대 경로의 기준 디렉터리를 보장하지 않습니다.
uv를 사용했다면 command를 "uv"로, args를 ["run", "python", "server.py"]로 바꾸고 cwd에 프로젝트 경로를 지정합니다. 이렇게 하면 uv가 프로젝트의 가상환경을 자동으로 잡아 줍니다.
{
"mcpServers": {
"public-api-mcp": {
"command": "uv",
"args": ["run", "python", "server.py"],
"cwd": "/절대경로/public-api-mcp",
"env": {
"PUBLIC_DATA_API_KEY": "여기에_인증키_입력"
}
}
}
}
6단계: 동작 확인
Claude Desktop을 완전히 종료했다가 다시 실행합니다. 채팅창 하단에 도구 아이콘(망치 모양)이 나타나면 서버가 정상 연결된 것입니다. 다음처럼 질문해 봅니다.
“사업자등록번호 1234567890이 유효한지 확인해줘.”
Claude가 check_business_registration 도구를 호출해 공공데이터 API 결과를 바탕으로 답변하면 성공입니다.
연결 직후 점검할 체크리스트:
- 망치 아이콘에
public-api-mcp서버와 등록한 도구가 보이는가 - 도구 호출 시 인증키 오류 없이 응답이 오는가
- 잘못된 입력(예: 9자리 번호)에도 서버가 죽지 않고 오류를 반환하는가
흔한 오류와 해결법
| 오류 메시지 | 원인 | 해결 방법 |
|---|---|---|
SERVICE_KEY_IS_NOT_REGISTERED_ERROR | API 키 오류 또는 URL 인코딩 문제 | UTF-8 인증키 사용, 공백·특수문자 주의 |
NORMAL_SERVICE_ERROR | 호출 한도 초과 또는 잘못된 파라미터 | data.go.kr 마이페이지에서 호출량 확인 |
Connection refused (Claude Desktop) | 서버 경로 오류 또는 Python 미설치 | command 경로를 절대 경로로, python --version 확인 |
ModuleNotFoundError: mcp | 가상환경 미활성화 | cwd와 command가 같은 venv를 바라보도록 수정 |
| XML 파싱 오류 | BOM(UTF-8-sig) 또는 인코딩 문제 | response.content에 ET.fromstring() 직접 적용 |
이미 만들어진 한국 공공데이터 MCP 서버
바닥부터 만들기 전에, 오픈소스로 공개된 서버를 먼저 살펴보세요. 구조를 참고하거나 그대로 가져다 쓸 수 있습니다.
- 한국 부동산 MCP: 국토교통부 실거래가 API로 아파트·오피스텔 실거래 조회 및 매수 시나리오 분석. GitHub: tae0y/real-estate-mcp
- 공공데이터포털 MCP 서버 모음: 국민연금·국세청·조달청·금융감독원 등 여러 공공 API를 묶은 서버.
uvx data-go-mcp.nps-business-enrollment@latest로 즉시 실행 가능. GitHub: Koomook/data-go-mcp-servers - 표준국어대사전 MCP 서버: 국립국어원 사전을 로컬 SQLite로 변환해 오프라인 검색. GitHub: dahlia/ko-stdict-mcp
공공데이터 카테고리 전체 서버 목록에서 더 많은 서버를 확인할 수 있습니다.
서버 품질을 높이는 4가지 팁
1. 도구 설명(docstring)을 구체적으로 작성하세요. Claude는 도구를 선택할 때 docstring을 참고합니다. “사업자등록번호를 확인합니다”보다 “10자리 사업자등록번호를 입력받아 국세청 API로 진위와 영업 상태를 확인합니다”가 훨씬 정확하게 선택됩니다.
2. 응답 크기를 제한하세요.
공공 API는 수백 건의 결과를 한 번에 반환하기도 합니다. numOfRows=10 같은 파라미터로 건수를 제한하거나, 도구 함수 안에서 슬라이싱해 Claude의 컨텍스트 낭비를 줄이세요.
3. 결과를 로컬에 캐시하세요. 같은 데이터를 반복 조회하는 경우 SQLite에 캐시를 저장하면 API 호출 한도를 아낄 수 있습니다. 표준국어대사전 MCP 서버가 이 방식을 잘 구현한 사례입니다.
4. 타입 힌트를 반드시 붙이세요. FastMCP는 함수 시그니처의 타입 힌트로 MCP 도구 스키마를 자동 생성합니다. 타입이 없으면 Claude가 파라미터를 잘못 추론할 수 있습니다.
자주 묻는 질문
공공데이터 API 키는 어디서 발급받나요? 공공데이터포털(data.go.kr)에 회원가입 후, 원하는 API 서비스 페이지에서 ‘활용신청’ 버튼을 누르면 됩니다. 심사 없이 즉시 발급되는 API가 대부분이며, 일부는 기관 검토 후 1~3일이 걸립니다.
Python 말고 다른 언어로도 MCP 서버를 만들 수 있나요? 네, Anthropic이 공식 SDK를 TypeScript(Node.js)와 Python 두 가지로 제공합니다. 공공 API 연동은 HTTP 호출만 가능하면 어떤 런타임이든 사용할 수 있습니다.
stdio 방식과 SSE(HTTP) 방식 중 어느 것을 선택해야 하나요? 로컬에서 Claude Desktop과 단독으로 연동할 때는 stdio가 가장 간단합니다. 여러 클라이언트가 동시에 접속하거나 원격 배포가 필요한 경우에는 SSE(Streamable HTTP) 방식을 고려하세요.
공공데이터 응답이 XML 형태인데 어떻게 처리하나요?
Python 표준 라이브러리 xml.etree.ElementTree 또는 xmltodict 패키지로 XML을 파싱한 뒤 딕셔너리로 변환하고, 도구 반환값은 JSON 직렬화 가능한 형태로 가공하면 됩니다. BOM(UTF-8-sig)이 붙은 응답은 response.text 대신 response.content에 ET.fromstring()을 적용하면 파싱 오류를 피할 수 있습니다.
이미 만들어진 한국 공공데이터 MCP 서버는 없나요? 있습니다. 국토교통부 실거래가 데이터를 다루는 한국 부동산 MCP, 여러 공공 API를 묶은 공공데이터포털 MCP 서버 모음 등이 오픈소스로 공개되어 있습니다. 직접 개발 전에 참고하거나 그대로 사용할 수 있습니다.
API 일일 호출 한도를 초과하면 어떻게 되나요? 공공데이터포털 API는 대부분 하루 1,000~10,000건 한도가 있으며, 초과 시 오류 코드를 반환합니다. 프로덕션 용도라면 결과를 로컬 캐시(SQLite 등)에 저장해 불필요한 중복 호출을 줄이는 것을 권장합니다.
다음 단계
이 가이드의 구조를 이해했다면 어떤 공공 API든 같은 방식으로 MCP 서버로 만들 수 있습니다. 핵심은 @mcp.tool() 함수 하나에 ‘API 호출 → 응답 파싱 → 가공된 결과 반환’을 담는 패턴입니다. 공공데이터 카테고리에서 다른 개발자들이 공개한 서버를 탐색해 보고, 직접 만든 서버가 있다면 MCP모아에 등록해 커뮤니티와 공유해 보세요. 더 많은 MCP 서버는 전체 서버 목록에서 확인할 수 있습니다.