deal-locator-mcp
# deal-locator — 상업용 부동산 딜 올인원 MCP
**국토부 공공데이터(실거래가 · 건축물대장)를 공인중개사 실무로 바꾸는 MCP 서버.**
구·동 평단가 시세 조회, 가려진 실거래가가 *어느 건물*인지 특정, 손바뀜 이력 추적,
주소 → 구/동/번지·법정코드·필지 확인, 고객용 데이터카드 자동 제작까지 — **대화 한 줄로.**
> 국토부는 상업용 실거래가의 지번을 `소격동 8*`처럼 **마스킹**해 공개합니다. 남들이
> "어느 건물인지 모른다"에서 멈출 때, deal-locator는 건축물대장 표제부로 **역매칭해 그
> 건물을 되짚고**, 그 위에 시세 · 이력 · 콘텐츠를 얹은 올인원 도구입니다.






> **🆕 v1.5 (2026-08)** — **당월 거래가 조회에 들어옵니다.** 이전에는 조회 창을
> *직전 달부터* 세어(`months=12` = 1~12개월 전) **이번 달 체결 거래가 통째로 빠졌습니다**
> — 실측으로 1,200억 거래(2026-08-26 체결)를 5일 뒤 조회했더니 `[NOT_FOUND]`
> "실거래 없음" 이었습니다. 이제 `months` 는 **당월 포함**으로 셉니다. 당월은
> 신고기한(계약일로부터 30일)이 안 지나 표본이 얇으므로, 그 취지의 고지가 응답에
> 함께 나갑니다(0건이어도 '거래가 없었다'는 뜻이 아닙니다).
> ⚠️ 같은 `months` 값의 구간이 한 달 최신 쪽으로 이동합니다.
>
> **v1.5.2 (2026-09)** — **"표제부없음" 오판 수정.** 실재하는 지번이 `[NOT_FOUND]`
> "번지 오타/신축/멸실 가능" 으로 나오던 문제를 고쳤습니다(실측: 서초구 방배동 910-15·
> 우면동 72-8 — 둘 다 실제로는 각각 240억·32억 정확매칭 거래가 있었습니다).
> 원인은 데이터 부재가 아니라 건축물대장 표제부 수신이 **조용히 중간에 끊긴 것**이었고,
> 그 실패가 부재와 똑같은 응답으로 나갔습니다. 세 가지를 바꿨습니다.
> ① 건축HUB 를 **https** 로 부릅니다 — 평문 HTTP 는 일부 네트워크에서 중간 장비에 끊겨
> "200 + 빈 본문" 으로 돌아옵니다(실측 http 7/10·평균 11.7초 vs https 10/10·평균 0.38초).
> ② 단건 지번 조회가 동 전체(방배동 5,432건·55페이지)를 긁지 않고 **본번 지정 조회 1회**로
> 끝납니다 — 0.8초. ③ **조회 실패와 부재를 구분**합니다. 표제부를 못 받으면 `[NOT_FOUND]`
> 가 아니라 외부 API 오류로 나가므로, 이 응답을 근거로 부재를 단정하지 마세요.
>
> **v1.5.1 (2026-09)** — **fastmcp 4 호환 수정.** 플러그인 설치(`uvx --from git+…`)가 fastmcp 4.0 을
> 받으면서 `fastmcp.tools.tool` 경로가 사라져 **서버가 켜지지 않던 문제**를 고쳤습니다(fastmcp `<4` 상한 포함).
> 이미 설치한 경우 Claude Code 재시작 후에도 안 뜨면 `uv cache clean deal-locator-mcp` 를 한 번 실행하세요.
>
> **v1.4** — **카드 신뢰도 게이트**: `deal_card_create` 가 추정매칭
> 이하(신뢰도 0.90 미만)는 `LOW_CONFIDENCE` 로 멈춥니다. 카드 PNG 는 대화를 떠나
> 고객 손에 가는데, 추정매칭은 *동일 스펙 옆 건물일 수 있는* 상태이기 때문입니다.
> 근거(`match_explain`) 확인 후 `allow_estimated=true` 로만 발행되며, 발행된 카드에는
> 신뢰도 배지가 그대로 찍힙니다.
>
> **v1.3** — ① 매칭 엔진 v2: 지분거래 비율매칭·자릿수 프리필터 등으로 마스킹 지번
> 복원율 **84%**(서울 25개 구 전수, 오매칭 0) ② 새 도구
> [`deals_export`](#7-deals_export--실거래-csv-내보내기): 연월 지정 서울 전역 실거래를
> **지번 복원된 CSV**로 다운로드(2006~, 장기간은 연도별 파일) ③ 건축HUB API 응답
> 형식 변경 대응.
---
## 목차
**처음이라면** → [1분 요약](#1분-요약--이게-뭔가요) · [다루는 범위](#다루는-범위-v1) · [설치](#설치) · [도구 7종](#도구-7종)
**쓰다가 막히면** → [매칭 신뢰도](#매칭-신뢰도는-반드시-함께-읽으세요) · [FAQ](#faq) · [한계 · 주의](#한계--주의)
<details>
<summary>전체 목차 펼치기</summary>
- [1분 요약 — 이게 뭔가요?](#1분-요약--이게-뭔가요)
- [다루는 범위 (v1)](#다루는-범위-v1)
- [무엇이 들어있나요](#무엇이-들어있나요)
- [설치](#설치)
- [도구 7종](#도구-7종)
- [1. `resolve_address` — 주소·필지 확인](#1-resolve_address--주소필지-확인)
- [2. `deal_card_search` — 매물 종합 확인](#2-deal_card_search--매물-종합-확인)
- [3. `deal_history` — 실거래가 손바뀜 이력 확인](#3-deal_history--실거래가-손바뀜-이력-확인)
- [4. `area_scan` — 구/동 실거래가 최신 시세 확인](#4-area_scan--구동-실거래가-최신-시세-확인)
- [5. `match_explain` — 매칭 근거](#5-match_explain--매칭-근거)
- [매칭 신뢰도는 반드시 함께 읽으세요](#매칭-신뢰도는-반드시-함께-읽으세요)
- [6. `deal_card_create` — 데이터카드](#6-deal_card_create--데이터카드)
- [7. `deals_export` — 실거래 CSV 내보내기](#7-deals_export--실거래-csv-내보내기)
- [FAQ](#faq)
- [저장소 구조](#저장소-구조)
- [한계 · 주의](#한계--주의)
- [고지](#고지)
- [Star History](#star-history)
- [라이선스](#라이선스)
</details>
---
## 1분 요약 — 이게 뭔가요?
국토교통부 상업업무용 실거래가는 일반건물의 지번을 `소격동 8*` 처럼 가려서 공개합니다.
그래서 "이 건물이 얼마에 팔렸나"를 확인하려면 대장을 일일이 대조해야 했습니다.
이 서버는 **건축물대장 표제부(건축년도 · 연면적 · 대지면적)** 와 **부속지번 대장**으로
역매칭해 그 필지를 특정합니다.
```
소격동 8* · 216억 3,842만원 · 대지 361㎡ / 연면적 356.18㎡ / 1981년
↓ 표제부 3개 값이 정확히 일치하는 필지는 하나뿐
소격동 86 (북촌로5길 76) — 정확매칭 0.97
```
모든 수치는 공공데이터포털(data.go.kr) 공식 API 실측값입니다. 결과가 없으면
`[NOT_FOUND]` 를 반환합니다 — **AI가 수치를 지어내지 못하도록** 설계했습니다.
---
## 다루는 범위 (v1)
> **📌 꼭 확인하세요.**
현재는 **통건물(한 필지 위 건물 한 채) 상업용건물 매매**를 다룹니다.
여기서 나오는 시세·평단가는 전부 이 통건물 기준이며,
앞으로 **토지 · 공장 · 도로** 등 다른 물건 종류로 취급 범위를 넓혀 나갈 예정입니다.
| 구분 | 물건 종류 |
|---|---|
| ✅ 지금 취급 | **통건물(유형 '일반') 상업용건물** 매매 |
| ⏳ 확장 예정 | 토지 · 공장 · 도로 등 |
> ※ 집합(구분상가) 거래는 현재 제외됩니다.
---
## 무엇이 들어있나요
| 구성 | 내용 |
|---|---|
| 조회 도구 5종 | 지번 · 이력 · 지역 스캔 · 매칭 근거 — 전부 읽기 전용 |
| 카드 도구 1종 | 조회 결과를 데이터카드 PNG 1장으로 (고객 제시 · SNS용) |
| 매칭 엔진 | 표제부 역매칭 + 부속지번 재앵커, 6단계 신뢰도 파이프라인(지분거래 비율매칭 포함) · 표제부 완전수신 보장 |
| 캐시 | 15분 · 128건 — 같은 지번 재조회는 API를 다시 때리지 않습니다 |
---
## 설치
> **한눈에** — ① 인증키 발급 → ② uv 설치 → ③ 플러그인(권장) 또는 Desktop 등록. 여기까지가 필수입니다.
> ④ 카드 기능 · ⑤ 프리워밍은 선택이니, 급하면 ③까지만 하고 바로 조회하세요.
### 1. 인증키 발급 (필수)
[공공데이터포털](https://www.data.go.kr) 에서 아래 2개를 활용신청하고 **디코딩 인증키**를 받습니다.
- 국토교통부_상업업무용 부동산 매매 신고 자료
- 건축HUB_건축물대장정보 서비스
승인까지 보통 몇 분~1시간 걸립니다.
### 2. uv 설치 (필수)
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### 3-A. 플러그인으로 설치 (권장 — `/명령어`까지 함께 들어옵니다)
플러그인으로 깔면 MCP 도구 7개와 **슬래시 명령 7개**가 한 번에 붙습니다.
먼저 인증키를 홈 폴더에 파일 하나로 둡니다. 터미널에서:
```bash
echo 'DEAL_LOCATOR_SERVICE_KEY=발급받은_디코딩_인증키' > ~/.deal-locator.env
chmod 600 ~/.deal-locator.env
```
그다음 Claude 에서:
```
/plugin marketplace add syleedlabs/deal-locator-mcp
/plugin install deal-locator@dlabs
```
재시작하면 아래 명령을 바로 쓸 수 있습니다.
| 명령 | 하는 일 |
| --- | --- |
| `/area-scan` | 구·동 통건물 시세와 분기 추이 |
| `/deal-card` | 지번 실거래 한 건 조회 |
| `/deal-history` | 그 지번의 손바뀜 이력 |
| `/match-explain` | 왜 이 건물로 판단했는지 근거 |
| `/resolve-address` | 주소·필지 구성 확인 |
| `/deal-card-image` | 데이터카드 PNG 만들기 |
| `/deals-export` | 연월 지정 서울 전역 실거래 CSV 다운로드 |
> 인증키 파일은 `~/.deal-locator.env` → `~/.config/deal-locator/.env` 순으로 찾습니다.
> 프로젝트 폴더에 `.env` 가 있으면 그쪽이 우선입니다.
### 3-B. Claude Desktop 에 직접 등록 (도구만)
설정 → 개발자 → 설정 편집 → `claude_desktop_config.json`
```json
{
"mcpServers": {
"deal-locator": {
"command": "uvx",
"args": ["--from", "git+https://github.com/syleedlabs/deal-locator-mcp", "deal-locator-mcp"],
"env": {
"DEAL_LOCATOR_SERVICE_KEY": "발급받은_디코딩_인증키"
}
}
}
}
```
Claude Desktop 을 재시작하면 도구 7개가 잡힙니다.
> ⚠️ **이 설정 파일에는 인증키가 평문으로 들어갑니다.** 화면 공유·스크린샷·
> 원격지원 때 노출되지 않게 주의하세요. 키가 유출된 것 같으면 공공데이터포털에서
> 즉시 재발급하면 됩니다. 파일에 키를 두기 싫으면 아래 FAQ 의 `.env` 방식을 쓰세요.
### 4. 카드 기능을 쓰려면 (선택)
카드는 브라우저 엔진으로 이미지를 그립니다. 최초 1회만:
```bash
uvx --from git+https://github.com/syleedlabs/deal-locator-mcp playwright install chromium
```
건너뛰어도 조회 도구 5개는 정상 동작합니다.
### 5. 첫 조회를 빠르게 (선택 — 프리워밍)
구·동을 **처음** 조회하면 국토부 API 를 12개월치 받아오느라 20~35초 걸립니다
(한 번 받은 구는 이후 즉시 응답합니다). 미리 채워두려면:
```bash
# 서울 25구 · 12개월치 캐시 채우기 (API 300회, 몇 분 소요 — 한 번만)
uvx --from git+https://github.com/syleedlabs/deal-locator-mcp deal-locator-warm
# 자주 보는 구만: deal-locator-warm --gus 강남구 성동구 마포구
```
인증키는 조회와 같은 `~/.deal-locator.env` 를 씁니다. 중간에 끊겨도 다시 실행하면
남은 것만 이어서 받습니다. 실거래는 매달 갱신되니, 원하면 월 1회쯤 다시 돌리세요.
---
## 도구 7종
| 도구 | 하는 일 | 이렇게 물어보세요 |
|---|---|---|
| `resolve_address` | 주소 → 구/동/번지 + 법정코드, 필지 구성 확인 | "소격동 86 주소 확인해줘" |
| `deal_card_search` | 지번 하나의 최신 실거래 종합 | "소격동 86 실거래가 알려줘" |
| `deal_history` | 그 지번의 매칭 실거래 이력 전체 | "이 건물 거래 이력 다 보여줘" |
| `area_scan` | 동 단위 평당가 구간 스캔 (지번 몰라도 조회) | "성수동1가 평당 4.5~5.5억 거래" |
| `match_explain` | 매칭 근거 공개 — 표제부값 vs 거래행값 대조 | "이 매칭 왜 이렇게 나왔어?" |
| `deal_card_create` | 데이터카드 PNG 1장 생성 | "이 건으로 카드 만들어줘" |
| `deals_export` | 연월 지정 서울 전역 실거래 CSV 다운로드 | "2026년 7월 실거래 CSV로 뽑아줘" |
앞의 5개는 **읽기 전용**입니다. 파일을 만드는 도구는 `deal_card_create`(카드 PNG)와
`deals_export`(CSV) 둘뿐이고, 외부에 무언가를 보내지 않습니다.
각 도구를 **사용방법 → 결과물 → 설명** 순으로 정리한 실행 예시입니다.
값은 전부 공식 API 실측값이며, 표시는 가독성을 위해 정리한 것입니다.
---
## 1. `resolve_address` — 주소·필지 확인
**사용방법**
```
/resolve-address 종로구 소격동 86
```
**결과물**
```
종로구 소격동 86 · 법정코드 11110-14200
필지 구성: 단일 (부속지번 없음)
```
**설명**
- 다른 조회가 막히기 전에 주소가 제대로 잡히는지 · 합필/부속지번이 있는지 먼저 확인합니다.
- `조회실패` 는 '단일 필지'가 아니라 **미확인**이니 구분해서 읽으세요.
---
## 2. `deal_card_search` — 매물 종합 확인
**사용방법**
```
/deal-card 종로구 소격동 86
```
**결과물**
```
216억 3,842만원 · 2026-05-14 · 정확매칭 0.97
대지 361㎡ (109.2평) · 연면적 356.18㎡ (107.7평) · 1981년 준공
대지 평단가 1억 9,815만원/평 · 제1종일반주거 · 매도 법인 → 매수 법인
북촌로5길 76 (소격동)
```
**설명**
- 지번 하나의 최신 실거래를 종합카드 1콜로. 신뢰도(정확매칭 0.97)를 함께 읽으세요.
---
## 3. `deal_history` — 실거래가 손바뀜 이력 확인
**사용방법**
```
/deal-history 성수동1가 685-442
```
**결과물**
```
[성동구 성수동1가 685-442] 매칭 실거래 이력 · 최근 24개월
■ 2026-06-18 57억 5,000만원 정확매칭 0.97 법인 → 법인
■ 2025-11-27 55억 3,000만원 정확매칭 0.97 법인 → 법인
→ 약 7개월 만에 재거래, +2억 2,000만원 (+4.0%)
대지 136㎡(41.1평) · 연면적 209.34㎡(63.3평) · 1990년 · 제2종일반주거
※ 해제신고 6건 제외
```
**설명**
- 한 지번의 손바뀜을 최신순으로 — 재거래·가격 추이를 한눈에. 건별 신뢰도가 다를 수 있습니다.
---
## 4. `area_scan` — 구/동 실거래가 최신 시세 확인
**사용방법**
```
/area-scan 성수동1가 # 동: 시세 통계 + 개별 거래
/area-scan 성동구 # 구: 구 전체 통계 + 동별 평단가 순위
```
**결과물** — 동을 조회한 최근 한 분기(3개월) 예시입니다.
```
[성동구 성수동1가] 최근 3개월(2026 Q2) · 통건물 12건
대지 평단가 평균 1억 6,028만원 · 중앙값 1억 6,136만원 (p25 1.45억 ~ p75 2.09억)
연면적 평단가 평균 7,770만원 · 중앙값 8,530만원
표본 동 전체 14건 → 집합(구분상가) 2건 제외 · 해제 2건 제외 → 통건물 12건 집계
```
**설명**
- 동을 주면 시세 통계와 개별 거래를, 구를 주면 구 전체 통계와 동별 평단가 순위를 냅니다.
- 동 평균 시세는 국토부 원본 전수에 가까운 `stats` 로 답합니다.
- `coverage`(모수 분해)를 함께 봐야 표본이 대표성을 갖는지 판단할 수 있습니다.
---
## 5. `match_explain` — 매칭 근거
**사용방법**
```
/match-explain 영등포동8가 34-20
```
**결과물**
```
[영등포동8가 34-20] 매칭 근거 · 정확매칭 0.90 (stage2)
거래 4억 4,000만원 · 2026-05-06 (지번 마스킹 '영등포동8가 3*')
표제부(앵커) vs 거래행
연면적 31.21㎡ = 31.21㎡ ✓ 일치
건축년도 1985 = 1985 ✓ 일치
대지면적 21.78㎡ vs 22.8㎡ Δ 1.02㎡ (신고 반올림 오차 수준)
→ 3속성 중 2개 정확 일치 + 대지면적만 근소차 → 'stage2 강등'이나 라벨은 '정확매칭'
```
**설명**
- 국토부 실거래가는 지번을 `영등포동8가 3*`처럼 **마스킹**해 공개합니다. 이 도구들은 건축물대장
표제부(건축년도·연면적·대지면적)로 **역매칭**해 '이 건물'이라고 특정하는데, **매칭 신뢰도**는
그 특정이 얼마나 확실한지를 뜻합니다.
- `추정매칭`이면 **같은 스펙의 옆 건물**일 수 있고, 그 값을 고객·보고서에 "이 건물 실거래가"로
인용하면 **엉뚱한 건물 가격을 대는 오류**가 됩니다.
- `match_explain`은 어떤 표제부 값으로 어떻게 특정했는지(앵커 vs 거래행)를 대조해, 인용 전에
그 위험을 직접 판단하게 합니다.
### 매칭 신뢰도는 반드시 함께 읽으세요
| 표기 | 뜻 |
|---|---|
| 확정 / 정확매칭 | 표제부 값이 정확히 일치 — 사실상 그 필지 |
| 추정매칭 | 유사 스펙으로 좁힌 것 — **동일 스펙 인접 건물일 수 있습니다** |
| 인접후보 | 후보 수준 — 확인 없이 인용하지 마세요 |
`추정매칭` 이하를 고객에게 제시하기 전에 `match_explain` 으로 근거를 확인하세요.
---
## 6. `deal_card_create` — 데이터카드
건물 사진 위에 실측 수치를 얹은 4:5 카드(2160×2700)를 만듭니다. 홍보 문구는
들어가지 않습니다 — 카드의 모든 글자가 실측값이거나 고정 라벨입니다.
**사용방법**
```
/deal-card-image 영등포구 영등포동8가 34-20 [건물사진]
```
> 직접 호출: `deal_card_create(address="영등포구 영등포동8가 34-20", photo="~/사진.jpg")`
**결과물** — 건물 사진(입력)에 실측 수치를 얹어 카드(출력)를 만듭니다.
<table>
<tr>
<td align="center"><b>건물 사진 (입력)</b></td>
<td align="center"><b>데이터카드 (결과물)</b></td>
</tr>
<tr>
<td><img src="assets/deal-card-create-input.png" width="280" alt="영등포동8가 34-20 건물 사진(입력)"></td>
<td><img src="assets/deal-card-create-example.png" width="280" alt="영등포동8가 34-20 데이터카드(결과물)"></td>
</tr>
</table>
> 영등포구 영등포동8가 34-20 · 거래일 2026-05-06 · 매매 4.4억 · 토지 7평(평단가 6,377만원/평) · 연면적 9평 · 준공업 · 1985년 준공 · 정확매칭 0.90.
**설명**
**멈추는 지점이 2곳 있습니다** — 둘 다 실패가 아니라 **사람이 결정할 상태**라
재시도로 뚫리지 않습니다.
- **`LOW_CONFIDENCE` — 추정매칭 이하(신뢰도 0.90 미만)는 기본적으로 만들지 않습니다.**
카드는 대화를 떠나 고객 손에 가는데, `추정매칭`은 정의상 *동일 스펙 옆 건물일 수
있는* 상태입니다 — 옆 건물 실거래가가 이 건물 값으로 박힌 이미지가 돌아다닐 수
있습니다. `match_explain` 으로 근거를 확인한 뒤, 그래도 발행하기로 했다면
**`allow_estimated=true`** 로 다시 부르세요.
- **`PHOTO_MISSING` — 건물 사진이 없으면 만들지 않습니다.** 사진 없이 만들면 회색 판이
나가고 결국 다시 만들게 되기 때문입니다. 사진 경로를 주고 다시 부르거나, 그대로
진행하려면 `allow_no_photo=true` 를 주세요.
**그 밖에**
- **매칭 신뢰도가 카드에 배지로 표기됩니다.** 위 게이트를 통과해 발행되는 카드에도
근거가 항상 따라다녀야 한다고 봤습니다(`추정매칭` 이하는 색으로 구분). 즉 신뢰도는
**차단(게이트) + 각인(배지)** 두 겹으로 다룹니다.
- 저장 위치는 `~/deal-locator-cards/<날짜>/` 입니다 (`DEAL_LOCATOR_CARD_DIR` 로 변경 가능).
---
## 7. `deals_export` — 실거래 CSV 내보내기
연월(YYYYMM)을 지정해 **서울 전역(또는 한 구)의 상업업무용 통건물 실거래를, 마스킹
지번을 역매칭으로 복원한 CSV**로 내려받습니다. DB·분석 파이프라인에 넣을 **원천
데이터**를 만드는 도구입니다 — 화면 시세 조회는 `area_scan` 이 담당합니다.
**사용방법**
```
/deals-export 202607 → 서울 25개 구 전체, 2026년 7월, 지번 복원(기본)
/deals-export 202601-202606 강남구 → 강남구 상반기(범위는 최대 24개월)
/deals-export 202607 원본 → 역매칭 없이 국토부 원본 그대로(수십 초)
```
> 직접 호출: `deals_export(year_month="202607")`,
> 범위·구 한정은 `deals_export(year_month="202601", year_month_to="202606", gu="강남구")`
**결과물** — 고정 폴더 `~/deal-locator-exports/` 에 **복원본 + 미복원본 2파일**
(utf-8-sig — 엑셀에서 바로 열립니다. `DEAL_LOCATOR_EXPORT_DIR` 로 폴더 변경 가능.
날짜 하위폴더가 없어 파이프라인이 경로를 하드코딩해도 되고, 같은 연월 재실행은 같은
파일을 덮어씁니다 — 멱등)
```
■ 실거래 CSV 내보내기 — 서울전역 202607 (통건물)
복원본: ~/deal-locator-exports/실거래_통건물_서울전역_202607_복원.csv — 171건 (정확매칭 139건 · 추정매칭 32건)
미복원본: ~/deal-locator-exports/실거래_통건물_서울전역_202607_미복원.csv — 31건 (금액·면적은 실측, 지번만 미확정)
전체 202건 · 해제신고 8건 포함(해제사유발생일 컬럼으로 구분)
※ 집합(구분상가) 588건은 취급 범위 밖이라 제외(v1)
구별 상위: 중구 27건 · 종로구 22건 · 강남구 11건 · …
```
### 긴 기간(예: 10년치)을 요청하면 어떻게 처리되나요
`/deals-export 2016년부터 강남구`, `최근 10년`, `2006년부터 전체` 처럼 **24개월을 넘는
기간**을 요청하면, 한 번에 통짜로 받는 게 아니라 **연 단위로 나눠 여러 번 호출하고
연도별 파일로 저장**합니다. 예를 들어 "2016~2025 강남구"는 아래처럼 진행됩니다.
```
2016년 → 실거래_통건물_강남구_2016_복원.csv (+ _미복원)
2017년 → …_2017_복원.csv
⋮ (한 해 끝날 때마다 그 해 복원율을 한 줄씩 보고)
2025년 → …_2025_복원.csv
─────────────────────────────────
마무리: 연도별 복원율 표 + 생성된 파일 목록
```
**왜 통짜가 아니라 연 단위로 쪼개나요 (기술적 이유)**
- **도구 한 번 호출은 최대 24개월**입니다. 한 호출이 유한 시간 안에 끝나야 MCP
클라이언트(예: Claude Desktop)가 응답을 기다리다 **타임아웃으로 끊는 사고**를 막을 수
있고, 도중 실패해도 그 구간만 다시 받으면 되기 때문입니다(통짜 호출은 몇 시간째
실패하면 전부 날아갑니다).
- 그래서 **연 단위(1~12월) 청크**로 끊습니다 — 청크 경계가 **연도별 파일과 1:1로
맞아떨어져** DB 파티션·증분 적재에 그대로 쓰기 좋습니다.
- **첫 해만 오래 걸리고 이후는 빠릅니다.** 역매칭이 쓰는 **건축물대장은 연도와 무관한
'현재' 대장**이라, 첫 해를 처리하며 서울 전 동의 표제부를 받아 캐시에 굳히면 그다음
해들은 **거래 조회만** 하면 됩니다. 즉 무거운 건 최초 표제부 수신 1회뿐입니다.
- **이미 받은 해는 다시 긁지 않습니다(멱등 재개).** 완결된 과거 연도는 파일이 있으면
건너뛰고, **현재 진행 중인 해만 매번 다시 받아** 새로 공개된 월을 반영합니다
(현재 해도 `_YYYY_` 파일명으로 고정돼 매달 같은 파일을 덮어씁니다 — 겹치는 파일이
쌓여 파이프라인이 중복 적재하는 일을 막습니다).
**그래서 알아둘 것**
- **첫 전체 백필은 오래 걸립니다.** 서울 전역 장기이면 표제부 최초 수신 때문에 수십 분
이상 걸릴 수 있어, 시작 전에 안내합니다. 급하면 특정 구부터 받거나 `원본`(match=false,
역매칭 생략)으로 빠르게 받을 수 있습니다.
- **과거로 갈수록 지번 복원율이 떨어집니다** — 위에서 설명한 표제부 '현재 스냅샷' 한계
때문입니다(최근 ~84% → 10년 전 ~79% → 20년 전 ~16%). 연도별 복원율 표를 함께
드리니, 어느 연도부터 지번 레이어가 촘촘해지는지 보고 판단하세요. **점(지번) 레이어는
최근·`정확매칭` 위주로, 과거·미복원·추정은 동 단위 집계 레이어로** 쓰는 걸 권합니다.
**파일 구성**
- **복원본(`…_복원.csv`)** — 지번이 특정된 거래. 국토부 원본 컬럼(마스킹 지번 포함)은
그대로 두고 **`복원지번` · `대지위치_표제부` · `도로명대지위치_표제부` · `매칭단계` ·
`매칭신뢰도`(정확매칭/추정매칭)** 컬럼을 추가합니다. 추정매칭은 동일 스펙 인접
건물일 가능성이 있으니 하류에서 `매칭신뢰도` 로 필터하세요.
- **미복원본(`…_미복원.csv`)** — 지번 특정에 실패한 거래(`역매칭실패사유` 포함).
**금액·면적은 실측값**이므로 버리지 말고 용도에 맞게 쓰세요. 0건이면 파일을 만들지
않습니다.
**알아둘 것**
- **통건물(유형='일반')만 담깁니다.** 집합(구분상가)은 취급 범위 밖(v1)이라 빠지고
제외 건수만 보고합니다.
- **해제신고 거래는 행으로 남습니다.** 데이터 다운로드가 행을 지우면 원본과 어긋나기
때문입니다 — 시세 분석 전에 `해제사유발생일` 컬럼이 채워진 행을 제외하세요.
- **역매칭은 동별 건축물대장 전체를 받습니다** — 콜드 캐시면 수 분~수십 분, 한 번
받은 뒤에는 수 분 안에 끝납니다. 빠르게 원본만 필요하면 `match=false`(`원본`).
- **조회 창(`months`)은 당월부터 셉니다** (v1.5.0~). `months=12` 면 '이번 달 포함
최근 12개월'입니다. v1.4.0 까지는 직전 달부터 세어 **당월 거래가 통째로 안 보였습니다**
— 실측으로 1,200억 거래가 체결 5일 뒤에도 `[NOT_FOUND]` 였습니다.
- 당월은 신고기한(계약일로부터 30일)이 안 지나 **표본이 얇습니다** — 지금 0건이어도
'거래가 없었다'는 뜻이 아닙니다. 조회 결과에 그 취지의 고지가 함께 나갑니다.
- 최근 월은 신고 지연(신고기한 30일)으로 데이터가 아직 없을 수 있습니다 — 이때는
`[NOT_FOUND]` 로 답하며 수치를 지어내지 않습니다.
- **확보 가능 기간은 2006년 1월 ~ 현재(약 20년)입니다.** 그 이전은 원천 데이터가
없습니다(아래 FAQ). "2006년부터", "최근 10년", "전체" 같은 장기 요청은 스킬이
**연 단위 파일**로 나눠 확보합니다.
- **장기 데이터는 과거로 갈수록 지번 복원율이 떨어집니다** — 표제부가 '현재 스냅샷'이라
그 사이 재건축된 과거 건물은 못 맞춥니다(실측: 최근 ~84%, 10년 전 ~79%, 20년 전 ~16%).
히스토리 맵을 만든다면 **점(지번) 레이어에는 `매칭신뢰도=정확매칭`만 쓰고, 미복원·
추정매칭은 동(洞) 단위 집계 레이어로** 쓰는 걸 권합니다(금액·면적·법정동은 전 기간 실측).
## FAQ
**Q. 아파트도 되나요?**
> 아니요. **서울 · 상업업무용 · 매매**만 다룹니다(v1). 아파트 · 오피스텔 · 단독다가구 · 토지 · 전월세는 범위 밖입니다.
**Q. 첫 조회가 너무 느립니다.**
> 건축물대장 전체를 불러오기 때문에 수십 초~수 분 걸립니다. 이후 15분간 캐시되어 같은 구 조회는 즉시 나옵니다.
**Q. 실거래가는 몇 년치까지 받을 수 있나요?**
> **2006년 1월 ~ 현재, 약 20년치**입니다. **실거래가 신고 의무화가 2006년 1월 1일 시행**돼, 그 이전 거래는 신고 자체가 없어 국토부에 원천 데이터가 존재하지 않습니다(도구 하한도 2006 — `200512`는 `PARSE_ERROR`로 거부). 이 도구가 다루는 상업·업무용 통건물 매매도 2006년부터 제공됩니다.
>
> 다만 이건 *원천 데이터*가 20년치라는 뜻이고, **마스킹 지번 복원(역매칭)은 최근일수록 강하고 과거로 갈수록 급락**합니다(최근 ~84% → 10년 전 ~79% → 20년 전 ~16%). 표제부(건축물대장)가 '현재 스냅샷'이라, 그 사이 재건축·신축된 과거 건물은 현재 대장과 스펙이 안 맞기 때문입니다. 그래서 장기 히스토리 맵을 만든다면 **지번 단위 레이어는 최근 구간에서 촘촘**하고, 과거 구간은 **동 단위 집계(거래밀도·평단가 추이)** 로 쓰는 게 맞습니다 — 미복원 건도 금액·면적·법정동은 전 기간 실측이라 동 레이어엔 온전히 활용됩니다.
>
> 2006년 이전 시계열까지 필요하면 실거래가가 아닌 다른 소스(감정원 시세지수, 공시지가 이력 등)를 별도 레이어로 붙이는 방법을 검토하세요.
**Q. 계약 취소된 거래도 포함되나요?**
> 아니요. **해제신고 건은 집계에서 제외**하고 그 건수를 알려줍니다.
**Q. 지번이 특정되지 않는 거래가 있습니다.**
> 표제부와 일치하는 필지를 못 찾은 경우입니다. `area_scan` 결과에 `마스킹 미복원` 으로 표기되며, 그 건의 **금액·면적은 실측값**이지만 주소는 확정된 것이 아닙니다.
**Q. 인증키를 설정 파일에 넣기 싫습니다.**
> 실행 폴더(또는 그 상위 1단계)에 `.env` 를 두면 자동으로 읽습니다(`.env.example` 참고). `.env` 는 절대 커밋하지 마세요.
>
> 보안상 **`DEAL_LOCATOR_*` 와 `DATA_GO_KR_API_KEY` 만 읽습니다.** `.env` 의 다른 줄은 무시합니다 — 남의 프로젝트 폴더에서 서버를 띄웠을 때 그쪽 설정(프록시 등)이 섞여 들어와 요청이 엉뚱한 서버를 경유하는 일을 막기 위함입니다.
>
> 저장·캐시 폴더 설정(`DEAL_LOCATOR_CARD_DIR` · `DEAL_LOCATOR_EXPORT_DIR` · `DEAL_LOCATOR_CACHE_DIR`)은 **실행 폴더의 `.env` 에서는 읽지 않습니다.** 환경변수, `DEAL_LOCATOR_ENV_FILE` 로 지정한 파일, 홈 설정 파일(`~/.deal-locator.env` · `~/.config/deal-locator/.env`)에서만 받습니다 — 남이 만든 폴더의 `.env` 가 캐시 폴더를 바꿔, 조작된 데이터를 실측값처럼 읽게 만드는 일을 막기 위함입니다.
**Q. 카드 만들 때 임의 파일이 읽히지 않나요?**
> `photo` 는 **파일 내용으로 이미지 여부를 판별**합니다(PNG·JPEG·GIF·WebP). 이미지가 아니면 렌더하지 않고 멈춥니다. 카드 렌더는 JavaScript 를 끈 상태로 돌고 모든 네트워크 요청이 차단되므로, 카드 값에 스크립트가 섞여도 실행되지 않고 외부로 나가지도 않습니다.
---
## 저장소 구조
```
deal-locator-mcp/
├─ src/deal_locator/
│ ├─ server.py MCP 서버 — 도구 7종 정의 · 구조화 출력
│ ├─ core/ 매칭 엔진 (표제부 역매칭 · 부속지번 · 파이프라인)
│ └─ render/ 데이터카드 렌더 (템플릿 + Pretendard 폰트)
├─ tests/ 114개
├─ server.json MCP 레지스트리 메타데이터
└─ .env.example
```
---
## 한계 · 주의
이 도구가 **무엇을 못 하는지**를 먼저 밝힙니다. 수치를 인용하기 전에 반드시 함께 읽으세요.
**취급 범위**
- **서울 · 상업업무용 · 매매뿐입니다 (v1).** 아파트 · 오피스텔 · 단독다가구 · 토지 · 전월세,
그리고 서울 외 지역은 조회되지 않습니다.
- **통건물(일반)만 다룹니다 — 집합(구분상가) 거래는 모든 응답에서 제외됩니다.** 여기서 나오는
시세 · 평단가는 전부 통건물 기준이며, **구분상가 한 칸 시세로 인용하면 안 됩니다.** 제외된
집합 거래 건수는 응답의 `jiphap_excluded` 로 함께 알려줍니다.
**매칭의 한계**
- **매칭은 확률이지 등기부가 아닙니다.** `추정매칭` 은 동일 스펙 인접 건물일 수 있고,
`인접후보` 는 확인 없이 인용하면 안 됩니다. `추정매칭` 이하는 `match_explain` 으로 근거를
확인한 뒤 쓰세요.
- **특정되지 않는 거래가 있습니다.** 표제부와 일치하는 필지를 못 찾으면 `마스킹 미복원` 으로
표기됩니다 — 그 건의 **금액 · 면적은 실측값이지만 주소는 확정된 것이 아닙니다.**
- **왜 100% 매칭은 불가능한가 (면적 오차의 원인).** 매칭은 표제부의 **연면적 · 대지면적 ·
건축년도(사용승인일)** 를 실거래 신고행과 대조하는데, 이 값들은 서로 다른 공부(건축물대장 vs
토지대장)에서 나오기 때문에 완전히 일치하지 않을 수 있습니다.
- **대지면적이 공부마다 다릅니다.** 코너 필지의 **가각전제**, **도로 확폭 · 건축선 후퇴**가
있으면 실제 건축에 쓸 수 있는 땅이 줄어 **토지대장 대지면적**과 **건축물대장 대지면적**이
어긋납니다. 또 필지가 여러 지번으로 **합필**된 경우 주지번 하나만으로는 면적이 맞지 않아 —
이 도구는 **부속지번(보조지번) 대장을 합산해 대표지번으로 재앵커**하고, 다필지로 확인되면
대지면적 허용 오차를 완화해 보정합니다.
- **연면적도 공부상 차이가 있습니다.** **옥탑** 등 일부 공간이 대장에 반영되지 않는 경우가
있어 신고 연면적과 표제부 연면적이 딱 떨어지지 않을 수 있습니다.
그래서 이 도구는 **면적 오차를 단계적으로 허용하는 매칭 파이프라인**을 씁니다:
0. **마스킹 자릿수 프리필터** — 마스킹 `2**`는 "본번이 정확히 3자리이고 2로 시작"을
뜻합니다(실측 규칙). 자릿수까지 검사해 후보 풀을 좁혀 오매칭 여지를 줄입니다.
1. **정확매칭** — 연면적 · 대지면적 · 건축년도 3속성 완전일치(사실상 확정)
2. **건축년도 + 연면적** 일치
3. **오차범위 ±10%**(연면적 · 대지) — 합필 필지는 대지 검사 완화
4. **지분거래 비율매칭** — 지분 매매는 신고 면적이 건물 전체가 아니라 **지분 몫**이라
절대값 비교가 원리상 불가능합니다. 대신 **연면적 지분율 ≈ 대지면적 지분율**(등기
지분율은 두 면적에 동일하게 적용됨)이 0.2% 이내로 일치하는 후보가 **유일**할 때만
복원합니다. 지분거래가 작은 건물의 전체 스펙과 우연히 겹쳐 생기던 오매칭도 함께
차단됩니다.
5. **추정매칭(전부 유일후보 한정)** — 건축년도 결측 시 연면적(+대지) 정확일치,
건축년도 ±1년(연말 준공 · 이월 등기 노이즈) + 연면적 정확일치, 대지 공부 오차 시
연면적±10% + 건축년도 일치 등 — 어느 경우든 **후보가 유일**할 때만 복원.
**후보가 둘 이상이면 확정하지 않습니다(옆 건물 오매칭 방지).**
위에서 아래로 갈수록 신뢰도를 낮춰 `정확매칭` · `추정매칭` · `인접후보`로 표기합니다.
**매칭 정확도는 표제부 데이터 완전성에 좌우됩니다** — 건축HUB API의 일시 오류로 표제부가
부분 수신되면 그 동의 복원율이 떨어집니다. 이 도구는 **5xx 재시도 + 부분수신본 캐시 방지 +
JSON/XML 겸용 파싱**(건축HUB가 2026-08부터 기본 응답을 JSON으로 변경)으로 항상 완전한
표제부로만 매칭합니다. 대형 동도 절단 없이 수신합니다(신림동 17,795건 실측 대응).
(측정: **서울 25개 구 전수** — 거래 발생 352개 동, 12개월, 통건물 마스킹 매매 2,547건 —
복원율 **84.3%**(해제 제외 시 84.7%), 확정급 1 · 2단계 68.1%, 합성 자가검증 오매칭 0 —
기준 2026-08 · 표본 기간에 따라 달라짐)
**데이터 · 통계**
- **해제신고(계약 취소) 건은 집계에서 제외**하고 그 건수를 알려줍니다. 취소된 값을 실거래로
오인하지 않도록 한 조치입니다.
- **`area_scan` 통계는 표본이 얇을 수 있습니다.** 통건물 매매는 동에 따라 월 1~7건이라, 반드시
`coverage`(모수 분해: 전체 · 집합 제외 · 해제 제외 · 마스킹 미복원)를 함께 보고 대표성을
판단하세요.
- **첫 조회는 느리고, 캐시는 최신이 아닐 수 있습니다.** 구·동 첫 조회는 건축물대장 전체를 받느라
수십 초~수 분 걸립니다(이후 15분 캐시). 실거래는 매달 갱신되므로 오래된 캐시·프리워밍 데이터는
최신 거래를 반영하지 못할 수 있습니다.
**원칙**
- **결과가 없으면 `[NOT_FOUND]` 를 반환합니다 — 데이터가 없는 것이지 0원이 아닙니다.** 이 경우
수치를 지어내면 안 됩니다(AI가 환각하지 못하도록 설계된 신호입니다).
- **소유자 등 개인정보는 다루지 않습니다.** 공개된 실거래 · 건축물대장 실측값만 반환합니다.
> 위 한계를 넘는 판단(계약 · 감정 · 고객 제시)에는 반드시 원문을 직접 확인하세요.
> 아래 고지를 함께 읽어주세요.
---
## 고지
이 도구의 결과는 **참고자료이며 중개대상물 확인·설명서가 아닙니다.**
공적장부의 원문(국토교통부 실거래가 공개시스템, 건축물대장)이 언제나 우선합니다.
고객에게 제시하거나 계약 판단에 쓰기 전에 원문을 직접 확인하세요.
매칭 결과의 정확성에 대해 제작자는 책임지지 않습니다.
출처: 국토교통부 실거래가 공개시스템 · 건축HUB (공공데이터포털 data.go.kr)
---
## Star History
[](https://star-history.com/#syleedlabs/deal-locator-mcp&Date)
---
## 라이선스
MIT License — Copyright (c) 2026 디랩스(DLABS)
동봉 폰트 [Pretendard](https://github.com/orioncactus/pretendard) 는 SIL Open Font
License 1.1 입니다. 폰트에는 MIT 가 적용되지 않습니다 — [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) 참조.
## 문의
디랩스(DLABS) · [github.com/syleedlabs](https://github.com/syleedlabs)
TDQS
Scored across 6 tools
Each tool has a distinct and well-defined purpose. resolve_address handles address parsing, deal_card_search retrieves the latest deal card for a specific parcel, deal_history provides full transaction history, match_explain details matching logic, area_scan offers area-level statistics, and deal_card_create generates a PNG card. There's no functional overlap.
All tool names follow a consistent verb_noun snake_case pattern (e.g., resolve_address, deal_card_search, area_scan). The naming is predictable and clearly describes each tool's action.
With 6 tools, the server covers the core workflows of a real estate deal locator: address resolution, individual deal lookup, history, matching explanation, area scanning, and card generation. The count feels appropriate for the domain and avoids bloat.
The tool set covers essential operations for locating commercial property deals in Seoul, including address lookup, detailed parcel info, history, matching explanation, and area-wide scanning. A minor gap is the lack of a direct search by specific building name or address beyond the initial resolve, but area_scan with road filter partially addresses this.