korean-stats-mcp 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +301 -0
- package/dist/api/client.d.ts +65 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +143 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/types.d.ts +157 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +5 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cache/index.d.ts +55 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +102 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/config/index.d.ts +46 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +54 -0
- package/dist/config/index.js.map +1 -0
- package/dist/data/quickStatsParams.d.ts +76 -0
- package/dist/data/quickStatsParams.d.ts.map +1 -0
- package/dist/data/quickStatsParams.js +1344 -0
- package/dist/data/quickStatsParams.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +5 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +5 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/statisticsAssistant.d.ts +25 -0
- package/dist/prompts/statisticsAssistant.d.ts.map +1 -0
- package/dist/prompts/statisticsAssistant.js +43 -0
- package/dist/prompts/statisticsAssistant.js.map +1 -0
- package/dist/resources/categoryTree.d.ts +18 -0
- package/dist/resources/categoryTree.d.ts.map +1 -0
- package/dist/resources/categoryTree.js +80 -0
- package/dist/resources/categoryTree.js.map +1 -0
- package/dist/resources/index.d.ts +6 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +6 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/keyIndicators.d.ts +20 -0
- package/dist/resources/keyIndicators.d.ts.map +1 -0
- package/dist/resources/keyIndicators.js +108 -0
- package/dist/resources/keyIndicators.js.map +1 -0
- package/dist/server-http.d.ts +10 -0
- package/dist/server-http.d.ts.map +1 -0
- package/dist/server-http.js +134 -0
- package/dist/server-http.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +194 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/analyzeTimeSeries.d.ts +70 -0
- package/dist/tools/analyzeTimeSeries.d.ts.map +1 -0
- package/dist/tools/analyzeTimeSeries.js +204 -0
- package/dist/tools/analyzeTimeSeries.js.map +1 -0
- package/dist/tools/chains.d.ts +197 -0
- package/dist/tools/chains.d.ts.map +1 -0
- package/dist/tools/chains.js +369 -0
- package/dist/tools/chains.js.map +1 -0
- package/dist/tools/compareStatistics.d.ts +62 -0
- package/dist/tools/compareStatistics.d.ts.map +1 -0
- package/dist/tools/compareStatistics.js +190 -0
- package/dist/tools/compareStatistics.js.map +1 -0
- package/dist/tools/fetchKosisExcel.d.ts +62 -0
- package/dist/tools/fetchKosisExcel.d.ts.map +1 -0
- package/dist/tools/fetchKosisExcel.js +366 -0
- package/dist/tools/fetchKosisExcel.js.map +1 -0
- package/dist/tools/getRecommendedStats.d.ts +41 -0
- package/dist/tools/getRecommendedStats.d.ts.map +1 -0
- package/dist/tools/getRecommendedStats.js +251 -0
- package/dist/tools/getRecommendedStats.js.map +1 -0
- package/dist/tools/getStatisticsData.d.ts +75 -0
- package/dist/tools/getStatisticsData.d.ts.map +1 -0
- package/dist/tools/getStatisticsData.js +305 -0
- package/dist/tools/getStatisticsData.js.map +1 -0
- package/dist/tools/getStatisticsList.d.ts +69 -0
- package/dist/tools/getStatisticsList.d.ts.map +1 -0
- package/dist/tools/getStatisticsList.js +336 -0
- package/dist/tools/getStatisticsList.js.map +1 -0
- package/dist/tools/getTableInfo.d.ts +66 -0
- package/dist/tools/getTableInfo.d.ts.map +1 -0
- package/dist/tools/getTableInfo.js +85 -0
- package/dist/tools/getTableInfo.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +19 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/quickStats.d.ts +71 -0
- package/dist/tools/quickStats.d.ts.map +1 -0
- package/dist/tools/quickStats.js +490 -0
- package/dist/tools/quickStats.js.map +1 -0
- package/dist/tools/quickTrend.d.ts +61 -0
- package/dist/tools/quickTrend.d.ts.map +1 -0
- package/dist/tools/quickTrend.js +328 -0
- package/dist/tools/quickTrend.js.map +1 -0
- package/dist/tools/searchStatistics.d.ts +41 -0
- package/dist/tools/searchStatistics.d.ts.map +1 -0
- package/dist/tools/searchStatistics.js +318 -0
- package/dist/tools/searchStatistics.js.map +1 -0
- package/dist/utils/dataFormatter.d.ts +40 -0
- package/dist/utils/dataFormatter.d.ts.map +1 -0
- package/dist/utils/dataFormatter.js +142 -0
- package/dist/utils/dataFormatter.js.map +1 -0
- package/dist/utils/errorHandler.d.ts +33 -0
- package/dist/utils/errorHandler.d.ts.map +1 -0
- package/dist/utils/errorHandler.js +94 -0
- package/dist/utils/errorHandler.js.map +1 -0
- package/dist/utils/metaLookup.d.ts +93 -0
- package/dist/utils/metaLookup.d.ts.map +1 -0
- package/dist/utils/metaLookup.js +170 -0
- package/dist/utils/metaLookup.js.map +1 -0
- package/dist/utils/queryParser.d.ts +45 -0
- package/dist/utils/queryParser.d.ts.map +1 -0
- package/dist/utils/queryParser.js +244 -0
- package/dist/utils/queryParser.js.map +1 -0
- package/dist/utils/regions.d.ts +70 -0
- package/dist/utils/regions.d.ts.map +1 -0
- package/dist/utils/regions.js +261 -0
- package/dist/utils/regions.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Korean Stats MCP
|
|
2
|
+
|
|
3
|
+
**KOSIS 통계청 OpenAPI를 12개 도구로.** 인구, 경제, 고용, 주거, 사회, 환경 등 91개 키워드 + 17개 시도 + 자치구·시군 230+ 자동 라우팅을 AI 어시스턴트에서 바로 사용.
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://modelcontextprotocol.io/)
|
|
7
|
+
[](https://kosis.kr/openapi/)
|
|
8
|
+
|
|
9
|
+
> 통계청 KOSIS OpenAPI 기반 MCP 서버. Claude Desktop, Cursor, Windsurf, Claude.ai 등에서 바로 사용 가능.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## v1.4 — 자연어 약어·오타·공백 정규화 + 체인 도구
|
|
14
|
+
|
|
15
|
+
**LLM이 통계청 수치를 학습 시점으로 답하는 문제를 끝낸다.** 매 질문마다 KOSIS 공식 DB를 직접 조회.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
"한국 인구가 몇 명이야?"
|
|
19
|
+
"GDP 추세 보여줘"
|
|
20
|
+
"전국 17개 시도 인구·출산율·GRDP 비교"
|
|
21
|
+
"성남시 핵심 지표 한장 브리핑"
|
|
22
|
+
"민선 4기 출산율 추이"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
→ 한 번의 호출로 KOSIS API 실시간 조회 + 자연어 응답. 별도 SQL·API 호출 불필요.
|
|
26
|
+
|
|
27
|
+
**ChatGPT·Claude가 추정한 통계 수치를 그대로 믿지 마세요.** 정책 보고서, 시정 연설, 민원 답변, 연구 자료 등 수치 신뢰가 필요한 모든 곳에 필수.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 자연어 한 줄이면 끝
|
|
32
|
+
|
|
33
|
+
**그냥 자연어로 물어보세요.** AI가 키워드·지역·연도·주기·기간을 알아서 추출합니다.
|
|
34
|
+
|
|
35
|
+
### 약어·오타·공백 변형 자동 정규화 (v1.4 신규)
|
|
36
|
+
|
|
37
|
+
| 입력 | 매칭 결과 |
|
|
38
|
+
|------|----------|
|
|
39
|
+
| `GDP` / `gdp` / `G D P` | 국내총생산 |
|
|
40
|
+
| `출산률` / `출산율` / `합계출산` | 합계출산율 |
|
|
41
|
+
| `고용율` / `취업률` | 고용률 |
|
|
42
|
+
| `실엄률` / `실업률` / `청년실업` | 실업률 |
|
|
43
|
+
| `노인` / `노년` / `65세 이상` | 65세 이상 고령인구 |
|
|
44
|
+
| `집값` / `주택값` | 주택매매가격지수 |
|
|
45
|
+
| `아파트값` / `전셋값` | 아파트·전세 가격지수 |
|
|
46
|
+
| `연봉` / `월소득` / `봉급` | 상용근로자 월평균 임금 |
|
|
47
|
+
| `population` / `fertility` / `inflation` | 영문 별칭 (인구·출산율·물가) |
|
|
48
|
+
|
|
49
|
+
→ 100개 이상의 줄임말·오타·공백 변형을 정식 키워드로 자동 매핑. 사용자가 정식 용어를 몰라도 동작.
|
|
50
|
+
|
|
51
|
+
### 시도·자치구·시군 자동 라우팅
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
"한국 인구" → 51,117,378명 (2025)
|
|
55
|
+
"서울 인구" → 9,299,548명
|
|
56
|
+
"제주 인구" → 664,792명
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
자치구·시군 230+개도 인식합니다. KOSIS OpenAPI는 광역시도 단위까지만 지원하므로, 자치구 입력 시 **소속 광역시도로 자동 fallback** + 자치구 단위 정밀 조회 경로(`fetch_kosis_excel`) 안내가 함께 나옵니다. 동명 자치구(`중구`, `남구` 등)는 광역시 컨텍스트가 같이 있으면 정확히 disambiguate.
|
|
60
|
+
|
|
61
|
+
### 시계열 추세 + 자연어 기간 추출
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
"최근 10년 출산율 추이"
|
|
65
|
+
"민선 4기 인구 변화"
|
|
66
|
+
"임기 4년차 GRDP"
|
|
67
|
+
"작년 대비 실업률"
|
|
68
|
+
"역대 출산율"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
→ "지난 N년", "민선 N기", "임기 N년차", "작년 대비", "역대" 같은 표현이 자동으로 `yearCount`로 환산됩니다. 응답에는 평균 변화율, 최고/최저점, 변동성, 추세 분류(상승·하락·안정·변동)가 함께 나옵니다.
|
|
72
|
+
|
|
73
|
+
### 체인 도구 — 한 번에 다지표·다지역·정책영역
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
"성남시 통계 한장 보고"
|
|
77
|
+
"전국 17개 시도 인구·출산율·GRDP 비교"
|
|
78
|
+
"저출산 영역 10년 추세"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
세 체인 도구가 여러 `quick_stats`/`quick_trend` 호출을 자동으로 묶어줍니다:
|
|
82
|
+
|
|
83
|
+
- **`chain_region_brief`** — 단일 지역의 13개 핵심 지표(인구·고용·경제·주거·사회·환경) 한장 브리핑. `format='speech'`면 한 줄 요약(취임사·신년사용)
|
|
84
|
+
- **`chain_compare_regions`** — N개 지역 × M개 지표 매트릭스 + 자동 순위 (전국 17개 동시 비교 가능)
|
|
85
|
+
- **`chain_policy_indicator`** — 7개 정책 영역(저출산·고령화·주거·일자리·치안·보건·경제) 묶음 10년 시계열
|
|
86
|
+
|
|
87
|
+
### 장래추계 데이터 안내
|
|
88
|
+
|
|
89
|
+
노령화지수 같이 KOSIS DB가 **장래추계 데이터를 포함**하는 통계는 응답에 `isProjection: true` + "추계" 명시 안내가 자동 부착됩니다. LLM이 미래 추계를 실측처럼 인용하는 위험 방지.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 왜 만들었나
|
|
94
|
+
|
|
95
|
+
대한민국 정부 통계는 [KOSIS](https://kosis.kr)에 모여 있지만, 공무원·연구자·기자가 매번 사이트를 뒤지거나 OpenAPI 파라미터를 조립하는 비용이 너무 큽니다. 그리고 LLM은 통계 수치를 학습 시점으로 환각하기 일쑤입니다.
|
|
96
|
+
|
|
97
|
+
이 프로젝트는 KOSIS의 핵심 통계를 **자연어 한 줄로 호출 가능한 12개 MCP 도구**로 감싸서, AI 어시스턴트나 스크립트가 KOSIS 공식 DB를 직접 조회하도록 만듭니다. 시정 보고서·민원 답변·연설문·정책수립용으로 매일 KOSIS 사이트를 검색하던 공무원이 만들었습니다.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 설치 및 사용법
|
|
102
|
+
|
|
103
|
+
### 방법 1: Claude.ai 웹 커넥터 (설치 없이 바로) ⭐ 가장 쉬움
|
|
104
|
+
|
|
105
|
+
Claude Pro/Max/Team/Enterprise 요금제에서 동작.
|
|
106
|
+
|
|
107
|
+
1. [claude.ai](https://claude.ai) 로그인 → 좌측 사이드바 본인 이름 → **설정** → **커넥터**
|
|
108
|
+
2. **커스텀 커넥터 추가** 클릭
|
|
109
|
+
3. 입력:
|
|
110
|
+
- **이름**: `korean-stats` (원하는 이름)
|
|
111
|
+
- **URL**: `https://korean-stats-mcp.fly.dev/mcp`
|
|
112
|
+
4. **추가** → 추가된 커넥터 **구성** → 모든 도구를 **"항상 사용"**으로 설정
|
|
113
|
+
5. 채팅창에 `"한국 출산율 추세 보여줘"` 같이 자연어로 질문하면 끝
|
|
114
|
+
|
|
115
|
+
### 방법 2: AI 데스크톱 앱 (설치 없음)
|
|
116
|
+
|
|
117
|
+
Claude Desktop / Cursor / Windsurf 설정 파일에 추가.
|
|
118
|
+
|
|
119
|
+
**설정 파일 위치:**
|
|
120
|
+
|
|
121
|
+
| 앱 | Windows | macOS |
|
|
122
|
+
|------|---------|-----|
|
|
123
|
+
| Claude Desktop | `%APPDATA%\Claude\claude_desktop_config.json` | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
124
|
+
| Cursor | 프로젝트 `.cursor/mcp.json` | 프로젝트 `.cursor/mcp.json` |
|
|
125
|
+
| Windsurf | 프로젝트 `.windsurf/mcp.json` | 프로젝트 `.windsurf/mcp.json` |
|
|
126
|
+
|
|
127
|
+
**설정 내용:**
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"mcpServers": {
|
|
132
|
+
"korean-stats": {
|
|
133
|
+
"command": "npx",
|
|
134
|
+
"args": ["-y", "mcp-remote", "https://korean-stats-mcp.fly.dev/mcp"]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
저장 후 앱 재시작.
|
|
141
|
+
|
|
142
|
+
### 방법 3: 로컬 설치 (오프라인 가능)
|
|
143
|
+
|
|
144
|
+
**사전 준비:** [Node.js](https://nodejs.org) 20 이상.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git clone https://github.com/chrisryugj/korean-stats-mcp.git
|
|
148
|
+
cd korean-stats-mcp
|
|
149
|
+
pnpm install
|
|
150
|
+
pnpm run build
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
AI 앱 설정:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"mcpServers": {
|
|
158
|
+
"korean-stats": {
|
|
159
|
+
"command": "node",
|
|
160
|
+
"args": ["/absolute/path/korean-stats-mcp/dist/index.js"]
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**자동 설치 스크립트:**
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
curl -fsSL https://raw.githubusercontent.com/chrisryugj/korean-stats-mcp/main/install.sh | bash
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 도구 구조 (12개)
|
|
175
|
+
|
|
176
|
+
| 구분 | 도구 | 설명 |
|
|
177
|
+
|------|------|------|
|
|
178
|
+
| **빠른 자연어** ⭐ | `quick_stats` | 자연어 한 줄 → KOSIS 수치 즉답. 91 키워드 + 100+ 별칭/오타 정규화. |
|
|
179
|
+
| | `quick_trend` | 시계열 추세 + 평균 변화율 + 최고/최저점 + 자연어 기간 추출 ("민선 4기" 등). |
|
|
180
|
+
| **체인** ⛓ | `chain_region_brief` | 단일 지역 13지표 한장 브리핑. `format='speech'`로 연설용 한 줄. |
|
|
181
|
+
| | `chain_compare_regions` | N지역 × M지표 매트릭스 + 자동 순위 (전국 17개 동시 가능). |
|
|
182
|
+
| | `chain_policy_indicator` | 7개 정책 영역(저출산·고령화·주거·일자리·치안·보건·경제) 10년 시계열. |
|
|
183
|
+
| **검색·탐색** | `search_statistics` | KOSIS 90만+ 통계표 키워드 검색 → orgId/tableId 메타 획득. |
|
|
184
|
+
| | `get_statistics_list` | 주제별·기관별 트리 탐색 + 9개 분야 추천 카드(`recommendedTopic` 옵션). |
|
|
185
|
+
| | `get_table_info` | 통계표 메타데이터 (분류·항목·주기). 경량 응답. |
|
|
186
|
+
| **데이터** | `get_statistics_data` | 특정 통계표 데이터 조회. regionName/itemName 자동 매칭. |
|
|
187
|
+
| | `compare_statistics` | 시점별·항목별 정밀 비교. |
|
|
188
|
+
| | `analyze_time_series` | 상세 시계열 (CAGR·표준편차·추세선). |
|
|
189
|
+
| **특수** | `fetch_kosis_excel` | KOSIS 파일통계표(.xlsx) 다운로드 + 파싱 ([kordoc](https://github.com/chrisryugj/kordoc) 엔진). **자치구 기본통계** 등 OpenAPI 미지원 표 커버. |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 지원 키워드 (91개 정식 + 100+ 자연어 별칭)
|
|
194
|
+
|
|
195
|
+
### 인구·출산·사망·고령화
|
|
196
|
+
인구, 총인구, 출산율, 합계출산율, 출생아수, 조출생률, 사망자수, 조사망률, 사망률, 자연증가(율), 기대수명, 평균수명, 고령인구, 노인인구, 65세이상인구, 노령화지수, 고령화지수
|
|
197
|
+
|
|
198
|
+
### 혼인·이혼
|
|
199
|
+
혼인건수, 혼인율, 조혼인율, 이혼건수, 이혼율, 조이혼율, 초혼연령, 평균초혼연령, 남성·여성초혼연령
|
|
200
|
+
|
|
201
|
+
### 고용·소득
|
|
202
|
+
실업률, 고용률, 취업자수, 실업자수, 경제활동인구, 비경제활동인구, 임금, 월평균임금, 월급, 평균임금
|
|
203
|
+
|
|
204
|
+
### 경제
|
|
205
|
+
GDP, 국내총생산, 경제성장률, GDP성장률, 물가, 소비자물가, 소비자물가지수, GRDP, 지역내총생산
|
|
206
|
+
|
|
207
|
+
### 무역
|
|
208
|
+
수출, 수출액, 수입, 수입액, 무역수지
|
|
209
|
+
|
|
210
|
+
### 주거
|
|
211
|
+
주택가격, 주택매매가격, 아파트가격, 아파트매매가격, 전세가격, 주택전세, 전세, 아파트전세
|
|
212
|
+
|
|
213
|
+
### 환경·교통·사회
|
|
214
|
+
미세먼지(PM2.5), PM10, 대기오염, 초미세먼지, 자동차, 자동차등록, 교통사고, 사고건수, 범죄, 범죄율, 범죄발생, 의사, 의사수, 의료인력, 외래관광객, 입국자, 관광객
|
|
215
|
+
|
|
216
|
+
### 자연어 별칭 (v1.4 신규)
|
|
217
|
+
출산·출생·노인·청년실업·연봉·집값·아파트값·전셋값·의료진·차량·관광객수 등 + 영문 (`population`, `fertility`, `aging`, `inflation`, `gdp` 등) + 률/율 오타 (`출산률`, `고용율`, `실엄률`, `이혼률` 등).
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 지역 라우팅
|
|
222
|
+
|
|
223
|
+
- **17개 광역시도** — 서울, 부산, 대구, 인천, 광주, 대전, 울산, 세종, 경기, 강원, 충북, 충남, 전북, 전남, 경북, 경남, 제주 (풀네임·약칭 모두 인식)
|
|
224
|
+
- **자치구·시군 230+** — 자동으로 소속 광역시도로 fallback + 자치구 단위 정밀 조회 경로 안내
|
|
225
|
+
- **동명 자치구 disambiguate** — `중구`, `남구`, `동구` 등은 광역시 컨텍스트가 같이 있으면 정확히 매칭
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 변경 이력
|
|
230
|
+
|
|
231
|
+
<details>
|
|
232
|
+
<summary>v1.4 — 자연어 정규화 + 체인 도구 + 통폐합</summary>
|
|
233
|
+
|
|
234
|
+
**자연어 약어/오타/공백 정규화 (법령 MCP의 `LAW_ALIAS_ENTRIES` 패턴 차용)**
|
|
235
|
+
- `KEYWORD_ALIASES` 100+ 별칭으로 확장 (출생·노인·연봉·집값·청년실업·영문 별칭 등)
|
|
236
|
+
- `BASIC_TYPO_MAP` 신설 — 률/율 받침 오타 자동 교정 (`출산률→출산율`, `고용율→고용률`)
|
|
237
|
+
- `normalizeKeywordKey` — 공백·대소문자·중점/하이픈 정규화 후 매칭
|
|
238
|
+
- `extractKeyword` 단일 정규화 매칭으로 재작성. "G D P", "65세 이상", "경기 노인 인구" 등 자동 인식
|
|
239
|
+
|
|
240
|
+
**체인 도구 3종**
|
|
241
|
+
- `chain_region_brief` — 13지표 한장 브리핑, `format='speech'` 옵션 추가
|
|
242
|
+
- `chain_compare_regions` — N지역×M지표 매트릭스, **전국 17개 동시 비교** (max 10→17)
|
|
243
|
+
- `chain_policy_indicator` — 7개 정책 영역 10년 시계열
|
|
244
|
+
|
|
245
|
+
**P0 fixes**
|
|
246
|
+
- 자치구 region 파라미터 fallback 미동작 버그 — `quickStats`에서 `input.region`이 자치구일 때 광역시도 변환 분기를 skip하던 가드 제거
|
|
247
|
+
- `chain_region_brief.fallbackNote` — 자치구→광역시도 변환 노트 우선 노출
|
|
248
|
+
- 노령화지수 등 장래추계 데이터 — `isProjection: true` 메타 + "추계" 명시 안내
|
|
249
|
+
|
|
250
|
+
**자연어 기간 추출**
|
|
251
|
+
- `quick_trend` 키워드에서 "지난 N년", "민선 N기", "임기 N년차", "작년 대비", "역대" 자동 → `yearCount`
|
|
252
|
+
|
|
253
|
+
**통폐합**
|
|
254
|
+
- 도구 13개 → **12개**. `get_recommended_statistics`를 `get_statistics_list`의 `recommendedTopic` 옵션으로 흡수
|
|
255
|
+
|
|
256
|
+
</details>
|
|
257
|
+
|
|
258
|
+
<details>
|
|
259
|
+
<summary>v1.3 — P0 자치구 라우팅 일소 + 체인 도구 도입</summary>
|
|
260
|
+
|
|
261
|
+
- `DISTRICT_TO_PROVINCE` 33 → 200+ (경기·강원·충북·충남·전북·전남·경북·경남 전체 시군 + 부산 영도·동래·인천 남동 등)
|
|
262
|
+
- `AMBIGUOUS_DISTRICTS` + 광역시도 컨텍스트로 "광주 동구" / "부산 강서구" 정확 매칭
|
|
263
|
+
- `extractDistrictName` 광역시 약칭 가드 — "대구" 같은 광역시 약칭이 자치구로 오인되는 버그 fix
|
|
264
|
+
- 체인 도구 3종 신설 (region_brief, compare_regions, policy_indicator)
|
|
265
|
+
|
|
266
|
+
</details>
|
|
267
|
+
|
|
268
|
+
<details>
|
|
269
|
+
<summary>v1.2 — 자치구 라우팅 + 부분매칭 버그 픽스</summary>
|
|
270
|
+
|
|
271
|
+
- `quick_trend` keyword 자연어 처리 (extract* 헬퍼 공유)
|
|
272
|
+
- `extractProvinceName` 단어 경계 매칭으로 "해운대구"의 "대구" 부분매칭 버그 차단
|
|
273
|
+
- 자치구 → 광역시도 fallback + 자치구 단위 정밀 조회 경로(`fetch_kosis_excel`) 안내
|
|
274
|
+
|
|
275
|
+
</details>
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## 주요 특징
|
|
280
|
+
|
|
281
|
+
- **91개 키워드 + 100+ 자연어 별칭** — 줄임말·률/율 오타·공백 변형 자동 정규화
|
|
282
|
+
- **17개 시도 + 자치구·시군 230+** — 자치구는 광역시도로 자동 fallback + 정밀 조회 경로 안내
|
|
283
|
+
- **체인 도구 3종** — 단일 지역 13지표 한장 브리핑, N지역×M지표 매트릭스(전국 17개 동시), 7개 정책 영역 시계열
|
|
284
|
+
- **자연어 기간 추출** — "민선 4기", "임기 4년차", "작년 대비", "역대" 자동 환산
|
|
285
|
+
- **장래추계 안내** — 노령화지수 등 추계 데이터는 `isProjection: true` + "추계" 명시 안내
|
|
286
|
+
- **파일통계표 파싱** — KOSIS OpenAPI 미지원 표(.xlsx)는 [kordoc](https://github.com/chrisryugj/kordoc) 엔진으로 다운로드·파싱·Markdown 변환
|
|
287
|
+
- **캐시** — LRU 기반, 통계 데이터 6시간 TTL
|
|
288
|
+
- **원격 엔드포인트** — 설치 없이 `https://korean-stats-mcp.fly.dev/mcp`로 바로 사용
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 원격 엔드포인트
|
|
293
|
+
|
|
294
|
+
- **`https://korean-stats-mcp.fly.dev/mcp`** — Fly.io Singapore 리전, stateless HTTP, 12개 도구 전체 동작
|
|
295
|
+
- 헬스체크: `https://korean-stats-mcp.fly.dev/health`
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 라이선스
|
|
300
|
+
|
|
301
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOSIS OpenAPI HTTP 클라이언트
|
|
3
|
+
*/
|
|
4
|
+
import type { StatisticsListItem, StatisticsDataItem, SearchResultItem } from './types.js';
|
|
5
|
+
declare class KosisApiError extends Error {
|
|
6
|
+
code: string;
|
|
7
|
+
originalError?: Error | undefined;
|
|
8
|
+
constructor(code: string, message: string, originalError?: Error | undefined);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* KOSIS API 클라이언트
|
|
12
|
+
*/
|
|
13
|
+
export declare class KosisClient {
|
|
14
|
+
private baseUrl;
|
|
15
|
+
private apiKey;
|
|
16
|
+
constructor(apiKey?: string);
|
|
17
|
+
/**
|
|
18
|
+
* API 요청 실행
|
|
19
|
+
*/
|
|
20
|
+
private request;
|
|
21
|
+
/**
|
|
22
|
+
* 통계목록 조회
|
|
23
|
+
*/
|
|
24
|
+
getStatisticsList(vwCd: string, parentListId?: string): Promise<StatisticsListItem[]>;
|
|
25
|
+
/**
|
|
26
|
+
* 통계자료 조회 (통계표 선택 방식)
|
|
27
|
+
*/
|
|
28
|
+
getStatisticsData(params: {
|
|
29
|
+
orgId: string;
|
|
30
|
+
tblId: string;
|
|
31
|
+
objL1?: string;
|
|
32
|
+
objL2?: string;
|
|
33
|
+
objL3?: string;
|
|
34
|
+
objL4?: string;
|
|
35
|
+
itmId?: string;
|
|
36
|
+
prdSe: string;
|
|
37
|
+
startPrdDe?: string;
|
|
38
|
+
endPrdDe?: string;
|
|
39
|
+
newEstPrdCnt?: number;
|
|
40
|
+
}): Promise<StatisticsDataItem[]>;
|
|
41
|
+
/**
|
|
42
|
+
* 통합검색
|
|
43
|
+
* API 문서: https://kosis.kr/openapi/devGuide/devGuide_0701List.do
|
|
44
|
+
*/
|
|
45
|
+
searchStatistics(searchNm: string, options?: {
|
|
46
|
+
orgId?: string;
|
|
47
|
+
sort?: 'RANK' | 'DATE';
|
|
48
|
+
startCount?: number;
|
|
49
|
+
resultCount?: number;
|
|
50
|
+
}): Promise<SearchResultItem[]>;
|
|
51
|
+
/**
|
|
52
|
+
* 통계설명 조회
|
|
53
|
+
*/
|
|
54
|
+
getStatisticsExplain(orgId: string, tblId: string): Promise<Record<string, string>[]>;
|
|
55
|
+
/**
|
|
56
|
+
* 통계표 메타데이터 조회 (분류/항목 정보)
|
|
57
|
+
* @param orgId 기관 ID
|
|
58
|
+
* @param tblId 통계표 ID
|
|
59
|
+
* @param metaType 메타데이터 유형: TBL(통계표명), ORG(기관명), PRD(수록정보), ITM(분류/항목), UNIT(단위), SOURCE(출처)
|
|
60
|
+
*/
|
|
61
|
+
getTableMeta(orgId: string, tblId: string, metaType?: 'TBL' | 'ORG' | 'PRD' | 'ITM' | 'UNIT' | 'SOURCE'): Promise<Record<string, string>[]>;
|
|
62
|
+
}
|
|
63
|
+
export declare function getKosisClient(): KosisClient;
|
|
64
|
+
export { KosisApiError };
|
|
65
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAIjB,MAAM,YAAY,CAAC;AAEpB,cAAM,aAAc,SAAQ,KAAK;IAEtB,IAAI,EAAE,MAAM;IAEZ,aAAa,CAAC,EAAE,KAAK;gBAFrB,IAAI,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACR,aAAa,CAAC,EAAE,KAAK,YAAA;CAK/B;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAK3B;;OAEG;YACW,OAAO;IAyErB;;OAEG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,MAAW,GACxB,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAWhC;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAUjC;;;OAGG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GACA,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAW9B;;OAEG;IACG,oBAAoB,CACxB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IASpC;;;;;OAKG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAgB,GAClE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAQrC;AAKD,wBAAgB,cAAc,IAAI,WAAW,CAK5C;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOSIS OpenAPI HTTP 클라이언트
|
|
3
|
+
*/
|
|
4
|
+
import { config } from '../config/index.js';
|
|
5
|
+
class KosisApiError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
originalError;
|
|
8
|
+
constructor(code, message, originalError) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.originalError = originalError;
|
|
12
|
+
this.name = 'KosisApiError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* KOSIS API 클라이언트
|
|
17
|
+
*/
|
|
18
|
+
export class KosisClient {
|
|
19
|
+
baseUrl;
|
|
20
|
+
apiKey;
|
|
21
|
+
constructor(apiKey) {
|
|
22
|
+
this.baseUrl = config.kosis.baseUrl;
|
|
23
|
+
this.apiKey = apiKey || config.kosis.apiKey;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* API 요청 실행
|
|
27
|
+
*/
|
|
28
|
+
async request(endpoint, params) {
|
|
29
|
+
// undefined 값 제거 및 문자열 변환
|
|
30
|
+
const cleanParams = {};
|
|
31
|
+
for (const [key, value] of Object.entries(params)) {
|
|
32
|
+
if (value !== undefined) {
|
|
33
|
+
cleanParams[key] = String(value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
cleanParams.apiKey = this.apiKey;
|
|
37
|
+
cleanParams.format = 'json';
|
|
38
|
+
cleanParams.jsonVD = 'Y';
|
|
39
|
+
const url = new URL(this.baseUrl + endpoint);
|
|
40
|
+
url.search = new URLSearchParams(cleanParams).toString();
|
|
41
|
+
// 8초 타임아웃 (Vercel maxDuration 15초 내에 여유 확보)
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const timeoutId = setTimeout(() => controller.abort(), 8000);
|
|
44
|
+
try {
|
|
45
|
+
const response = await fetch(url.toString(), {
|
|
46
|
+
signal: controller.signal,
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new KosisApiError('HTTP_ERROR', `HTTP ${response.status}: ${response.statusText}`);
|
|
50
|
+
}
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
// 에러 응답 처리
|
|
53
|
+
if (data.err || data.errMsg) {
|
|
54
|
+
throw new KosisApiError(data.err || 'API_ERROR', data.errMsg || '알 수 없는 API 오류');
|
|
55
|
+
}
|
|
56
|
+
// 결과가 배열이 아닌 경우 빈 배열 반환
|
|
57
|
+
if (!Array.isArray(data)) {
|
|
58
|
+
if (data.result && Array.isArray(data.result)) {
|
|
59
|
+
return data.result;
|
|
60
|
+
}
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof KosisApiError) {
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
70
|
+
throw new KosisApiError('TIMEOUT', 'KOSIS API 응답 시간 초과 (8초). 잠시 후 다시 시도해주세요.');
|
|
71
|
+
}
|
|
72
|
+
throw new KosisApiError('NETWORK_ERROR', '네트워크 오류가 발생했습니다.', error);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
clearTimeout(timeoutId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 통계목록 조회
|
|
80
|
+
*/
|
|
81
|
+
async getStatisticsList(vwCd, parentListId = '') {
|
|
82
|
+
return this.request(config.kosis.endpoints.statisticsList, {
|
|
83
|
+
method: 'getList',
|
|
84
|
+
vwCd,
|
|
85
|
+
parentListId,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 통계자료 조회 (통계표 선택 방식)
|
|
90
|
+
*/
|
|
91
|
+
async getStatisticsData(params) {
|
|
92
|
+
return this.request(config.kosis.endpoints.parameterData, {
|
|
93
|
+
method: 'getList',
|
|
94
|
+
...params,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 통합검색
|
|
99
|
+
* API 문서: https://kosis.kr/openapi/devGuide/devGuide_0701List.do
|
|
100
|
+
*/
|
|
101
|
+
async searchStatistics(searchNm, options) {
|
|
102
|
+
return this.request(config.kosis.endpoints.searchStatistics, {
|
|
103
|
+
method: 'getList',
|
|
104
|
+
searchNm,
|
|
105
|
+
...options,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 통계설명 조회
|
|
110
|
+
*/
|
|
111
|
+
async getStatisticsExplain(orgId, tblId) {
|
|
112
|
+
return this.request(config.kosis.endpoints.statsExplain, {
|
|
113
|
+
method: 'getMeta',
|
|
114
|
+
type: 'TBL',
|
|
115
|
+
orgId,
|
|
116
|
+
tblId,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 통계표 메타데이터 조회 (분류/항목 정보)
|
|
121
|
+
* @param orgId 기관 ID
|
|
122
|
+
* @param tblId 통계표 ID
|
|
123
|
+
* @param metaType 메타데이터 유형: TBL(통계표명), ORG(기관명), PRD(수록정보), ITM(분류/항목), UNIT(단위), SOURCE(출처)
|
|
124
|
+
*/
|
|
125
|
+
async getTableMeta(orgId, tblId, metaType = 'ITM') {
|
|
126
|
+
return this.request(config.kosis.endpoints.statisticsData, {
|
|
127
|
+
method: 'getMeta',
|
|
128
|
+
type: metaType,
|
|
129
|
+
orgId,
|
|
130
|
+
tblId,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// 싱글톤 인스턴스
|
|
135
|
+
let clientInstance = null;
|
|
136
|
+
export function getKosisClient() {
|
|
137
|
+
if (!clientInstance) {
|
|
138
|
+
clientInstance = new KosisClient();
|
|
139
|
+
}
|
|
140
|
+
return clientInstance;
|
|
141
|
+
}
|
|
142
|
+
export { KosisApiError };
|
|
143
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|