Skip to main content
Glama
namjiman

ks-local-mcp

by namjiman
README.md
# ks-local-mcp

승정원일기·조선왕조실록 로컬 PostgreSQL MCP 서버.

로컬 PostgreSQL DB에 직접 접속해 189만 건 승정원일기·38만 건 실록을 Claude Desktop에서 검색·조회한다.

## 전제 조건

- macOS 또는 Linux
- PostgreSQL 18이 로컬에 실행 중
- `sjw` DB: 승정원일기 (국편 XML 적재 완료)
- `sillok` DB: 조선왕조실록 (국편 XML 적재 완료)
- [Claude Desktop](https://claude.ai/download) 설치

## 설치

```bash
curl -LsSf https://raw.githubusercontent.com/namjiman/ks-local-mcp/main/install.sh | bash
```

설치 중 PostgreSQL 접속 URL과 비밀번호를 입력한다. 입력하지 않으면 기본값(`postgresql://postgres@127.0.0.1:5432/sjw`)을 사용한다.

설치 후 Claude Desktop을 재시작하면 도구 15개가 활성화된다.

### 수동 설치

`~/Library/Application Support/Claude/claude_desktop_config.json`에 추가:

```json
{
  "mcpServers": {
    "ks_local_mcp": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/namjiman/ks-local-mcp", "ks-local-mcp"],
      "env": {
        "SJW_DATABASE_URL": "postgresql://postgres:비밀번호@127.0.0.1:5432/sjw",
        "SILLOK_DATABASE_URL": "postgresql://postgres:비밀번호@127.0.0.1:5432/sillok"
      }
    }
  }
}
```

## 도구 목록 (15개)

### 공통

| 도구 | 설명 |
|---|---|
| `list_sources` | 사용 가능한 DB 목록과 개요 |
| `db_status` | 두 DB의 실시간 건수·날짜 범위·색인 수 |

### 승정원일기 (sjw · 1623–1910 · 189만 건)

| 도구 | 설명 | 주요 파라미터 |
|---|---|---|
| `sjw_search` | 본문 키워드 검색 | keyword, limit, offset, entry_type, and_terms, regex, normalize, with_snippet |
| `sjw_count` | 건수만 반환 — 빈도 조사용 | keyword, field, normalize |
| `sjw_count_by_period` | 시기별 빈도 집계 | keyword, by(reign/decade/year) |
| `sjw_index_search` | 색인(이름·지명·서명) 검색 | value, index_type, limit, offset, exact |
| `sjw_date_search` | 날짜 범위 검색 | date_from, date_to, keyword, offset, with_snippet |
| `sjw_get_entry` | 기사/좌목 전문 조회 | entry_id, include_xml |

### 조선왕조실록 (sillok · 태조–철종 · 38만 건)

| 도구 | 설명 | 주요 파라미터 |
|---|---|---|
| `sillok_search` | 본문 키워드 검색 | keyword, limit, offset, and_terms, regex, normalize, with_snippet |
| `sillok_count` | 건수만 반환 — 빈도 조사용 | keyword, field, normalize |
| `sillok_count_by_period` | 시기별 빈도 집계 | keyword, by(reign/decade/year) |
| `sillok_index_search` | 색인(이름·지명·서명·연호·관직) 검색 | value, index_type, limit, offset, exact |
| `sillok_date_search` | 날짜 범위 검색 | date_from, date_to, keyword, offset, with_snippet |
| `sillok_subject_search` | 주제분류 검색 | subject, limit, offset |
| `sillok_get_article` | 기사 전문 조회 | article_id, include_xml |

## 주요 기능

### 진짜 총건수 (`total`)

모든 검색 도구가 `COUNT(*)`를 별도로 실행해 limit에 잘리지 않은 실제 총건수를 반환한다.

```json
{"total": 2699, "offset": 0, "limit": 20, "rows": 20, "docs": [...]}
```

### 페이지네이션 (`offset`)

`offset` 파라미터로 101번째 이후 결과를 순차적으로 수집할 수 있다.

```
sjw_search(keyword="呼望", limit=50, offset=0)   → 1–50번
sjw_search(keyword="呼望", limit=50, offset=50)  → 51–100번
```

### 경량 모드 (`with_snippet=False`)

`with_snippet=False`로 전수 ID 수집 시 응답 크기를 대폭 줄일 수 있다. ID·날짜·제목만 반환한다.

### 빈도 조사 (`sjw_count`, `sillok_count`)

본문 payload 없이 건수만 반환한다. 어휘 빈도 조사의 1단계에서 사용한다.

```
sjw_count(keyword="呼望")  → {"total": 2699}
```

### 시기별 분포 (`sjw_count_by_period`)

재위·10년·연도 단위로 빈도를 집계한다.

```
sjw_count_by_period(keyword="呼望", by="reign")
→ [{"bucket": "영조01년", "n": 12}, ...]
```

### AND 검색 + 정규식

```
sjw_search(keyword="呼望", and_terms=["牌招"])   → 두 어 동시 출현
sjw_search(keyword="", regex="呼望|牌招")        → 정규식
```

### HTML 실체참조 정규화

희귀 한자가 `&#xNNNN;` 형태로 저장된 경우 `normalize=True`로 양형 매칭한다.

```
sjw_search(keyword="實𧏮", normalize=True)
```

## 검색 권장 순서

1. `sjw_count` / `sillok_count` — 빈도 먼저 파악
2. `sjw_index_search` — 색인에서 인명·지명·서명 확인
3. `sjw_search` (with_snippet=False) — 전수 ID 수집
4. `sjw_get_entry` — 필요한 건 전문 확인

## 날짜 기준

모든 검색 결과의 `resolved_date`는 `coalesce(date_seogi, date_gregorian_resolved)` (양력 기준).

- `date_seogi`: 원문에서 직접 파싱된 날짜
- `date_gregorian_resolved`: KASI OpenAPI 양력 보정값
- `date_seogi_raw`: 원문 날짜 문자열 (수정 불가)

## 검색 속도 향상 (선택)

`sql/ks_local_trgm_indexes.sql`을 실행하면 `ilike` 검색이 수 배 빨라진다.

```bash
# sjw
/Library/PostgreSQL/18/bin/psql -h 127.0.0.1 -U postgres -d sjw \
  -f sql/ks_local_trgm_indexes.sql

# sillok
/Library/PostgreSQL/18/bin/psql -h 127.0.0.1 -U postgres -d sillok \
  -f sql/ks_local_trgm_indexes.sql
```

인덱스 생성은 `CONCURRENTLY` 옵션으로 실행 중에도 DB 읽기가 가능하다. 완료까지 수 분 소요.

## 근거 인용 형식

```
근거: 승정원일기 entry_id=SJW-A04020290-00001, date=1626-03-26, title=...
근거: 조선왕조실록 article_id=wka_12502030_001, date=1530-02-30, title=...
```

## 관련 MCP

| MCP | 용도 |
|---|---|
| [db_mcp](https://github.com/namjiman/db_mcp) | 한국고전종합DB(ITKC) 온라인 API 검색 |
| ks-local-mcp (이 저장소) | 승정원일기·실록 로컬 PostgreSQL 검색 |