korean-stats-mcp 1.6.0 → 1.8.1

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.
Files changed (90) hide show
  1. package/README.md +218 -187
  2. package/dist/api/client.d.ts +5 -2
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +11 -4
  5. package/dist/api/client.js.map +1 -1
  6. package/dist/api/types.d.ts +14 -9
  7. package/dist/api/types.d.ts.map +1 -1
  8. package/dist/cache/index.d.ts +2 -0
  9. package/dist/cache/index.d.ts.map +1 -1
  10. package/dist/cache/index.js +24 -4
  11. package/dist/cache/index.js.map +1 -1
  12. package/dist/config/index.d.ts +1 -1
  13. package/dist/config/index.d.ts.map +1 -1
  14. package/dist/config/index.js +2 -1
  15. package/dist/config/index.js.map +1 -1
  16. package/dist/data/districtFileMap.d.ts +16 -2
  17. package/dist/data/districtFileMap.d.ts.map +1 -1
  18. package/dist/data/districtFileMap.js +50 -11
  19. package/dist/data/districtFileMap.js.map +1 -1
  20. package/dist/data/quickStatsParams.d.ts +24 -1
  21. package/dist/data/quickStatsParams.d.ts.map +1 -1
  22. package/dist/data/quickStatsParams.js +70 -22
  23. package/dist/data/quickStatsParams.js.map +1 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/server-http.js +68 -12
  27. package/dist/server-http.js.map +1 -1
  28. package/dist/server.d.ts +4 -1
  29. package/dist/server.d.ts.map +1 -1
  30. package/dist/server.js +24 -4
  31. package/dist/server.js.map +1 -1
  32. package/dist/tools/analyzeTimeSeries.d.ts.map +1 -1
  33. package/dist/tools/analyzeTimeSeries.js +11 -10
  34. package/dist/tools/analyzeTimeSeries.js.map +1 -1
  35. package/dist/tools/chains.d.ts +4 -0
  36. package/dist/tools/chains.d.ts.map +1 -1
  37. package/dist/tools/chains.js +63 -42
  38. package/dist/tools/chains.js.map +1 -1
  39. package/dist/tools/compareStatistics.d.ts.map +1 -1
  40. package/dist/tools/compareStatistics.js +21 -4
  41. package/dist/tools/compareStatistics.js.map +1 -1
  42. package/dist/tools/explainStatistic.d.ts +43 -0
  43. package/dist/tools/explainStatistic.d.ts.map +1 -0
  44. package/dist/tools/explainStatistic.js +168 -0
  45. package/dist/tools/explainStatistic.js.map +1 -0
  46. package/dist/tools/fetchKosisExcel.d.ts +3 -0
  47. package/dist/tools/fetchKosisExcel.d.ts.map +1 -1
  48. package/dist/tools/fetchKosisExcel.js +33 -12
  49. package/dist/tools/fetchKosisExcel.js.map +1 -1
  50. package/dist/tools/getStatisticsData.js +2 -2
  51. package/dist/tools/getStatisticsList.js +1 -1
  52. package/dist/tools/getStatisticsList.js.map +1 -1
  53. package/dist/tools/index.d.ts +2 -0
  54. package/dist/tools/index.d.ts.map +1 -1
  55. package/dist/tools/index.js +2 -0
  56. package/dist/tools/index.js.map +1 -1
  57. package/dist/tools/quickRank.d.ts +62 -0
  58. package/dist/tools/quickRank.d.ts.map +1 -0
  59. package/dist/tools/quickRank.js +395 -0
  60. package/dist/tools/quickRank.js.map +1 -0
  61. package/dist/tools/quickStats.d.ts +4 -0
  62. package/dist/tools/quickStats.d.ts.map +1 -1
  63. package/dist/tools/quickStats.js +242 -165
  64. package/dist/tools/quickStats.js.map +1 -1
  65. package/dist/tools/quickTrend.d.ts +1 -1
  66. package/dist/tools/quickTrend.d.ts.map +1 -1
  67. package/dist/tools/quickTrend.js +79 -43
  68. package/dist/tools/quickTrend.js.map +1 -1
  69. package/dist/tools/searchStatistics.d.ts.map +1 -1
  70. package/dist/tools/searchStatistics.js +14 -11
  71. package/dist/tools/searchStatistics.js.map +1 -1
  72. package/dist/utils/concurrency.d.ts +11 -0
  73. package/dist/utils/concurrency.d.ts.map +1 -0
  74. package/dist/utils/concurrency.js +23 -0
  75. package/dist/utils/concurrency.js.map +1 -0
  76. package/dist/utils/dataFormatter.d.ts +7 -0
  77. package/dist/utils/dataFormatter.d.ts.map +1 -1
  78. package/dist/utils/dataFormatter.js +15 -0
  79. package/dist/utils/dataFormatter.js.map +1 -1
  80. package/dist/utils/districtKosisCodes.d.ts.map +1 -1
  81. package/dist/utils/districtKosisCodes.js +34 -5
  82. package/dist/utils/districtKosisCodes.js.map +1 -1
  83. package/dist/utils/queryParser.d.ts.map +1 -1
  84. package/dist/utils/queryParser.js +4 -2
  85. package/dist/utils/queryParser.js.map +1 -1
  86. package/dist/utils/regions.d.ts +9 -0
  87. package/dist/utils/regions.d.ts.map +1 -1
  88. package/dist/utils/regions.js +9 -0
  89. package/dist/utils/regions.js.map +1 -1
  90. package/package.json +22 -8
package/README.md CHANGED
@@ -1,130 +1,236 @@
1
1
  # Korean Stats MCP
2
2
 
3
- **KOSIS 통계청 OpenAPI를 12개 도구로.** 인구, 경제, 고용, 주거, 사회, 환경 등 91개 키워드 + 17개 시도 + 자치구·시군 230+ 자동 라우팅을 AI 어시스턴트에서 바로 사용.
3
+ **국가데이터처 KOSIS, 이제 사이트에 들어가지 않습니다.**
4
+ AI 어시스턴트에게 한국어로 물어보면 국가데이터처 공식 수치가 출처와 함께 바로 나옵니다.
4
5
 
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
7
  [![MCP](https://img.shields.io/badge/MCP-Compatible-blue)](https://modelcontextprotocol.io/)
7
8
  [![KOSIS](https://img.shields.io/badge/KOSIS-OpenAPI-green)](https://kosis.kr/openapi/)
8
9
 
9
- > 통계청 KOSIS OpenAPI 기반 MCP 서버. Claude Desktop, Cursor, Windsurf, Claude.ai 등에서 바로 사용 가능.
10
+ > 국가데이터처 KOSIS OpenAPI 기반 MCP 서버. Claude Desktop·Cursor·Claude.ai 등에서 바로 사용. 설치 없이 웹 커넥터로도 가능.
10
11
 
11
12
  ---
12
13
 
13
- ## v1.6 자치구·시군 230+ 정밀 라우팅 + 자연어 정규화 + 체인 도구
14
+ ## 30초 만에 겪어보기
14
15
 
15
- **LLM이 통계청 수치를 학습 시점으로 답하는 문제를 끝낸다.** 질문마다 KOSIS 공식 DB를 직접 조회.
16
+ > 채팅창에 이렇게 칩니다 (Claude.ai 커넥터 등록 [아래 설치법](#설치-3가지-방법) 참고)
16
17
 
17
18
  ```
18
- "한국 인구가 명이야?"
19
- "GDP 추세 보여줘"
20
- "전국 17개 시도 인구·출산율·GRDP 비교"
21
- "성남시 핵심 지표 한장 브리핑"
22
- "민선 4기 출산율 추이"
19
+ 나: 광진구 고용률 알려줘
20
+
21
+ AI: 2025년 하반기 광진구의 고용률은 61.6%입니다.
22
+ 📊 출처: 고용률 (KOSIS DT_1ES3A03_A01S)
23
23
  ```
24
24
 
25
- 번의 호출로 KOSIS API 실시간 조회 + 자연어 응답. 별도 SQL·API 호출 불필요.
25
+ KOSIS 사이트에 들어가 통계표를 찾고 분류 코드를 고르고 자치구 행을 스크롤할 필요가 없습니다.
26
+ **자치구 이름과 궁금한 것만 한국어로 던지면 됩니다.**
27
+
28
+ ---
29
+
30
+ ## 공무원 업무, 이렇게 바뀝니다
31
+
32
+ 국가데이터처 통계는 [KOSIS](https://kosis.kr)에 다 있습니다. 문제는 **꺼내 쓰는 비용**입니다.
33
+ 통계표 ID를 모르면 검색에서 헤매고, 찾아도 분류·항목·주기 코드를 조립해야 하고, 자치구 단위는 표 안에서 행을 뒤져야 합니다. 그래서 보고서 마감 직전마다 KOSIS와 씨름합니다.
26
34
 
27
- **ChatGPT·Claude가 추정한 통계 수치를 그대로 믿지 마세요.** 정책 보고서, 시정 연설, 민원 답변, 연구 자료 등 수치 신뢰가 필요한 모든 곳에 필수.
35
+ 도구는 과정을 **자연어 줄**로 줄입니다. 실제 업무 장면으로 봅니다.
28
36
 
29
37
  ---
30
38
 
31
- ## 자연어 줄이면
39
+ ### 📋 시정연설·신년사·업무보고 30분이 5초로
32
40
 
33
- **그냥 자연어로 물어보세요.** AI가 키워드·지역·연도·주기·기간을 알아서 추출합니다.
41
+ > **상황** 시장 신년사 원고에 "우리 시 현황" 한 단락을 넣어야 한다. 인구·출산율·고용·지역경제 수치를 KOSIS에서 하나씩 베껴오는 데 매번 30분~1시간.
34
42
 
35
- ### 약어·오타·공백 변형 자동 정규화 (v1.4 신규)
43
+ ```
44
+ 나: 성남시 신년사에 넣을 핵심 통계 한 줄로 정리해줘
36
45
 
37
- | 입력 | 매칭 결과 |
38
- |------|----------|
39
- | `GDP` / `gdp` / `G D P` | 국내총생산 |
40
- | `출산률` / `출산율` / `합계출산` | 합계출산율 |
41
- | `고용율` / `취업률` | 고용률 |
42
- | `실엄률` / `실업률` / `청년실업` | 실업률 |
43
- | `노인` / `노년` / `65세 이상` | 65세 이상 고령인구 |
44
- | `집값` / `주택값` | 주택매매가격지수 |
45
- | `아파트값` / `전셋값` | 아파트·전세 가격지수 |
46
- | `연봉` / `월소득` / `봉급` | 상용근로자 월평균 임금 |
47
- | `population` / `fertility` / `inflation` | 영문 별칭 (인구·출산율·물가) |
46
+ AI: 성남시의 주민등록 인구 ○○만 명, 합계출산율 ○.○○명,
47
+ 65세 이상 고령인구 ○○만 명, 실업률 ○.○%, 지역내총생산 ○○조 원
48
+ (○○○○년 기준)입니다.
49
+ ```
50
+
51
+ `chain_region_brief`의 **연설용 모드**가 핵심 지표를 자동으로 추려 한 문장으로 만듭니다. 13개 지표 전체 브리핑도 한 번에 가능합니다.
48
52
 
49
- → 100개 이상의 줄임말·오타·공백 변형을 정식 키워드로 자동 매핑. 사용자가 정식 용어를 몰라도 동작.
53
+ ---
50
54
 
51
- ### 시도·자치구·시군 자동 라우팅
55
+ ### 🏛 지방의회 답변·행정사무감사 대비 — "옆 동네보다 낮은 거 아니냐"
56
+
57
+ > **상황** — 의원이 "우리 구 실업률이 인접 구보다 높은 것 아니냐"고 질의할 예정. 인접 자치구를 일일이 조회해 비교표를 만들어야 한다.
52
58
 
53
59
  ```
54
- "한국 인구" → 51,117,378명 (2025)
55
- "서울 인구" → 9,299,548명
56
- "제주 인구" → 664,792명
60
+ 나: 강남구, 서초구, 송파구 실업률이랑 고용률 비교해줘
61
+
62
+ AI: 📊 3개 지역 × 2개 지표 비교
63
+ • 실업률: 최고 ○○구(○.○%), 최저 ○○구(○.○%)
64
+ • 고용률: 최고 ○○구(○○.○%), 최저 ○○구(○○.○%)
65
+ [지역별 순위 매트릭스 + 기준시점 포함]
57
66
  ```
58
67
 
59
- 전국 230+ 자치구·시군도 **정밀 라우팅**합니다. `광진구 인구`, `해운대구 고용률`, `수원시 사망률`처럼 자치구를 입력하면 KOSIS 자치구 단위 통계표(14종)로 직접 조회해 정확한 수치를 돌려줍니다 — 인구·출산·고령인구·의사수·아파트/전세가격·고용률·취업자·실업률·사망자수·사망률·혼인(건수·율)·이혼(건수·율). 자치구 통계연보(`.xlsx`)가 있으면 그쪽을 우선 쓰고, 없으면 KOSIS OpenAPI 자치구 코드로 라우팅합니다. 매핑이 없거나 KOSIS가 자치구 데이터를 미수록한 경우에만 소속 광역시도로 fallback + 안내합니다. 동명 자치구(`중구`, `남구` 등)는 광역시 컨텍스트가 같이 있으면 정확히 disambiguate.
68
+ `chain_compare_regions`는 **최대 17개 지역 × 8개 지표**를 번에 매트릭스로 만들고 지표별 순위까지 매깁니다. "전국 17개 시도 출산율 순위"도 줄입니다.
60
69
 
61
- ### 시계열 추세 + 자연어 기간 추출
70
+ ---
71
+
72
+ ### 📑 정책보고서·연구용역 현황 분석 — 10년 추세를 한 번에
73
+
74
+ > **상황** — 저출산 대응 5개년 계획 보고서. "최근 10년 추세" 챕터에 들어갈 시계열 데이터가 필요하다.
62
75
 
63
76
  ```
64
- "최근 10년 출산율 추이"
65
- "민선 4기 인구 변화"
66
- "임기 4년차 GRDP"
67
- "작년 대비 실업률"
68
- "역대 출산율"
77
+ 나: 저출산 영역 최근 10년 추세 정리해줘
78
+
79
+ AI: 📑 저출산 영역 10년 추세
80
+ 합계출산율: 지속 하락 (20○○→20○○년, -○○%)
81
+ 출생아수: 지속 하락 (-○○%)
82
+ • 혼인건수: 지속 하락 (-○○%)
83
+ • 평균초혼연령: 상승 (+○.○세)
84
+ [연도별 데이터포인트 + 변화율 전체]
69
85
  ```
70
86
 
71
- "지난 N년", "민선 N기", "임기 N년차", "작년 대비", "역대" 같은 표현이 자동으로 `yearCount`로 환산됩니다. 응답에는 평균 변화율, 최고/최저점, 변동성, 추세 분류(상승·하락·안정·변동)가 함께 나옵니다.
87
+ `chain_policy_indicator`는 **7개 정책 영역**(저출산·고령화·주거·일자리·치안·보건·경제)을 영역별 3~4개 지표 묶음으로 시계열 분석합니다. 평균 변화율·최고/최저점·추세 분류가 함께 나옵니다.
88
+
89
+ ---
90
+
91
+ ### 🗣 민원 응대·보도자료 — 묻는 즉시 공식 수치
72
92
 
73
- ### 체인 도구 번에 다지표·다지역·정책영역
93
+ > **상황**"우리 동네 미세먼지가 요즘 어떠냐"는 민원 전화. 또는 보도자료에 들어갈 수치를 30분 뒤 회신해야 한다.
74
94
 
75
95
  ```
76
- "성남시 통계 한장 보고"
77
- "전국 17개 시도 인구·출산율·GRDP 비교"
78
- "저출산 영역 10년 추세"
96
+ 나: 충남 미세먼지 수치
97
+ AI: 20○○년 충남의 PM2.5 농도는 ○○㎍/㎥입니다. 📊 출처: KOSIS
98
+
99
+ 나: 부산 인구 최근 10년 변화는?
100
+ AI: 부산의 인구 10년 추세: 지속적인 하락 추세. ... (변화율·최고/최저점 포함)
79
101
  ```
80
102
 
81
- 체인 도구가 여러 `quick_stats`/`quick_trend` 호출을 자동으로 묶어줍니다:
103
+ 단일 수치는 `quick_stats`, 추세는 `quick_trend`. **모든 응답에 통계표 출처가 붙어** 그대로 인용할 수 있습니다.
82
104
 
83
- - **`chain_region_brief`** — 단일 지역의 13개 핵심 지표(인구·고용·경제·주거·사회·환경) 한장 브리핑. `format='speech'`면 한 줄 요약(취임사·신년사용)
84
- - **`chain_compare_regions`** — N개 지역 × M개 지표 매트릭스 + 자동 순위 (전국 17개 동시 비교 가능)
85
- - **`chain_policy_indicator`** — 7개 정책 영역(저출산·고령화·주거·일자리·치안·보건·경제) 묶음 10년 시계열
105
+ ---
86
106
 
87
- ### 장래추계 데이터 안내
107
+ ### 🎯 자치구·시군 단위까지 — 광역 평균에 묻히지 않습니다
88
108
 
89
- 노령화지수 같이 KOSIS DB가 **장래추계 데이터를 포함**하는 통계는 응답에 `isProjection: true` + "추계" 명시 안내가 자동 부착됩니다. LLM이 미래 추계를 실측처럼 인용하는 위험 방지.
109
+ > **상황** "광진구" 고용률이 필요한데 검색하면 "서울특별시" 평균만 나온다.
110
+
111
+ ```
112
+ 나: 광진구 고용률, 광진구 65세 이상 인구
113
+
114
+ AI: 2025년 하반기 광진구의 고용률은 61.6%입니다.
115
+ 2024년 광진구의 65세 이상 고령인구는 ○○,○○○명입니다.
116
+ ```
117
+
118
+ 전국 **230개 이상의 자치구·시군**을 KOSIS 자치구 단위 통계표로 직접 조회합니다. 전국 226개 시군구가 동일 구조로 수록된 **KOSIS 표준 통계표(자치구 코드 라우팅)를 우선** 쓰고, 표준표에 없는 분야만 자치구 통계연보(`.xlsx`)로 보완합니다. `중구`·`남구`처럼 여러 시에 있는 이름도 "부산 중구"처럼 광역시를 같이 말하면 정확히 구분합니다.
90
119
 
91
120
  ---
92
121
 
93
- ## 만들었나
122
+ ### 🛡 ChatGPT가 찍어준 통계, 그대로 보고서에 넣지 마세요
123
+
124
+ 일반 AI는 통계 수치를 **학습 시점 기준으로 기억**합니다. "서울 인구"를 물으면 몇 년 전 값을 자신 있게 답합니다. 그 수치가 보고서·연설문·국정감사 자료에 들어가면 사고입니다.
94
125
 
95
- 대한민국 정부 통계는 [KOSIS](https://kosis.kr)에 모여 있지만, 공무원·연구자·기자가 매번 사이트를 뒤지거나 OpenAPI 파라미터를 조립하는 비용이 너무 큽니다. 그리고 LLM은 통계 수치를 학습 시점으로 환각하기 일쑤입니다.
126
+ 커넥터를 켜면 AI는 **질문할 때마다 KOSIS 공식 DB를 실시간 조회**하고, 답변에 통계표 ID(출처)를 함께 표기합니다. 추정이 아니라 인용입니다.
96
127
 
97
- 프로젝트는 KOSIS의 핵심 통계를 **자연어 줄로 호출 가능한 12개 MCP 도구**로 감싸서, AI 어시스턴트나 스크립트가 KOSIS 공식 DB를 직접 조회하도록 만듭니다.
128
+ > 장래추계가 포함된 통계는 "수치는 실측이 아닌 국가데이터처 추계"라는 안내가, 인구동향(출생·사망·혼인·이혼) 최근 시점에는 "잠정치일 있음" 안내가 자동으로 붙습니다. 추계·잠정치를 확정 실측처럼 인용하는 실수를 막습니다.
98
129
 
99
130
  ---
100
131
 
101
- ## 설치 사용법
132
+ ## 무엇을 물어볼 수 있나
133
+
134
+ ### 통계 키워드 — 92개 + 자연어 별칭 100개 이상
135
+
136
+ | 분야 | 예시 키워드 |
137
+ |------|------------|
138
+ | 인구·출산·고령 | 인구, 출산율, 출생아수, 사망률, 기대수명, 고령인구, 노령화지수 |
139
+ | 혼인·이혼 | 혼인건수, 이혼율, 초혼연령, 평균초혼연령 |
140
+ | 고용·소득 | 실업률, 고용률, 취업자수, 경제활동인구, 월평균임금 |
141
+ | 경제 | GDP, 경제성장률, 물가(소비자물가지수), GRDP(지역내총생산) |
142
+ | 무역 | 수출, 수입, 무역수지 |
143
+ | 주거 | 주택매매가격, 아파트가격, 전세가격 |
144
+ | 환경·교통·사회 | 미세먼지(PM2.5/PM10), 자동차등록, 교통사고, 범죄율, 의사수, 외래관광객 |
145
+
146
+ **정식 용어를 몰라도 됩니다.** `집값`→주택매매가격, `노인`→고령인구, `월소득`→월평균임금처럼 줄임말·구어체를 자동 변환합니다. `출산률`·`고용율` 같은 률/율 오타, `G D P` 같은 공백, `population`·`gdp` 같은 영문도 인식합니다.
147
+
148
+ > 정의가 **다른** 지표는 조용히 바꿔치지 않습니다 — `청년실업률`(15~29세)·`연봉`(연 단위)·`가계소득`처럼 비슷해 보여도 다른 통계인 질문에는 오답 대신 "어느 통계를 봐야 하는지" 안내가 나갑니다. 지역명도 마찬가지 — 인식 못 한 지역명에 전국값을 대신 내놓지 않습니다.
149
+
150
+ ### 지역 — 17개 시도 + 자치구·시군 230개 이상
151
+
152
+ 전국 광역시도 17개(풀네임·약칭 모두)와 자치구·시군 230여 곳. `"민선 8기 출산율 추이"`, `"임기 4년차 GRDP"`, `"작년 대비 실업률"`, `"역대 인구"` 같은 한국 행정 어법의 기간 표현도 자동으로 분석 연수로 환산합니다.
153
+
154
+ ---
155
+
156
+ ## 14개 도구
157
+
158
+ 대부분의 질문은 **`quick_stats`·`quick_trend`·`quick_rank`·체인 도구 3종**이면 끝납니다. 나머지는 정밀 조회용입니다.
159
+
160
+ | 구분 | 도구 | 하는 일 |
161
+ |------|------|---------|
162
+ | **자연어 즉답** ⭐ | `quick_stats` | 자연어 한 줄 → KOSIS 수치 즉답 |
163
+ | | `quick_trend` | 시계열 추세 + 변화율 + 최고/최저점 (자연어 기간 인식) |
164
+ | | `quick_rank` 🆕 | "우리 지역 전국 몇 위?" — 17개 시도 또는 시군구 전수 대비 순위·백분위·평균 격차·순위 변동. 동일 표·동일 시점 단일 조회로 비교가능성 보장 |
165
+ | **출처·각주** 🆕 | `explain_statistic` | 통계 공식 정의·작성목적·조사주기·용어해설 + 보고서 인용 각주 문구 생성 |
166
+ | **체인** ⛓ | `chain_region_brief` | 한 지역 13개 지표 종합 브리핑 (연설용 한 줄 모드 포함) |
167
+ | | `chain_compare_regions` | N개 지역 × M개 지표 매트릭스 + 순위 (최대 17×8) |
168
+ | | `chain_policy_indicator` | 7개 정책 영역 묶음 10년 시계열 |
169
+ | **검색·탐색** | `search_statistics` | KOSIS 통계표 키워드 검색 |
170
+ | | `get_statistics_list` | 주제별·기관별 트리 탐색 + 분야별 추천 |
171
+ | | `get_table_info` | 통계표 메타데이터(분류·항목·주기) |
172
+ | **정밀 데이터** | `get_statistics_data` | 특정 통계표 데이터 조회 (지역명·항목명 자동 매칭) |
173
+ | | `compare_statistics` | 시점별·항목별 정밀 비교 |
174
+ | | `analyze_time_series` | 상세 시계열 (CAGR·표준편차·추세선) |
175
+ | **파일 통계표** | `fetch_kosis_excel` | KOSIS 파일통계표(`.xlsx`) 다운로드·파싱 — 자치구 통계연보 등 OpenAPI 미지원 표 커버 |
176
+
177
+ ---
178
+
179
+ ## 설치 (3가지 방법)
180
+
181
+ ### 방법 1 — Claude.ai 웹 커넥터 (설치 없음) ⭐ 가장 쉬움
182
+
183
+ Claude Pro/Max/Team/Enterprise 요금제에서 동작합니다.
184
+
185
+ 1. [claude.ai](https://claude.ai) 로그인 → 좌측 본인 이름 → **설정** → **커넥터**
186
+ 2. **커스텀 커넥터 추가**
187
+ 3. 입력 — 이름: `korean-stats` / URL: `https://korean-stats-mcp.fly.dev/mcp`
188
+ 4. **추가** → 추가된 커넥터 **구성** → 모든 도구를 **"항상 사용"**으로
189
+ 5. 채팅창에 `"광진구 고용률 알려줘"` 처럼 한국어로 질문하면 끝
190
+
191
+ ### 방법 2 — AI 데스크톱 앱 (설치 없음)
192
+
193
+ Claude Desktop / Cursor / Windsurf에 원격 MCP 서버를 등록합니다.
194
+
195
+ #### 원클릭 자동 설치 ⭐
102
196
 
103
- ### 방법 1: Claude.ai 커넥터 (설치 없이 바로) 가장 쉬움
197
+ 설치 스크립트가 클라이언트 설정 파일을 자동으로 찾아 `korean-stats` 항목을 등록합니다. 기존 설정은 백업(`*.bak.*`) 보존되고, 다른 MCP 서버 항목은 그대로 둡니다.
104
198
 
105
- Claude Pro/Max/Team/Enterprise 요금제에서 동작.
199
+ **macOS / Linux** (`jq` 또는 `python3` 필요)
106
200
 
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. 채팅창에 `"한국 출산율 추세 보여줘"` 같이 자연어로 질문하면 끝
201
+ ```bash
202
+ curl -fsSL https://raw.githubusercontent.com/chrisryugj/korean-stats-mcp/main/install.sh | bash
203
+ ```
204
+
205
+ **Windows (PowerShell)**
206
+
207
+ ```powershell
208
+ irm https://raw.githubusercontent.com/chrisryugj/korean-stats-mcp/main/install.ps1 | iex
209
+ ```
114
210
 
115
- ### 방법 2: AI 데스크톱 (설치 없음)
211
+ 기본값은 클라이언트 모두 등록(`all`)입니다. 특정 클라이언트만 설치하려면 `--client`(`claude`·`cursor`·`windsurf`·`all`) 옵션을 씁니다.
212
+
213
+ ```bash
214
+ # macOS / Linux — Cursor만
215
+ curl -fsSL https://raw.githubusercontent.com/chrisryugj/korean-stats-mcp/main/install.sh | bash -s -- --client cursor
216
+ ```
217
+
218
+ ```powershell
219
+ # Windows — Cursor만
220
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/chrisryugj/korean-stats-mcp/main/install.ps1))) -Client cursor
221
+ ```
116
222
 
117
- Claude Desktop / Cursor / Windsurf 설정 파일에 추가.
223
+ 스크립트는 등록 원격 서버 헬스 체크를 수행합니다. 설치 후 해당 앱을 재시작하세요.
118
224
 
119
- **설정 파일 위치:**
225
+ #### 수동 등록
120
226
 
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` |
227
+ 설정 파일을 직접 편집해도 됩니다.
126
228
 
127
- **설정 내용:**
229
+ | 앱 | 설정 파일 위치 |
230
+ |----|---------------|
231
+ | Claude Desktop | Windows `%APPDATA%\Claude\claude_desktop_config.json` · macOS `~/Library/Application Support/Claude/claude_desktop_config.json` |
232
+ | Cursor | 프로젝트 `.cursor/mcp.json` |
233
+ | Windsurf | 프로젝트 `.windsurf/mcp.json` |
128
234
 
129
235
  ```json
130
236
  {
@@ -137,11 +243,11 @@ Claude Desktop / Cursor / Windsurf 설정 파일에 추가.
137
243
  }
138
244
  ```
139
245
 
140
- 저장 후 재시작.
246
+ 저장 후 앱을 재시작합니다.
141
247
 
142
- ### 방법 3: 로컬 설치 (오프라인 가능)
248
+ ### 방법 3 로컬 설치 (오프라인 가능)
143
249
 
144
- **사전 준비:** [Node.js](https://nodejs.org) 20 이상 · [KOSIS OpenAPI 키](https://kosis.kr/openapi/) (무료 발급).
250
+ **준비물**: [Node.js](https://nodejs.org) 20 이상 · [KOSIS OpenAPI 키](https://kosis.kr/openapi/) (무료 발급)
145
251
 
146
252
  ```bash
147
253
  git clone https://github.com/chrisryugj/korean-stats-mcp.git
@@ -150,169 +256,94 @@ pnpm install
150
256
  pnpm run build
151
257
  ```
152
258
 
153
- AI 앱 설정 (`KOSIS_API_KEY`에 발급받은 입력):
259
+ AI 앱 설정에 발급받은 키를 넣습니다.
154
260
 
155
261
  ```json
156
262
  {
157
263
  "mcpServers": {
158
264
  "korean-stats": {
159
265
  "command": "node",
160
- "args": ["/absolute/path/korean-stats-mcp/dist/index.js"],
266
+ "args": ["/절대경로/korean-stats-mcp/dist/index.js"],
161
267
  "env": { "KOSIS_API_KEY": "발급받은_키" }
162
268
  }
163
269
  }
164
270
  }
165
271
  ```
166
272
 
167
- **자동 설치 스크립트:**
168
-
169
- ```bash
170
- curl -fsSL https://raw.githubusercontent.com/chrisryugj/korean-stats-mcp/main/install.sh | bash
171
- ```
273
+ > 로컬에서 직접 실행할 때는 프로젝트 루트에 `.env` 파일을 만들어 `KOSIS_API_KEY=...`를 넣어도 됩니다. (`.env.example` 참고)
172
274
 
173
275
  ---
174
276
 
175
- ## 도구 구조 (12개)
176
-
177
- | 구분 | 도구 | 설명 |
178
- |------|------|------|
179
- | **빠른 자연어** ⭐ | `quick_stats` | 자연어 한 줄 → KOSIS 수치 즉답. 91 키워드 + 100+ 별칭/오타 정규화. |
180
- | | `quick_trend` | 시계열 추세 + 평균 변화율 + 최고/최저점 + 자연어 기간 추출 ("민선 4기" 등). |
181
- | **체인** ⛓ | `chain_region_brief` | 단일 지역 13지표 한장 브리핑. `format='speech'`로 연설용 한 줄. |
182
- | | `chain_compare_regions` | N지역 × M지표 매트릭스 + 자동 순위 (전국 17개 동시 가능). |
183
- | | `chain_policy_indicator` | 7개 정책 영역(저출산·고령화·주거·일자리·치안·보건·경제) 10년 시계열. |
184
- | **검색·탐색** | `search_statistics` | KOSIS 90만+ 통계표 키워드 검색 → orgId/tableId 메타 획득. |
185
- | | `get_statistics_list` | 주제별·기관별 트리 탐색 + 9개 분야 추천 카드(`recommendedTopic` 옵션). |
186
- | | `get_table_info` | 통계표 메타데이터 (분류·항목·주기). 경량 응답. |
187
- | **데이터** | `get_statistics_data` | 특정 통계표 데이터 조회. regionName/itemName 자동 매칭. |
188
- | | `compare_statistics` | 시점별·항목별 정밀 비교. |
189
- | | `analyze_time_series` | 상세 시계열 (CAGR·표준편차·추세선). |
190
- | **특수** | `fetch_kosis_excel` | KOSIS 파일통계표(.xlsx) 다운로드 + 파싱 ([kordoc](https://github.com/chrisryugj/kordoc) 엔진). **자치구 기본통계** 등 OpenAPI 미지원 표 커버. |
191
-
192
- ---
193
-
194
- ## 지원 키워드 (91개 정식 + 100+ 자연어 별칭)
195
-
196
- ### 인구·출산·사망·고령화
197
- 인구, 총인구, 출산율, 합계출산율, 출생아수, 조출생률, 사망자수, 조사망률, 사망률, 자연증가(율), 기대수명, 평균수명, 고령인구, 노인인구, 65세이상인구, 노령화지수, 고령화지수
198
-
199
- ### 혼인·이혼
200
- 혼인건수, 혼인율, 조혼인율, 이혼건수, 이혼율, 조이혼율, 초혼연령, 평균초혼연령, 남성·여성초혼연령
201
-
202
- ### 고용·소득
203
- 실업률, 고용률, 취업자수, 실업자수, 경제활동인구, 비경제활동인구, 임금, 월평균임금, 월급, 평균임금
204
-
205
- ### 경제
206
- GDP, 국내총생산, 경제성장률, GDP성장률, 물가, 소비자물가, 소비자물가지수, GRDP, 지역내총생산
277
+ ## 정확성과 신뢰
207
278
 
208
- ### 무역
209
- 수출, 수출액, 수입, 수입액, 무역수지
210
-
211
- ### 주거
212
- 주택가격, 주택매매가격, 아파트가격, 아파트매매가격, 전세가격, 주택전세, 전세, 아파트전세
213
-
214
- ### 환경·교통·사회
215
- 미세먼지(PM2.5), PM10, 대기오염, 초미세먼지, 자동차, 자동차등록, 교통사고, 사고건수, 범죄, 범죄율, 범죄발생, 의사, 의사수, 의료인력, 외래관광객, 입국자, 관광객
216
-
217
- ### 자연어 별칭 (v1.4 신규)
218
- 출산·출생·노인·청년실업·연봉·집값·아파트값·전셋값·의료진·차량·관광객수 등 + 영문 (`population`, `fertility`, `aging`, `inflation`, `gdp` 등) + 률/율 오타 (`출산률`, `고용율`, `실엄률`, `이혼률` 등).
279
+ - **공식 출처** — 모든 수치는 국가데이터처 KOSIS OpenAPI를 실시간 조회합니다. 응답에 통계표 ID가 표기되어 그대로 인용·검증할 수 있습니다.
280
+ - **추계 데이터 구분** — 장래추계가 포함된 통계는 "추계" 안내가 자동으로 붙습니다.
281
+ - **자치구 데이터 무결성** — 자치구 단위 데이터가 KOSIS에 없으면 임의로 광역시도 값을 자치구 값인 척 답하지 않고, "광역시도 데이터로 대체했다"고 명시합니다.
282
+ - **캐시** — 동일 질의는 6시간 캐싱하여 빠르게 응답하되, 통계 갱신 주기를 해치지 않습니다.
219
283
 
220
284
  ---
221
285
 
222
- ## 지역 라우팅
286
+ ## 원격 엔드포인트
223
287
 
224
- - **17개 광역시도** 서울, 부산, 대구, 인천, 광주, 대전, 울산, 세종, 경기, 강원, 충북, 충남, 전북, 전남, 경북, 경남, 제주 (풀네임·약칭 모두 인식)
225
- - **자치구·시군 230+ 정밀 라우팅** — 자치구 통계연보(`.xlsx`) 또는 KOSIS 자치구 단위 통계표(14종)로 직접 조회. 커버 분야: 인구·출산·고령인구·의사수·아파트/전세가격·고용률·취업자·실업률·사망자수·사망률·혼인·이혼
226
- - **fallback** — 매핑이 없거나 KOSIS가 자치구 데이터를 미수록한 경우에만 소속 광역시도로 대체 + 안내
227
- - **동명 자치구 disambiguate** — `중구`, `남구`, `동구` 등은 광역시 컨텍스트가 같이 있으면 정확히 매칭
288
+ - 엔드포인트: `https://korean-stats-mcp.fly.dev/mcp` (14개 도구 전체 동작)
289
+ - 헬스체크: `https://korean-stats-mcp.fly.dev/health`
228
290
 
229
291
  ---
230
292
 
231
293
  ## 변경 이력
232
294
 
233
295
  <details>
234
- <summary>v1.6 — 자치구 고용·인구동태 정밀 라우팅 확장</summary>
296
+ <summary>v1.7 — 자치구 데이터 소스 우선순위 재정립 + HTTP 서버 안정화</summary>
235
297
 
236
- **자치구 단위 OpenAPI 라우팅 14분야로 확장**
237
- - 고용 `DT_1ES3A03_A01S` (고용률·취업자, objL2 연령 코드)
238
- - 실업`DT_1ES3A01S` (실업률·실업자·경제활동인구)
239
- - 인구동태`INH_1B82A01`(사망자수) · `INH_1B80A18`(사망률) · `INH_1B83A35`(혼인건수) · `INH_1B85033`(이혼건수) · `INH_1B8000I_01`(조이혼율) · `INH_1B8000I_02`(조혼인율)
240
- - `getDistrictKscdCodeFor` UP_ITM_ID 없는 메타(고용 통계표) 대응: "서울 광진구" 결합형 / "수원시" 단일형 직접 인덱스 + 동명 시군(고성군) ambiguous 처리
241
- - `DistrictOpenApiRoute` — `objL2`(보조 분류) · `districtObjLevel`/`extraObjL1`(자치구 코드 objLevel swap) 옵션 추가
242
- - 통계연보(`.xlsx`) value 추출 실패 시 OpenAPI 라우팅으로 fall-through
243
- - KOSIS 자치구 데이터 미수록(`-`) 시 광역 fallback로 degrade
244
- - 시뮬레이션 108 케이스 100% 통과 (전국 자치구 정밀값)
298
+ - 자치구 조회 우선순위 전환 — KOSIS **표준 OpenAPI(자치구 코드 라우팅)를 1순위**로, 통계연보(`.xlsx`)는 표준표에 없는 분야의 보조 경로로. 표준표는 전국 226시군구가 동일 구조라 일관성·다지역 비교가능성이 보장됨
299
+ - 통계연보 `.xlsx`의 `file_sn`을 분야명 매칭으로 **자치구별 동적 도출** — 자치구마다 다른 통계연보 분야 순서 때문에 엉뚱한 분야 파일을 읽던 문제 차단
300
+ - 자치구 데이터 미수록 시 광역값을 자치구 값인 척 답하지 않도록 **응답 격하 강화** "○○구 단위 미수록, 참고로 상위 지역 □□는 X" 형태로 첫 문장부터 명시
301
+ - `chain_compare_regions` **소스 혼합 감지** 같은 지표가 지역별로 다른 KOSIS 통계표에서 조회되면 비교가능성 경고 자동 부착
302
+ - HTTP 서버 메모리 누수 차단 (v1.7.1) rate-limit IP 버킷 주기적 정리, 요청 생성되는 MCP Server 인스턴스 명시적 종료, SIGTERM graceful shutdown (korean-law-mcp 안정화 패턴 적용)
245
303
 
246
304
  </details>
247
305
 
248
306
  <details>
249
- <summary>v1.4자연어 정규화 + 체인 도구 + 통폐합</summary>
250
-
251
- **자연어 약어/오타/공백 정규화 (법령 MCP의 `LAW_ALIAS_ENTRIES` 패턴 차용)**
252
- - `KEYWORD_ALIASES` 100+ 별칭으로 확장 (출생·노인·연봉·집값·청년실업·영문 별칭 등)
253
- - `BASIC_TYPO_MAP` 신설 — 률/율 받침 오타 자동 교정 (`출산률→출산율`, `고용율→고용률`)
254
- - `normalizeKeywordKey` — 공백·대소문자·중점/하이픈 정규화 후 매칭
255
- - `extractKeyword` 단일 정규화 매칭으로 재작성. "G D P", "65세 이상", "경기 노인 인구" 등 자동 인식
256
-
257
- **체인 도구 3종**
258
- - `chain_region_brief` — 13지표 한장 브리핑, `format='speech'` 옵션 추가
259
- - `chain_compare_regions` — N지역×M지표 매트릭스, **전국 17개 동시 비교** (max 10→17)
260
- - `chain_policy_indicator` — 7개 정책 영역 10년 시계열
261
-
262
- **P0 fixes**
263
- - 자치구 region 파라미터 fallback 미동작 버그 — `quickStats`에서 `input.region`이 자치구일 때 광역시도 변환 분기를 skip하던 가드 제거
264
- - `chain_region_brief.fallbackNote` — 자치구→광역시도 변환 노트 우선 노출
265
- - 노령화지수 등 장래추계 데이터 — `isProjection: true` 메타 + "추계" 명시 안내
266
-
267
- **자연어 기간 추출**
268
- - `quick_trend` 키워드에서 "지난 N년", "민선 N기", "임기 N년차", "작년 대비", "역대" 자동 → `yearCount`
307
+ <summary>v1.6자치구 고용·인구동태 정밀 라우팅 확장</summary>
269
308
 
270
- **통폐합**
271
- - 도구 13개 **12개**. `get_recommended_statistics`를 `get_statistics_list`의 `recommendedTopic` 옵션으로 흡수
309
+ - 자치구 단위 OpenAPI 라우팅을 14개 분야로 확장 — 고용(`DT_1ES3A03_A01S`)·실업(`DT_1ES3A01S`)·인구동태(`INH_*` 사망·혼인·이혼)
310
+ - 고용·실업 통계표의 반기(`prdSe='S'`) 주기를 응답의 `PRD_SE` 필드 기준으로 라벨링 — "2025년 하반기"처럼 정확 표기
311
+ - `getDistrictKscdCodeFor` — `UP_ITM_ID` 없는 메타 대응("서울 광진구" 결합형 / "수원시" 단일형), 동명 시군 ambiguous 처리
312
+ - 자치구 통계연보(`.xlsx`) value 추출 실패 시 OpenAPI 라우팅으로 자동 fall-through
313
+ - 배포를 Fly.io 컨테이너로 전환 — 자치구 `.xlsx` 파싱(kordoc) 엔진 포함
272
314
 
273
315
  </details>
274
316
 
275
317
  <details>
276
- <summary>v1.3P0 자치구 라우팅 일소 + 체인 도구 도입</summary>
318
+ <summary>v1.4자연어 정규화 + 체인 도구</summary>
277
319
 
278
- - `DISTRICT_TO_PROVINCE` 33 200+ (경기·강원·충북·충남·전북·전남·경북·경남 전체 시군 + 부산 영도·동래·인천 남동 등)
279
- - `AMBIGUOUS_DISTRICTS` + 광역시도 컨텍스트로 "광주 동구" / "부산 강서구" 정확 매칭
280
- - `extractDistrictName` 광역시 약칭 가드 — "대구" 같은 광역시 약칭이 자치구로 오인되는 버그 fix
281
- - 체인 도구 3종 신설 (region_brief, compare_regions, policy_indicator)
320
+ - 약어·오타·공백 변형 자동 정규화 (`KEYWORD_ALIASES` 100개 이상, 률/율 오타 교정)
321
+ - 체인 도구 3종 `chain_region_brief`(연설용 모드 포함)·`chain_compare_regions`(전국 17개 동시)·`chain_policy_indicator`
322
+ - `quick_trend` 자연어 기간 추출 — "민선 N기", "임기 N년차", "작년 대비", "역대"
323
+ - 도구 13개 12개 통폐합
282
324
 
283
325
  </details>
284
326
 
285
327
  <details>
286
- <summary>v1.2 — 자치구 라우팅 + 부분매칭 버그 픽스</summary>
328
+ <summary>v1.2 ~ v1.3 — 자치구 라우팅 도입</summary>
287
329
 
288
- - `quick_trend` keyword 자연어 처리 (extract* 헬퍼 공유)
289
- - `extractProvinceName` 단어 경계 매칭으로 "해운대구"의 "대구" 부분매칭 버그 차단
290
- - 자치구 광역시도 fallback + 자치구 단위 정밀 조회 경로(`fetch_kosis_excel`) 안내
330
+ - `DISTRICT_TO_PROVINCE` 자치구·시군 매핑 200개 이상으로 확장
331
+ - 동명 자치구를 광역시도 컨텍스트로 구분 (`AMBIGUOUS_DISTRICTS`)
332
+ - "해운대구"의 "대구" 부분매칭 부분매칭 버그 차단
333
+ - 자치구 정밀 조회 경로(`fetch_kosis_excel`) 도입
291
334
 
292
335
  </details>
293
336
 
294
337
  ---
295
338
 
296
- ## 주요 특징
297
-
298
- - **91개 키워드 + 100+ 자연어 별칭** — 줄임말·률/율 오타·공백 변형 자동 정규화
299
- - **17개 시도 + 자치구·시군 230+ 정밀 라우팅** — 자치구 통계연보(`.xlsx`) 또는 KOSIS 자치구 단위 통계표(14종)로 직접 조회, 미수록 시에만 광역 fallback
300
- - **체인 도구 3종** — 단일 지역 13지표 한장 브리핑, N지역×M지표 매트릭스(전국 17개 동시), 7개 정책 영역 시계열
301
- - **자연어 기간 추출** — "민선 4기", "임기 4년차", "작년 대비", "역대" 자동 환산
302
- - **장래추계 안내** — 노령화지수 등 추계 데이터는 `isProjection: true` + "추계" 명시 안내
303
- - **파일통계표 파싱** — KOSIS OpenAPI 미지원 표(.xlsx)는 [kordoc](https://github.com/chrisryugj/kordoc) 엔진으로 다운로드·파싱·Markdown 변환
304
- - **캐시** — LRU 기반, 통계 데이터 6시간 TTL
305
- - **원격 엔드포인트** — 설치 없이 `https://korean-stats-mcp.fly.dev/mcp`로 바로 사용
306
-
307
- ---
308
-
309
- ## 원격 엔드포인트
339
+ ## 라이선스
310
340
 
311
- - **`https://korean-stats-mcp.fly.dev/mcp`** — Fly.io Singapore 리전, stateless HTTP, 12개 도구 전체 동작
312
- - 헬스체크: `https://korean-stats-mcp.fly.dev/health`
341
+ [MIT](./LICENSE)
313
342
 
314
343
  ---
315
344
 
316
- ## 라이선스
345
+ ## 참고한 프로젝트
317
346
 
318
- [MIT](./LICENSE)
347
+ - **[Dayoooun/korea-stats-mcp](https://github.com/Dayoooun/korea-stats-mcp)** — 이 프로젝트의 포크 시작점. 원본에 깊은 감사를 표합니다. 라이선스는 원본과 동일한 MIT.
348
+ - **[kordoc](https://github.com/chrisryugj/kordoc)** — KOSIS 파일통계표(`.xlsx`)를 다운로드·파싱하는 엔진. `fetch_kosis_excel` 도구가 이 엔진을 사용합니다.
349
+ - **[korean-law-mcp](https://github.com/chrisryugj/korean-law-mcp)** — HTTP 서버 안정화 패턴(rate-limit 버킷 정리, MCP 인스턴스 명시적 종료, SIGTERM graceful shutdown)을 v1.7.1에 적용했습니다.
@@ -17,7 +17,7 @@ export declare class KosisClient {
17
17
  /**
18
18
  * API 요청 실행 (timeout 15s + 3회 재시도 + 지수 백오프)
19
19
  *
20
- * - Fly Singapore → KOSIS Korea cold path 일시 abort 대응
20
+ * - Fly 해외 리전(nrt 등) → KOSIS Korea cold path 일시 abort 대응
21
21
  * - KOSIS 응답 에러(err/errMsg 필드)는 영구 실패 → 즉시 throw, retry 안 함
22
22
  * - HTTP 4xx도 영구 실패 → 즉시 throw
23
23
  * - 네트워크 오류·타임아웃·5xx만 retry (800ms / 1600ms 백오프)
@@ -54,7 +54,10 @@ export declare class KosisClient {
54
54
  resultCount?: number;
55
55
  }): Promise<SearchResultItem[]>;
56
56
  /**
57
- * 통계설명 조회
57
+ * 통계설명 조회 (statisticsExplData.do)
58
+ *
59
+ * 응답은 camelCase 단일 객체(statsNm, writingPurps, examinPd, mainTermExpl 등) —
60
+ * request()가 단일 객체를 [obj]로 감싸 반환한다. metaItm=All 필수.
58
61
  */
59
62
  getStatisticsExplain(orgId: string, tblId: string): Promise<Record<string, string>[]>;
60
63
  /**
@@ -1 +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;;;;;;;OAOG;YACW,OAAO;IAsFrB;;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"}
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;;;;;;;OAOG;YACW,OAAO;IA0FrB;;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;;;;;OAKG;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"}
@@ -25,7 +25,7 @@ export class KosisClient {
25
25
  /**
26
26
  * API 요청 실행 (timeout 15s + 3회 재시도 + 지수 백오프)
27
27
  *
28
- * - Fly Singapore → KOSIS Korea cold path 일시 abort 대응
28
+ * - Fly 해외 리전(nrt 등) → KOSIS Korea cold path 일시 abort 대응
29
29
  * - KOSIS 응답 에러(err/errMsg 필드)는 영구 실패 → 즉시 throw, retry 안 함
30
30
  * - HTTP 4xx도 영구 실패 → 즉시 throw
31
31
  * - 네트워크 오류·타임아웃·5xx만 retry (800ms / 1600ms 백오프)
@@ -67,6 +67,10 @@ export class KosisClient {
67
67
  if (data.result && Array.isArray(data.result)) {
68
68
  return data.result;
69
69
  }
70
+ // 단일 객체 응답 (statisticsExplData.do 등) — [obj]로 정규화
71
+ if (data && typeof data === 'object' && Object.keys(data).length > 0) {
72
+ return [data];
73
+ }
70
74
  return [];
71
75
  }
72
76
  return data;
@@ -125,14 +129,17 @@ export class KosisClient {
125
129
  });
126
130
  }
127
131
  /**
128
- * 통계설명 조회
132
+ * 통계설명 조회 (statisticsExplData.do)
133
+ *
134
+ * 응답은 camelCase 단일 객체(statsNm, writingPurps, examinPd, mainTermExpl 등) —
135
+ * request()가 단일 객체를 [obj]로 감싸 반환한다. metaItm=All 필수.
129
136
  */
130
137
  async getStatisticsExplain(orgId, tblId) {
131
138
  return this.request(config.kosis.endpoints.statsExplain, {
132
- method: 'getMeta',
133
- type: 'TBL',
139
+ method: 'getList',
134
140
  orgId,
135
141
  tblId,
142
+ metaItm: 'All',
136
143
  });
137
144
  }
138
145
  /**