ECOS MCP Server
# ๐ฆ ECOS MCP Server
ํ๊ตญ์ํ ๊ฒฝ์ ํต๊ณ์์คํ
(ECOS) Open API๋ฅผ ์ํ ์ต์ MCP(Model Context Protocol) ์๋ฒ์
๋๋ค.
AI ์์ด์ ํธ(Claude Desktop, Cursor ๋ฑ)๊ฐ ํ๊ตญ ๊ฑฐ์๊ฒฝ์ ํต๊ณ ๋ฐ์ดํฐ๋ฅผ ์์ฐ์ด๋ก ์ค์๊ฐ ๊ฒ์ํ๊ณ ๊ณ ํจ์จ ์๊ณ์ด ๋ถ์์ ์ํํ ์ ์๊ฒ ํด์ค๋๋ค.
---
## โจ ํต์ฌ ๊ธฐ๋ฅ
### ๐ ๏ธ MCP Tools (7๊ฐ)
๋ชจ๋ ๋๊ตฌ๋ ์ฝ๊ธฐ ์ ์ฉ(`readOnlyHint`)์ผ๋ก ํ์๋์ด ์๊ณ , ์คํจ ์ MCP ํ์ค ์๋ฌ(`isError: true`)๋ฅผ ๋ฐํํฉ๋๋ค.
| Tool | ์ค๋ช
| ์ฃผ์ ํน์ง |
|------|------|-----------|
| `get_popular_statistic` | **1-Shot ์ธ๊ธฐ ์งํ ์ฆ์ ์กฐํ** | ๊ธฐ์ค๊ธ๋ฆฌ, ์ฑ์ฅ๋ฅ , ๋ฌผ๊ฐ์์น๋ฅ , ํ์จ ๋ฑ์ ์ฝ๋ ๊ฒ์ ์์ด ํ ๋ฒ์ ํธ์ถ๋ก ์กฐํ |
| `search_statistics` | **ํต๊ณ ์๊ณ์ด ๋ฐ์ดํฐ ์กฐํ** (ํต์ฌ) | ์ค๋งํธ ๋ ์ง, ์ต์ ๊ตฌ๊ฐ ์ฐ์ , ์ฆ๊ฐ๋ฅ ๊ณ์ฐ(`transform`), ์ปดํฉํธ/CSV ํฌ๋งท |
| `search_statistic_tables` | **ํต๊ณํ ๊ฒ์ยท๊ณ์ธต ํ์** | ๋ก์ปฌ ์ธ๋ฑ์ค๋ก ์ฆ์ ์๋ต. ๋์ด์ฐ๊ธฐ ๋ฌด์ยท๋ค์ค ๋จ์ดยท๊ด๋ จ๋ ์ ์ ๋ ฌ, `parent_code`๋ก ๋ถ๋ฅ ํธ๋ฆฌ ํ์ |
| `get_key_statistics` | 100๋ ์ฃผ์ ๊ฒฝ์ ์งํ ์กฐํ | GDP, ๊ธฐ์ค๊ธ๋ฆฌ, ํ์จ, ํตํ๋ ๋ฑ ์ค์๊ฐ ํต์ฌ ์งํ |
| `search_statistic_word` | ํต๊ณ ์ฉ์ด ์ฌ์ ๊ฒ์ | ํ๊ตญ์ํ ๊ณต์ ์ฉ์ด ํด์ค |
| `list_statistic_items` | ํต๊ณํ ์ธ๋ถํญ๋ชฉ ๋ชฉ๋ก ์กฐํ | ํญ๋ชฉ์ฝ๋, ์ง์ ์ฃผ๊ธฐ, ์๋ก ๊ธฐ๊ฐ, ๋จ์ ํ์ธ (๊ฒฐ๊ณผ ์บ์) |
| `get_statistic_meta` | ํต๊ณ ๋ฉํ๋ฐ์ดํฐ ์กฐํ | ํต๊ณ ์์ฑ ๋ฐฐ๊ฒฝ, ์์ฑ ์ฃผ๊ธฐ, ํธ์ ๊ธฐ์ค ๋ฑ (๊ฒฐ๊ณผ ์บ์) |
### โก ํ ํฐ ์ต์ ํ ํฌ๋งท (`output_format`)
์๊ณ์ด ์กฐํ(`search_statistics`, `get_popular_statistic`) ๊ฒฐ๊ณผ๋ ๊ณต๋ฐฑ ์๋ JSON์ผ๋ก ๋ฐํ๋ฉ๋๋ค.
- **`"compact"`** (๊ธฐ๋ณธ๊ฐ): ๊ณ์ด(ํญ๋ชฉ)๋ณ๋ก ์ด๋ฆยท๋จ์๋ฅผ ํ ๋ฒ๋ง ์ฐ๊ณ ๊ฐ์ `[์์ , ๊ฐ]` ๋ฐฐ์ด๋ก ๋ฐํ
- **`"csv"`**: ํ ์ค์ ๊ด์ธก์น ํ๋. ์ฌ๋ฌ ํญ๋ชฉ์ ํยท์ฐจํธ๋ก ์ฎ๊ธธ ๋ ํธ๋ฆฌ
- **`"json"`**: ECOS ์๋ณธ ํ ๊ทธ๋๋ก
์ธก์ ์์(์๋น์๋ฌผ๊ฐ์ง์ 24๊ฐ์ ๋จ์ผ ๊ณ์ด, ๋ฌธ์ ์ ๊ธฐ์ค): ์๋ณธ JSON 6,545์ โ compact 605์(์ฝ 91% ์ถ์), csv 805์.
### ๐ ์ฆ๊ฐ๋ฅ ยท๋ณ๊ฒฝ ์์ (`transform`, `changes_only`)
- `transform="yoy"`: ์ ๋
๋๊ธฐ๋๋น ์ฆ๊ฐ๋ฅ (%) ์ด(`yoy_pct`) ์ถ๊ฐ. ๊ธฐ์ค ์์ ๋ฐ์ดํฐ๋ ์๋์ผ๋ก ํจ๊ป ์กฐํํฉ๋๋ค.
- `transform="pop"`: ์ง์ ๊ด์ธก์น ๋๋น ์ฆ๊ฐ๋ฅ (%) ์ด(`pop_pct`) ์ถ๊ฐ
- `changes_only=True`: ๊ฐ์ด ๋ฐ๋ ์์ ๋ง ๋ฐํ (์: ์ผ๋ณ ๊ธฐ์ค๊ธ๋ฆฌ 2๋
์น ์ฝ 500ํ โ ๋ณ๊ฒฝ ์์ ๋ช ํ)
### ๐๏ธ ์ค๋งํธ ๋ ์ง & ์ต์ ๊ตฌ๊ฐ ์ฐ์
- `start_date`/`end_date`๋ฅผ ์๋ตํ๋ฉด **์ผ๊ฐ(D)์ ์ต๊ทผ 3๊ฐ์, ๊ทธ ์ธ ์ฃผ๊ธฐ๋ ์ต๊ทผ 2๋
**์ด ์๋ ์ค์ ๋ฉ๋๋ค.
- ๊ฒฐ๊ณผ๊ฐ ํ ๋ฒ์ ๋ค ๋ด๊ธฐ์ง ์์ผ๋ฉด(`end_count` ์ด๊ณผ, sample ํค๋ 10๊ฑด) **๊ฐ์ฅ ์ต๊ทผ ๊ตฌ๊ฐ**์ ๋ฐํํ๊ณ `truncated: true`์ ์๋ด ๋ฌธ๊ตฌ๋ฅผ ๋ถ์
๋๋ค. ๊ณผ๊ฑฐ๋ถํฐ ํ์ด์ง ๋จ์๋ก ๋ฐ์ผ๋ ค๋ฉด `prefer_latest=False`๋ฅผ ์ฐ์ธ์.
---
## ๐ MCP Resources & Prompts
### Resources
- `ecos://popular-indicators`: ํ๊ตญ์ํ ์ฃผ์ ํต์ฌ ๊ฒฝ์ ์งํ(๊ธฐ์ค๊ธ๋ฆฌ, ์ค์ง GDP, ์๋น์๋ฌผ๊ฐ์ง์, ํ์จ, M2 ๋ฑ) ํ๋ฆฌ์
๋งคํํ
- `ecos://date-format-guide`: ์ฃผ๊ธฐ(Cycle)๋ณ ์ฌ๋ฐ๋ฅธ ๋ ์ง ํฌ๋งท ๊ท๊ฒฉ ์๋ด์
### Prompts
- `macro-economic-briefing`: 100๋ ์งํ์ ์ฑ์ฅ๋ฅ ยท๋ฌผ๊ฐ์์น๋ฅ ยท๊ธฐ์ค๊ธ๋ฆฌยทํ์จ ์ถ์ด ๊ธฐ๋ฐ ๊ฒฝ์ ํํฉ ๋ธ๋ฆฌํ
- `analyze-economic-trend`: ํน์ ๊ฒฝ์ ์งํ(์๋น์๋ฌผ๊ฐ์ง์ ๋ฑ) ์๊ณ์ด ์ถ์ด ๋ฐ ์ ์ฑ
์์ฌ์ ์ฌ์ธต ๋ถ์
---
## ๐
์ฃผ๊ธฐ(Cycle)๋ณ ๋ ์ง ํฌ๋งท ๊ท์น
| ์ฃผ๊ธฐ ์ฝ๋ | ์ฃผ๊ธฐ๋ช
| ์์/์ข
๋ฃ์ผ ํฌ๋งท ๊ท๊ฒฉ | ์์ |
|:---:|:---:|:---:|:---:|
| **`A`** | ์ฐ๊ฐ | `YYYY` | `"2020"`, `"2024"` |
| **`S`** | ๋ฐ๊ธฐ | `YYYYS1` / `YYYYS2` | `"2023S1"`, `"2023S2"` |
| **`Q`** | ๋ถ๊ธฐ | `YYYYQ1` ~ `YYYYQ4` | `"2023Q1"`, `"2024Q3"` |
| **`M`** | ์๊ฐ | `YYYYMM` | `"202401"`, `"202412"` |
| **`SM`** | ๋ฐ์ | `YYYYMMS1` / `YYYYMMS2` | `"202401S1"`, `"202401S2"` |
| **`D`** | ์ผ๊ฐ | `YYYYMMDD` | `"20240101"`, `"20240315"` |
---
## ๐ ์ฃผ์ ์ธ๊ธฐ ํต๊ณํ ํ๋ฆฌ์
| ์งํ๋ช
| ํค์๋(๋ณ์นญ) | ํต๊ณํ์ฝ๋ | ์ฃผ๊ธฐ | ํญ๋ชฉ์ฝ๋ | ๊ธฐ๋ณธ ์ฒ๋ฆฌ |
|--------|-------------|:---:|:---:|:---:|:---:|
| **ํ๊ตญ์ํ ๊ธฐ์ค๊ธ๋ฆฌ** | `๊ธฐ์ค๊ธ๋ฆฌ`, `๊ธ๋ฆฌ`, `base_rate` | `722Y001` | `D` | `0101000` | ๋ณ๊ฒฝ ์์ ๋ง |
| **๊ฒฝ์ ์ฑ์ฅ๋ฅ (์ค์ง, ์ ๊ธฐ๋น %)** | `์ฑ์ฅ๋ฅ `, `๊ฒฝ์ ์ฑ์ฅ๋ฅ `, `GDP์ฑ์ฅ๋ฅ ` | `200Y102` | `Q` | `10111` | |
| **์ค์ง GDP(๋ถ๊ธฐ, ์ญ์ต์)** | `GDP`, `์ค์งGDP`, `๊ตญ๋ด์ด์์ฐ` | `200Y108` | `Q` | `10601` | |
| **์๋น์๋ฌผ๊ฐ์์น๋ฅ (%)** | `๋ฌผ๊ฐ์์น๋ฅ `, `์ธํ๋ ์ด์
` | `901Y009` | `M` | `0` | `yoy` |
| **์๋น์๋ฌผ๊ฐ์ง์(CPI)** | `CPI`, `์๋น์๋ฌผ๊ฐ`, `๋ฌผ๊ฐ` | `901Y009` | `M` | `0` | |
| **์/๋ฌ๋ฌ ํ์จ(์ผ๋ณ)** | `ํ์จ`, `์๋ฌ๋ฌ`, `๋ฌ๋ฌ`, `USD` | `731Y001` | `D` | `0000001` | |
| **์/๋ฌ๋ฌ ํ์จ(์ํ๊ท )** | `์ํ๊ท ํ์จ`, `usd_krw_monthly` | `731Y004` | `M` | `0000001`/`0000100` | |
| **๋ณธ์ํตํ(ํ์)** | `๋ณธ์ํตํ`, `reserve_money` | `102Y004` | `M` | `ABA1` | |
| **M2 ๊ด์ํตํ** | `M2`, `ํตํ๋`, `๊ด์ํตํ` | `161Y006` | `M` | `BBHA00` | |
| **๊ตญ๊ณ ์ฑ(3๋
) ์์ต๋ฅ (์ผ๋ณ)** | `๊ตญ๊ณ ์ฑ`, `๊ตญ๊ณ ์ฑ3๋
`, `์ฑ๊ถ๊ธ๋ฆฌ` | `817Y002` | `D` | `010200000` | |
| **๊ตญ๊ณ ์ฑ(3๋
) ์์ต๋ฅ (์ํ๊ท )** | `๊ตญ๊ณ ์ฑ์ํ๊ท `, `treasury_3y_monthly` | `721Y001` | `M` | `5020000` | |
| **์์ฐ์๋ฌผ๊ฐ์ง์(PPI)** | `PPI`, `์์ฐ์๋ฌผ๊ฐ` | `404Y014` | `M` | `*AA` | |
`"ํตํ"`, `"์ง์"`์ฒ๋ผ ์ฌ๋ฌ ์งํ์ ๊ฑธ์น๋ ํค์๋๋ ํ๋ณด ๋ชฉ๋ก์ ๋ด์ ์๋ฌ๋ฅผ ๋๋ ค์ฃผ๋ฏ๋ก, ๋ ๊ตฌ์ฒด์ ์ธ ํค์๋๋ `id`๋ฅผ ์ฐ๋ฉด ๋ฉ๋๋ค.
---
## ๐ ๋น ๋ฅธ ์์
### 1. ์ค์น (๋ก์ปฌ ๊ฐ๋ฐ ์)
```bash
git clone https://github.com/kgy0617/ecos_mcp.git
cd ecos_mcp
uv sync
```
### 2. API ํค ์ค์ (์ ํ)
```bash
cp .env.example .env
# .env ํ์ผ์์ ECOS_API_KEY ์
๋ ฅ (๋ฏธ์
๋ ฅ ์ sample ํค ์๋ ์ ์ฉ)
```
> ๐ก API ํค ์์ด๋ `sample` ํค๋ก ํ
์คํธ ๊ฐ๋ฅํ๋ฉฐ, 1ํ ์ต๋ ํ์ฉ์น(10๊ฑด)๋ก ์๋ ํด๋จํ๋ฉ๋๋ค.
### 3. ์๊ฐ ์ง๋จ ํฌ์ค์ฒดํฌ ์คํ
```bash
uv run ecos-mcp --check
```
๋คํธ์ํฌ ์ฐ๊ฒฐ, API ํค ์ํ, ํต๊ณํ ์ธ๋ฑ์ค ๋ก๋๊ฐ ์๋์ผ๋ก ์ง๋จ๋ฉ๋๋ค.
---
## ๐ง MCP ํด๋ผ์ด์ธํธ ์ค์
### Claude Desktop
`~/Library/Application Support/Claude/claude_desktop_config.json`:
#### ๋ฐฉ๋ฒ A: GitHub URL ์ง์ ์คํ (ํด๋ก ๋ถํ์, ์ถ์ฒ โญ)
```json
{
"mcpServers": {
"ecos": {
"command": "uvx",
"args": ["--from", "git+https://github.com/kgy0617/ecos_mcp", "ecos-mcp"],
"env": {
"ECOS_API_KEY": "your_api_key_here"
}
}
}
}
```
#### ๋ฐฉ๋ฒ B: ๋ก์ปฌ ํด๋ก ์คํ
```json
{
"mcpServers": {
"ecos": {
"command": "uv",
"args": ["--directory", "/path/to/ecos_mcp", "run", "ecos-mcp"],
"env": {
"ECOS_API_KEY": "your_api_key_here"
}
}
}
}
```
### Claude Code
```bash
claude mcp add ecos -e ECOS_API_KEY=your_api_key_here -- uvx --from git+https://github.com/kgy0617/ecos_mcp ecos-mcp
```
### Cursor
Settings > Features > MCP Servers > Add New MCP Server:
- **๋ฐฉ๋ฒ A (GitHub ์ง์ ์คํ)**:
- **Name**: `ecos`
- **Type**: `command`
- **Command**: `uvx --from git+https://github.com/kgy0617/ecos_mcp ecos-mcp`
- **๋ฐฉ๋ฒ B (๋ก์ปฌ ํด๋ก )**:
- **Name**: `ecos`
- **Type**: `command`
- **Command**: `uv --directory /path/to/ecos_mcp run ecos-mcp`
---
## ๐ ์ฌ์ฉ ์์
### 1. ์ธ๊ธฐ ์งํ ์์คํฑ ์กฐํ (`get_popular_statistic`)
> **์ฌ์ฉ์**: "์ต๊ทผ ํ๊ตญ ๊ธฐ์ค๊ธ๋ฆฌ ์ด๋ป๊ฒ ๋ฐ๋์์ด?"
**Tool ํธ์ถ**:
```json
{
"indicator": "๊ธฐ์ค๊ธ๋ฆฌ",
"recent_years": 2,
"output_format": "compact"
}
```
**์๋ต ์์** (์ผ๋ณ 500์ฌ ํ ๋์ `changes_only=True`๊ฐ ๊ธฐ๋ณธ ์ ์ฉ๋์ด **๊ธ๋ฆฌ ๋ณ๋ ์์ ๋ง** ๊ฐ๊ฒฐํ๊ฒ ๋ฐํ):
```json
{
"stat_code": "722Y001",
"stat_name": "ํ๊ตญ์ํ ๊ธฐ์ค๊ธ๋ฆฌ ๋ฐ ์ฌ์์ ๊ธ๋ฆฌ",
"indicator": "base_rate",
"total_count": 500,
"count": 3,
"columns": ["time", "value"],
"series": [
{
"item": "ํ๊ตญ์ํ ๊ธฐ์ค๊ธ๋ฆฌ",
"item_code": "0101000",
"unit": "์ฐ%",
"data": [
["20230113", 3.5],
["20241011", 3.25],
["20241128", 3.0]
]
}
]
}
```
---
### 2. ๋ฌผ๊ฐ์์น๋ฅ CSV ์์ ํ ์ฐจํธ ๋ถ์
> **์ฌ์ฉ์**: "์๋น์๋ฌผ๊ฐ ์์น๋ฅ ์ต๊ทผ ๋ฐ์ดํฐ CSV๋ก ๋ฝ์์ ๋ถ์ํด์ค"
**Tool ํธ์ถ**:
```json
{
"indicator": "๋ฌผ๊ฐ์์น๋ฅ ",
"recent_years": 1,
"output_format": "csv"
}
```
**์๋ต ์์** (`transform="yoy"`๊ฐ ์๋ ์ ์ฉ๋์ด ์ ๋
๋๊ธฐ๋๋น ์ฆ๊ฐ๋ฅ ์ด์ธ `YOY_PCT`๊ฐ ํฌํจ๋จ):
```csv
# stat_code: 901Y009
# stat_name: 4.2.1. ์๋น์๋ฌผ๊ฐ์ง์
# indicator: inflation_rate
# total_count: 12
# count: 12
TIME,ITEM_CODE,ITEM,VALUE,UNIT,YOY_PCT
202401,0,์ด์ง์,113.15,2020=100,2.8
202402,0,์ด์ง์,113.77,2020=100,3.1
202403,0,์ด์ง์,113.94,2020=100,3.1
202404,0,์ด์ง์,114.09,2020=100,2.9
202405,0,์ด์ง์,114.14,2020=100,2.7
...
```
---
### 3. ํต๊ณํ ํค์๋ ๊ฒ์ ๋ฐ ๊ณ์ธต ํ์ (`search_statistic_tables`)
> **์ฌ์ฉ์**: "์๋น์๋ฌผ๊ฐ ๊ด๋ จ ํต๊ณํ ์ฐพ์์ค"
**Tool ํธ์ถ**:
```json
{
"keyword": "์๋น์ ๋ฌผ๊ฐ",
"searchable_only": true,
"limit": 3
}
```
**์๋ต ์์** (๋ก์ปฌ ์ธ๋ฑ์ค ๊ธฐ๋ฐ์ผ๋ก ๋์ด์ฐ๊ธฐ ๋ฌด์ ๋ฐ ๊ด๋ จ๋ ์ ์ ๋ ฌ):
```json
{
"query": "์๋น์ ๋ฌผ๊ฐ",
"total_matches": 3,
"count": 2,
"searchable_only": true,
"index_generated_at": "2026-09-26",
"rows": [
{
"P_STAT_CODE": "0000000211",
"STAT_CODE": "901Y009",
"STAT_NAME": "4.2.1. ์๋น์๋ฌผ๊ฐ์ง์",
"CYCLE": "M",
"SRCH_YN": "Y",
"ORG_NAME": "๊ตญ๊ฐ๋ฐ์ดํฐ์ฒ(02-2012-9114)"
},
{
"P_STAT_CODE": "0000000211",
"STAT_CODE": "901Y010",
"STAT_NAME": "4.2.2. ์๋น์๋ฌผ๊ฐ์ง์(ํน์๋ถ๋ฅ)",
"CYCLE": "M",
"SRCH_YN": "Y",
"ORG_NAME": "๊ตญ๊ฐ๋ฐ์ดํฐ์ฒ(02-2012-9114)"
}
]
}
```
*Tip*: `parent_code="0000000211"`๋ฅผ ์ง์ ํ๋ฉด ํด๋น ๋ถ๋ฅ์ ํ์ ํต๊ณํ ํธ๋ฆฌ๋ฅผ ์ง์ ํ์ํ ์๋ ์์ต๋๋ค.
---
### 4. ํต๊ณ ์ฉ์ด ์ฌ์ ๊ฒ์ (`search_statistic_word`)
> **์ฌ์ฉ์**: "ํ๊ตญ์ํ์์ ์ ์ํ๋ ๊ธฐ์ค๊ธ๋ฆฌ์ ์ ํํ ์๋ฏธ๊ฐ ๋ญ์ผ?"
**Tool ํธ์ถ**:
```json
{
"word": "๊ธฐ์ค๊ธ๋ฆฌ"
}
```
**์๋ต ์์**:
```json
{
"total_count": 1,
"count": 1,
"rows": [
{
"WORD": "๊ธฐ์ค๊ธ๋ฆฌ",
"CONTENT": "ํ๊ตญ์ํ์ด ๊ธ์ต๊ธฐ๊ด๊ณผ ํ๋งค์กฐ๊ฑด๋ถ์ฆ๊ถ(RP) ๋งค๋งค, ์๊ธ์กฐ์ ์๊ธ ๋ฐ ๋์ถ ๋ฑ์ ๊ฑฐ๋๋ฅผ ํ ๋ ๊ธฐ์ค์ด ๋๋ ์ ์ฑ
๊ธ๋ฆฌ"
}
]
}
```
---
## ๐งช ํ
์คํธ ์คํ
```bash
uv run pytest # ์คํ๋ผ์ธ ๋จ์ ํ
์คํธ (ECOS API๋ฅผ ๋ชจํน, ๋คํธ์ํฌ ๋ถํ์)
uv run pytest -m live # ์ค์ ECOS API ํธ์ถ ํ
์คํธ (๋ชจ๋ ํ๋ฆฌ์
์กฐํ ํ์ธ)
```
## ๐ ๋ผ์ด์ ์ค
MIT License
TDQS
Scored across 7 tools
get_popular_statistic, get_key_statistics, and search_statistics all return economic indicator data, so an agent must infer which mode fits the query. The descriptions clarify code-free keyword lookup versus generic code-based queries versus a fixed 100-indicator list, but 'popular' and 'key' remain semantically close.
Names are grouped by action (get_, search_, list_) and remain readable, but the set mixes singular and plural forms ('statistic' vs 'statistics') and uses different object patterns like get_popular_statistic versus get_key_statistics. The naming is not chaotic, but it is not fully consistent.
Seven tools is a well-scoped size for an economic-statistics server. Each tool serves a distinct stage of the workflow: quick lookup, generic retrieval, table discovery, item discovery, metadata, and dictionary lookup.
The tool surface covers the main ECOS workflows end to end: find a statistical table, inspect its items, retrieve time series, fetch metadata, look up terms, and access popular or major indicators. There are no obvious dead ends or missing core operations for the stated domain.