# 우리학교 알리미 (schoolinfo-mcp)

**내 아이 학교, 검색하지 말고 물어보세요.**

[![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org)

> *학교알리미는 정보가 다 있는데, 막상 찾으려면 어디 있는지 모릅니다.*
> *특히 **수행평가 계획**은 hwp 첨부파일 속에 숨어 있어 학부모가 열어보기도 어렵습니다.*

전국 모든 **초·중·고**의 공시정보는 [학교알리미](https://www.schoolinfo.go.kr)에 공개돼 있습니다.
이 도구는 학교알리미 **OpenAPI**(정형 데이터 35종), [**kordoc**](https://github.com/chrisryugj/kordoc)(hwp→마크다운),
그리고 [**NEIS 개방포털**](https://open.neis.go.kr)(급식·학사일정·시간표)을 묶어서, 사이트를 헤매지 않고 **학교명만으로**
**매일 급식(알레르기 회피 필터)**·학생수·동아리·방과후, **수행평가 계획**, **학사일정·시험 D-day·이번주 브리핑까지** 한 번에 받게 해줍니다.

세 가지 방법으로 쓸 수 있습니다 — 가장 쉬운 순서대로:

| 방법 | 누구에게 | 준비물 |
|------|---------|--------|
| 🌐 **웹앱** | 모든 학부모 (비개발자) | **없음.** 링크만 클릭 |
| 🤖 **AI에게 질문** (원격 MCP) | Claude/Cursor 쓰는 분 | **없음.** URL 한 줄 |
| ⌨️ **CLI / 자동알림 / 로컬 MCP** | 개발자·파워유저 | 인증키 |

---

## 🌐 가장 쉬운 방법 — 웹앱 (설치·인증키 없음)

브라우저만 있으면 됩니다. 아래 주소로 접속하세요:

### 👉 **https://school-mcp.fly.dev**

1. **학교 이름만 입력** (예: "자양중") → `학교 찾기`
   *(지역을 몰라도 됩니다. 전국에서 바로 찾아줘요. 시도/시군구로 좁혀 찾고 싶으면 `지역으로 검색` 탭.)*
2. 학교 카드에서 버튼 클릭:
   - 📋 **수행평가 계획** — 학교가 올린 hwp/pdf를 자동으로 표로 변환
     - **학년·과목 버튼**으로 우리 애 학년, 보고 싶은 과목만 콕 집어 봅니다.
       *(전과목·전학년을 한꺼번에 띄우지 않아 **휴대폰에서도 안 끊기고** 빠릅니다.)*
     - 원본 파일(hwp/pdf)도 **그대로 다운로드**
   - 📅 **이번주** — 이번주 급식·학사일정·다가오는 **시험/방학 D-day**를 한 화면에
   - 🍚 **급식** — 날짜별 식단에 **알레르기 회피 필터**(우유·땅콩 등 입력 → 위험 메뉴 ⚠️ 표시) + 칼로리
   - 📊 **핵심 공시** — 급식 통계·학생수·동아리·방과후·상담을 한 번에
3. 한 번 본 학교는 **최근 본 학교**에 저장 — 다음엔 한 번 탭으로 바로.

> 인증키 발급도, 회원가입도 필요 없습니다. **링크만 알면 누구나** 바로 쓸 수 있어요.
> **모바일 최적화**(화면 안 잘리고, 단어 단위 줄바꿈, 다크모드) — 카톡으로 링크 공유하면 다른 학부모도 그대로 사용.

```
┌──────────────────────────────────────┐
│  🏫 우리 학교 알리미                   │
├──────────────────────────────────────┤
│  ( 이름으로 검색 | 지역으로 검색 )     │
│  🔍 [ 자양중              ] [학교 찾기]│
├──────────────────────────────────────┤
│  최근 본 학교:  ⟨자양중학교⟩ ⟨개포중⟩  │
├──────────────────────────────────────┤
│  자양중학교  [중학교]                  │
│  서울특별시 광진구 자양동 · 공립        │
│  [📋 수행평가 계획] [🍚 급식]           │
│  [📅 이번주] [📊 핵심 공시]             │
└──────────────────────────────────────┘
            │ 📋 클릭
            ▼
┌──────────────────────────────────────┐
│  📋 자양중학교 수행평가 계획           │
│  학년  [1학년] [2학년] [3학년]         │
│  과목  [전체][국어][수학][영어][과학]… │
├──────────────────────────────────────┤
│  교과 │ 정기시험 │ 수행평가            │
│  국어 │   30    │ 설명하는 글 쓰기(20)…│
└──────────────────────────────────────┘
   고른 학년·과목만 표로 — 가볍게.
```

---

## 🤖 AI에게 물어보기 (Claude Desktop / Cursor)

설치하면 **자연어로 그냥 물어볼 수 있습니다.** "검색"이 아니라 "대화"입니다.

### 방법 A — 원격 MCP (설치·빌드·인증키 전부 불필요, 추천)

이미 fly에 떠 있는 서버에 연결만 하면 됩니다. 인증키는 **서버에 있으니** 각자 발급할 필요가 없어요.

`claude_desktop_config.json` (Claude Desktop) 또는 Cursor MCP 설정에 추가:

```json
{
  "mcpServers": {
    "schoolinfo": {
      "type": "streamable-http",
      "url": "https://school-mcp.fly.dev/mcp"
    }
  }
}
```

> URL **한 줄**이면 끝. 재시작하면 도구가 활성화됩니다. (Streamable HTTP, stateless — 세션 관리 없음)
> 클라이언트가 원격 MCP를 지원하지 않으면 `npx mcp-remote https://school-mcp.fly.dev/mcp`로 브리지하세요.

### 방법 B — 로컬 설치 (직접 구동, 인증키 필요)

본인 키로 로컬에서 돌리고 싶다면 (clone → build 후):

```json
{
  "mcpServers": {
    "schoolinfo": {
      "command": "node",
      "args": ["C:/github_project/schoolinfo-mcp/dist/mcp.js"],
      "env": { "SCHOOLINFO_API_KEY": "발급받은_인증키" }
    }
  }
}
```

> 인증키는 무료·즉시 발급입니다 → [발급 방법](#인증키-발급-cli--mcp-직접-구동-시)
> macOS는 `args` 경로만 바꾸면 됩니다. Claude/Cursor를 재시작하면 도구가 활성화됩니다.
> (로컬 구동에는 받은 hwp 파일을 직접 변환하는 `parse_evaluation_file`도 포함됩니다. 원격 MCP에는 보안상 제외.)

### 💬 학부모를 위한 실전 예시 프롬프트

설치 후, Claude에게 **이렇게 그대로 말해보세요.** (복사해서 붙여넣어도 됩니다)

**🍱 급식·기본 정보**
> "서울 강남구 개포중학교 급식 어떻게 운영돼? 직영이야 위탁이야?"

> "개포중학교 한 반에 몇 명이야? 학년별 학생수도 알려줘."

> "우리 동네 노원구 중학교 중에 개교한 지 오래된 곳 찾아줘."

**📋 수행평가 (이 도구의 핵심)** — *학년·과목을 콕 집어 물어보세요*
> "자양중학교 2학년 수행평가 계획 보여줘. 과목별로 뭘 언제 평가하는지 표로."

> "우리 애 자양중 1학년인데, 과학이랑 수학 수행평가만 자세히 알려줘."

> "개포중학교 올해 수행평가 계획 보여줘. 과목별 반영비율이랑 시기 정리해줘."

> "개포중 1학년 국어·영어·수학 수행평가만 표로 만들어줘. 언제 뭘 평가하는지."

> "우리 애가 중2인데, 이번 학기 수행평가 일정 빠른 것부터 순서대로 알려줘. 준비물·과제 있으면 같이."

> "자양중 3학년 영어 수행평가 항목이랑 배점, 정기시험 비율까지 정리해줘."

> "이 학교 수행평가 100%인 과목이랑 지필고사 비중 높은 과목을 구분해줘."

**🎭 학교 생활·활동**
> "개포중학교 동아리 어떤 게 있어? 방과후 프로그램도 같이 알려줘."

> "이 학교 상담은 어떻게 운영돼? 학교폭력 예방교육은 얼마나 해?"

**⚖️ 비교·판단 (전학·진학 고민)**
> "강남구 대청중학교랑 개포중학교 급식이랑 학급당 인원 비교해줘."

> "분당 지역 중학교 몇 곳 학생수랑 동아리 비교해서 표로 보여줘."

**📂 받은 파일 정리**
> "학교에서 받은 이 평가계획 hwp 파일에서 우리 애 학년 수행평가만 정리해줘"
> (파일 경로를 함께 알려주면 됨 — `C:\Downloads\2026_평가계획.hwp`)

> Claude가 알아서 학교를 찾고, hwp를 내려받아 변환하고, 표로 정리해줍니다.
> 학교코드·연도·파일 위치 같은 건 **하나도 몰라도 됩니다.**

### 제공 도구 (로컬 12종 · 원격 11종)

| 도구 | 하는 일 |
|------|---------|
| `find_school` | **학교명만으로 전국 검색** (지역 몰라도 됨) |
| `search_school` | 시도·시군구·학교급·이름으로 학교 찾기 |
| `list_disclosure_types` | 조회 가능한 공시항목 35종 목록 |
| `get_disclosure` | 특정 공시 1건 (급식/학생수/동아리 등) |
| `get_parent_digest` | 학부모 핵심 공시를 한 번에 |
| `get_school_schedule` | **학사일정 조회** (시험·방학·체험학습 + 다가오는 **시험/방학 D-day**, NEIS — `NEIS_API_KEY` 필요) |
| `get_school_meal` | **급식 식단 + 알레르기 회피 필터** (날짜별 요리·알레르기 18종·칼로리·영양, NEIS) |
| `get_school_week` | **이번주 브리핑** (급식·학사일정·D-day; 학년·반 주면 오늘 시간표까지, NEIS) |
| `get_exam_calendar` | **지역 시험 캘린더** — 여러 학교 중간·기말고사 일정을 한 타임라인으로 (학원·학부모, NEIS) |
| `get_school_report` | **학교 비교 리포트** — 같은 시군구 학교들을 학급당 인원·급식 운영방식·교원 기간제 비율·동아리 수로 한 표에 (전학·입학) |
| `get_evaluation_plan` | **수행평가 계획 자동 조회** (hwp 다운로드 → 파싱 → 표 추출) |
| `parse_evaluation_file` | 직접 받은 평가계획 파일(hwp/pdf/docx) 변환 |

---

## 🎯 핵심 기능: 수행평가 계획 자동화

"교과별(학년별) 교수·학습 및 평가 운영 계획"은 학부모가 가장 궁금해하지만 가장 찾기 어렵습니다.
이 항목은 학교알리미 OpenAPI에 **없고 hwp 첨부파일로만** 공시되기 때문입니다.

이 도구는 학교별 공시정보 웹의 내부 요청을 그대로 재현해서, **브라우저 없이 순수 HTTP로**
평가계획 hwp/hwpx/pdf를 자동으로 내려받고, kordoc으로 파싱해 수행평가 표를 뽑아줍니다.

```
학교명 입력
   │
   ▼
OpenAPI로 학교식별코드 조회 ──▶ 평가계획 첨부파일 목록 (POST)
   │                                  │
   │                                  ▼
   └────────────────────▶ hwp/hwpx/pdf 자동 다운로드
                                      │
                                      ▼
                          kordoc 파싱 → 수행평가 섹션 추출 → 표
```

실제 추출 예 (개포중학교):

| 과목 | 영역 | 유형 | 반영비율 |
|------|------|------|---------|
| 국어 | 말하기·듣기/매체 활동 | 정기시험(중간·기말) 선택형 | 30% |
| … | … | … | … |

**학교마다 평가계획을 올리는 방식이 다른데, 알아서 맞춰 보여줍니다:**

- **한 파일에 전학년·전과목**을 담은 학교(통합형) → 웹앱이 **학년·과목 버튼**을 만들어, 고른 학년/과목만 표로 그립니다. 문서가 수백 KB로 커도 **고른 부분만 그려서 휴대폰에서 안 끊깁니다.**
- **학년별·과목별로 파일이 나뉜** 학교 → **파일 목록**에서 골라 보거나 전체를 한꺼번에 볼 수 있습니다.
- AI(MCP)·CLI에서는 `subject="국어"`(특정 과목)·`all=true`(전체)로 골라 받습니다.

---

## ⌨️ CLI 사용

개발자·파워유저용. 터미널에서 바로, 스케줄러로 자동 알림까지.

### 설치

```bash
git clone https://github.com/chrisryugj/schoolinfo-mcp
cd schoolinfo-mcp
npm install
npm run build
```

### 인증키 발급 (CLI / MCP 직접 구동 시)

1. https://www.schoolinfo.go.kr/ng/go/pnnggo_a01_m0.do 접속
2. 네이버/카카오 로그인 후 OpenAPI 인증키 신청 (**무료·즉시 발급**)
3. 환경변수로 설정:

```bash
# .env.local 파일 또는 환경변수
SCHOOLINFO_API_KEY=발급받은_인증키
NEIS_API_KEY=발급받은_NEIS_인증키   # 학사일정 기능용(선택) — https://open.neis.go.kr 무료 발급
```

> `NEIS_API_KEY`는 급식·학사일정·이번주 브리핑(`get_school_meal`·`get_school_schedule`·`get_school_week`)에 쓰입니다. 없어도 나머지 공시 기능은 정상 동작합니다.

> 웹앱(위 https://school-mcp.fly.dev)을 쓰면 **이 단계가 필요 없습니다.**

### 명령어 (실제 동작 예시)

아래는 실제로 실행한 출력입니다.

#### 학교 검색

```bash
$ schoolinfo search 서울 강남구 중학교 개포
```
```markdown
## 개포중학교 (중학교)

| 항목 | 내용 |
|------|------|
| 설립 | 공립 |
| 교육청 | 서울특별시교육청 |
| 주소 | 서울특별시 강남구 선릉로 9 |
| 전화 | 02-2138-1631 |
| 홈페이지 | https://gaepo.sen.ms.kr |
| 학교코드 | S010000699 |
```

#### 급식

```bash
$ schoolinfo get 서울 강남구 중학교 개포중학교 급식
```
```markdown
### 급식 실시 현황

| 항목 | 값 |
|------|------|
| 급식학생수 | 1090 |
| 운영방식 - 급식종류 | 직영 |
| 급식담당인력(명) - 영양(교)사 | 1 |
| 급식담당인력(명) - 조리사 | 1 |
| 급식담당인력(명) - 조리원 | 9 |
| 급식비율 | 100 |
```

#### 학년별·학급별 학생수

```bash
$ schoolinfo get 서울 강남구 중학교 개포중학교 학년별
```
```markdown
### 학년별·학급별 학생수

| 항목 | 값 |
|------|------|
| 1학년 학생수 | 300 |
| 2학년 학생수 | 374 |
| 3학년 학생수 | 410 |
| 총계 학생수 | 1090 |
| 총계 학급당 학생수 | 29.5 |
```

#### 수행평가 계획 자동 조회

```bash
$ schoolinfo eval 서울 강남구 중학교 개포중학교
```
```markdown
## 📄 2026학년도 개포중 학교교육과정 편성 운영 및 교수학습 평가 계획.hwpx (hwpx)

### 🎯 수행평가 관련 (3개)

| 과목 | 1학기 | 2학기 | 반영비율(%) | 만점 |
|------|-------|-------|------------|------|
| 국어 | 말하기·듣기 매체 활동 / 정기시험 중간·기말(선택형) | … | 30 | 100 |
| …  | … | … | … | … |
```

과목별로 나뉜 학교는 목록을 먼저 보여줍니다:

```bash
$ schoolinfo eval 서울 강남구 고등학교 ○○고등학교
📋 ○○고등학교 평가계획 파일 12개 (과목별):
  - 2026_국어과_평가계획.pdf (320KB)
  - 2026_수학과_평가계획.pdf (280KB)
  ...
전체를 보려면 명령 끝에 'all'을 붙이세요. 예: eval 서울 강남구 고등학교 ○○고등학교 all
```

#### 그 외 명령

```bash
schoolinfo digest 서울 강남구 중학교 개포중학교       # 핵심 공시 모아보기
schoolinfo report 서울 강남구 중학교                   # 학교 비교 리포트 (학급당·급식·교원기간제·동아리)
schoolinfo report 서울 강남구 중학교 개포중 대청중     # 특정 학교들만 비교
schoolinfo exams  서울 강남구 중학교                   # 지역 시험 캘린더 (인근 학교 전체, NEIS)
schoolinfo exams  서울 강남구 중학교 개포중 대청중     # 특정 학교들 시험만
schoolinfo schedule 서울 강남구 중학교 개포중학교      # 학사일정 (시험·방학 등, NEIS_API_KEY 필요)
schoolinfo parse "C:\Downloads\2026_평가계획.hwp"     # 받은 hwp → 마크다운 + 수행평가 추출
schoolinfo check 서울 강남구 중학교 개포중학교         # 변경 감지 + 알림 (스케줄러용)
```

---

## 🔔 자동 알림 (공시가 바뀌면 팝업)

비개발자도 OS 스케줄러로 주기 실행하면 됩니다. 공시가 바뀔 때만 알림이 뜹니다.

**Windows 작업 스케줄러** — 매일 오전 8시 변경 확인:

```powershell
schtasks /create /tn "학교알리미체크" /sc daily /st 08:00 ^
  /tr "node C:\github_project\schoolinfo-mcp\dist\cli.js check 서울 강남구 중학교 개포중학교"
```

**macOS/Linux cron** — 매주 월요일 8시:

```cron
0 8 * * 1 SCHOOLINFO_API_KEY=... node /path/dist/cli.js check 서울 강남구 중학교 개포중학교
```

---

## 🚀 직접 배포하기 (선택)

웹앱을 본인 계정으로 띄우고 싶다면 (fly.io 무료 티어로 충분):

```bash
fly auth login                              # 최초 1회 (브라우저 로그인)
fly launch --no-deploy                      # 앱 생성 (fly.toml 자동 인식)
fly secrets set SCHOOLINFO_API_KEY=발급키   # 인증키를 secret으로 안전하게 주입
fly deploy                                  # 배포
```

배포 후 `https://<앱이름>.fly.dev`에서 시도/시군구/학교명 선택 → 끝.
hwp/hwpx/pdf 파싱은 순수 JS라 Chromium 같은 무거운 의존성이 없어 **512MB 머신으로도 충분**합니다.

---

## 🧩 무엇을 조회할 수 있나 (공시 35종)

| 분류 | 항목 |
|------|------|
| 👪 학생 | 학년별·학급별 학생수, 성별 학생수, 전·출입/학업중단, 입학생 |
| 🍱 급식·건강 | 급식 실시 현황, 급식비 집행, 보건관리, 환경위생, 체력 증진 |
| 🎭 활동 | 동아리, 방과후학교, 자유학기제, 교육운영 특색사업, 상담 |
| 👩‍🏫 교원 | 직위별·표시과목별·자격종별 교원, 직원 현황 |
| 🏫 시설·안전 | 교사/용지/지원시설 현황, 시설 개방, 장애인 편의시설, 안전교육, 시설안전 점검 |
| 💰 회계 | 예·결산서, 교비회계, 학교발전기금, 장학금, 교복 단가 |
| 🛡️ 안전 | 학교폭력 예방교육 실적, 수업일수·시수 |
| 📋 **첨부 전용** | **교과별 교수·학습 및 평가 운영 계획 (수행평가) — hwp 자동 추출** |

---

## 🏗️ 아키텍처

```
학교알리미 OpenAPI ─┐
 (35종 정형 JSON)   ├─→ SchoolInfoClient ─→ MCP 도구 / CLI / 웹앱
                    │
평가계획 hwp 첨부 ──┤─→ kordoc(parse) ─→ 수행평가 섹션 추출
                    │
NEIS 개방포털 ──────┘─→ 학사일정 (시험·방학 등)
```

| 모듈 | 역할 |
|------|------|
| `src/client.ts` | OpenAPI 클라이언트(지역 학교검색+공시) + **학교명 전국검색**(`searchSchoolsByName`) |
| `src/codes.ts` | 시도/시군구/학교급/공시항목 코드 매핑 + 약칭 정규화 |
| `src/evaluation.ts` | **평가계획 hwp 자동 다운로드** + kordoc 파싱·수행평가 추출 |
| `src/neis.ts` | **NEIS 학사일정** 조회 (학교코드 해석·동명이교 구분·월별 포맷) |
| `src/lib/` | 공통 인프라 — `fetch-with-retry`(재시도·타임아웃·키마스킹), `cache`(LRU+TTL) |
| `src/regions.json` | 17개 시도·시군구 행정코드 |
| `src/labels.json` | 35종 공시항목 컬럼ID→한글 라벨 |
| `src/mcpServer.ts` | MCP 도구 정의 (stdio·원격 HTTP 공용 `buildMcpServer`) |
| `src/mcp.ts` | MCP 서버 stdio 런처 |
| `src/cli.ts` | CLI + 변경감지 알림 |
| `src/server.ts` + `src/web.ts` | 웹앱 HTTP 서버 + 단일 페이지 UI + **원격 MCP `/mcp`** (fly 배포) |

---

## 🔒 보안

- 인증키는 코드/저장소가 아니라 **환경변수·fly secret**으로만 주입
- 외부(공공API·공문서) 데이터를 DOM에 넣을 때 **XSS 이스케이프 + DOMPurify + CSP** 3중 방어
- 파일 다운로드 50MB / 파싱 200MB 상한, 외부 요청 타임아웃, 경로 순회 차단
- 원본 다운로드는 파일명 정제 + `Content-Disposition` RFC5987 인코딩(헤더 인젝션 차단)
- 웹앱·원격 MCP IP rate limit (분당 60회), 에러 메시지에 내부 정보 비노출
- 원격 MCP는 **stateless**(세션 미보관) + 서버 로컬파일 접근 도구(`parse_evaluation_file`) 비노출

---

## 📜 라이선스

MIT · 데이터 출처: 학교알리미(schoolinfo.go.kr), 공공누리 제1유형(출처표시)
hwp 변환 엔진: [kordoc](https://github.com/chrisryugj/kordoc)
</content>
</invoke>
