Skip to main content
Glama
oowang15

zipnavi MCP Server

by oowang15
README.md
# zipnavi — 우리집 공사·인테리어 내비게이터 (MCP 서버)

집 공사·인테리어를 앞둔 사람이 **주소 하나로** 건물 이력·실거래가·인허가 절차·
시공 체크리스트·업체 검증 방법까지 안내받는 MCP 서버입니다.
공공데이터(건축HUB 건축물대장, 국토부 실거래가)와 주소 검색 API를 결합해
카카오 PlayMCP(AGENTIC PLAYER 10) 환경에서 동작하도록 설계했습니다.

> ⚠️ 본 서버가 제공하는 정보는 공공데이터 기반 참고용이며 법적 효력이 없습니다.
> 계약·인허가 전 건축물대장 원부(세움터)와 관할 행정청을 확인하세요.

## 도구 (5종)

| 도구 | 설명 | 데이터 원천 |
|---|---|---|
| `zipnavi_get_building_info` | 주소 → 건축물대장 요약(구조·연식·내진·주차·승강기) + 공사 관점 인사이트 | 건축HUB getBrTitleInfo |
| `zipnavi_get_recent_deals` | 주소 → 최근 실거래가 (매매/전월세 × 아파트·연립다세대·단독다가구·오피스텔, 1~24개월) | 국토부 RTMS 8종 |
| `zipnavi_get_permit_guide` | 공사 유형 → 신고/허가 여부·법적 근거·절차·주의사항 (9유형) | 내장 지식 |
| `zipnavi_renovation_checklist` | 단계별 체크리스트 (계약 전/시공 전/시공 중/준공 후) | 내장 지식 |
| `zipnavi_check_contractor` | 시공업체 검증 방법·공식 조회처·레드 플래그 | 내장 지식 |

모든 도구는 `response_format: "markdown"(기본) | "json"`을 지원하고,
실패 시에도 오류 대신 **행동을 유도하는 한국어 안내문**을 돌려줍니다.

## 환경 변수

| 변수 | 필수 | 설명 |
|---|---|---|
| `ZIPNAVI_MODE` | 아니오 | `mock` 또는 `live`. 미지정 시 키 2종이 모두 있으면 live, 아니면 mock |
| `DATA_GO_KR_KEY` | live 시 | 공공데이터포털 서비스 키. **일반 인증키(Decoding)** 값을 사용 — Encoding 키를 넣으면 이중 인코딩으로 SERVICE_KEY 오류 발생 |
| `KAKAO_REST_KEY` | live 시 | 카카오 로컬 API REST 키 (주소 → 법정동코드 변환) |
| `JUSO_CONFM_KEY` | 아니오 | juso.go.kr 승인키. 있으면 카카오 실패 시 폴백 |
| `ZIPNAVI_PORT` | 아니오 | 기본 8000 |

키는 환경 변수로만 주입합니다. 하드코딩·저장소 커밋 금지.

## 실행

```bash
pip install -r requirements.txt

# mock 모드 (키 불필요, 픽스처 데이터로 전 도구 동작)
ZIPNAVI_MODE=mock python -m zipnavi.server

# live 모드
DATA_GO_KR_KEY=... KAKAO_REST_KEY=... python -m zipnavi.server
```

기동 후:
- MCP 엔드포인트: `http://localhost:8000/mcp` (streamable-http, stateless)
- 헬스체크: `http://localhost:8000/health`

## 테스트

```bash
pip install -r requirements-dev.txt
python -m pytest tests -q
```

- 전 테스트 네트워크 0회 (mock 픽스처 + `httpx.MockTransport`)
- `test_server_roundtrip.py`가 PlayMCP 등록 검증(initialize → tools/list → tools/call)을
  인메모리로 사전 재현, `test_http_roundtrip.py`가 실제 HTTP로 재확인

## PlayMCP 제약 준수

| 제약 | 대응 |
|---|---|
| 응답 24KB 초과 시 반려 | 마크다운은 멀티바이트 안전하게 절단하고, JSON은 유효한 축약 안내 객체로 반환 |
| TextContent만 허용 | 전 도구 텍스트 반환 + `structured_output=False`로 structuredContent 자동 복제 차단 (roundtrip 테스트에서 타입 검증) |
| 도구명 `^[A-Za-z0-9_-]{1,128}$`, 'kakao' 금지 | `zipnavi_*` 5종 (테스트로 검증) |
| 도구 수 3~10개 | 5개 |
| Remote HTTPS 전용 | streamable-http + 리버스 프록시(TLS 종단)로 배포 |
| 평균 100ms / p99 3s | 실거래가 다개월 조회 총 데드라인 2.6s(`asyncio.wait`) + 동시 요청 5개 제한(Semaphore), httpx 타임아웃 2.0s(connect 1.5s), 재시도 1회 제한 |

## 데이터·약관 준수

- `fixtures/`의 mock 데이터는 **API 응답 스키마만 모사한 가상 데이터**입니다.
  카카오 로컬 API 실응답은 약관상 저장하지 않습니다(라이브 콜 즉시 소비).
- 공공데이터 응답 XML은 DTD 선언을 거부하는 파서로만 해석합니다(XXE 방어).