Skip to main content
Glama
README.md
# gov-notice-mcp

`gov-notice-mcp`는 정부 및 공공기관 공고를 수집, 저장, 검색, 추천하는 범용 MCP 서버와 REST API입니다. 특정 기업 전용 로직 없이 `user_profile.yaml`의 사용자 프로필을 기준으로 공고 적합도를 분석합니다.

## Features

- FastAPI REST API
- MCP Python SDK 기반 Tool 서버
- Connector 패턴 기반 기관 확장
- SQLite 개발 DB, PostgreSQL 운영 DB 지원
- APScheduler 기반 주기 수집
- Rule 기반 추천 점수
- pytest 기본 테스트

## Project Structure

```text
app/
  api/          REST routers
  connectors/   기관별 수집기
  jobs/         scheduler
  mcp/          MCP server/tools
  models/       SQLAlchemy models
  schemas/      Pydantic schemas
  services/     business logic
  utils/        parsing helpers
tests/
```

## Install

```bash
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
```

Windows PowerShell:

```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
Copy-Item .env.example .env
```

## OpenAPI Keys

`.env`에 키를 등록합니다. 저장소에는 실제 키를 커밋하지 마십시오.

```env
G2B_API_BASE_URL=https://apis.data.go.kr/1230000/ad/BidPublicInfoService
G2B_SERVICE_KEY=your-data-go-kr-service-key

NTIS_API_BASE_URL=https://www.ntis.go.kr/rndopen/openApi/public_project
NTIS_SERVICE_KEY=your-ntis-key
```

## Run REST API

```bash
uvicorn app.main:app --reload
```

기본 문서:

- <http://127.0.0.1:8000/docs>
- <http://127.0.0.1:8000/health>

## REST API Examples

```bash
curl "http://127.0.0.1:8000/notices?keyword=AI&only_open=true"
curl -X POST "http://127.0.0.1:8000/collect?keyword=AI&limit=10"
curl "http://127.0.0.1:8000/recommended"
curl "http://127.0.0.1:8000/profile"
```

## Run Web UI

```bash
cd web
npm install
npm run dev
```

기본 Web UI 주소는 <http://localhost:3000>입니다. 백엔드가 다른 주소에서 실행 중이면 `NEXT_PUBLIC_API_BASE_URL`을 설정합니다.

```bash
NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8000 npm run dev
```

## OpenAPI Test Console

OpenAPI Test 화면은 개발자가 실제 OpenAPI Key 발급 후 connector가 정상 동작하는지 검증하기 위한 개발/테스트용 기능입니다.

화면에서 source를 선택하면 백엔드가 서버의 `.env` 값을 읽어 해당 OpenAPI의 Base URL과 API Key를 자동으로 채웁니다. API Key 입력칸은 기본적으로 마스킹되며, 값은 DB나 브라우저 `localStorage`에 저장되지 않습니다. `Load .env` 버튼으로 현재 선택된 source의 `.env` 값을 다시 불러올 수 있습니다.

사용 순서:

1. Web UI 접속
2. `OpenAPI Test` 메뉴 선택
3. source 선택
4. Base URL 입력
5. API Key 입력
6. keyword 입력
7. 연결 테스트 실행
8. raw response와 normalized notice 확인

테스트 API:

```bash
curl -X POST "http://127.0.0.1:8000/openapi/test" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "g2b",
    "base_url": "https://apis.data.go.kr/1230000/ad/BidPublicInfoService",
    "service_key": "your-key",
    "keyword": "AI",
    "from_date": "2026-01-01",
    "to_date": "2026-12-31",
    "limit": 10
  }'
```

보안 원칙:

- API Key는 로그에 남기지 않습니다.
- API Key는 DB에 저장하지 않습니다.
- API Key는 브라우저 `localStorage`에 저장하지 않습니다.
- 테스트 요청 후 서버 메모리에 영구 저장하지 않습니다.
- 운영환경에서는 `.env`, Secret Manager, 컨테이너 secret 등으로 API Key를 관리하십시오.

## Run MCP

```bash
python -m app.mcp.server
```

MCP client 설정 예:

```json
{
  "mcpServers": {
    "gov-notice-mcp": {
      "command": "python",
      "args": ["-m", "app.mcp.server"],
      "cwd": "/path/to/gov-notice-mcp"
    }
  }
}
```

## MCP Tools

- `search_notices`: 공고 검색
- `get_notice_detail`: 공고 상세 조회
- `summarize_notice`: 공고 요약
- `analyze_fit_for_user`: 사용자 프로필 기준 적합도 분석
- `watch_new_notices`: 신규 공고 조회
- `get_user_profile`: 사용자 프로필 조회
- `update_user_profile`: 사용자 프로필 수정
- `collect_notices`: 수집 실행

## Recommendation Rules

- 관심 키워드: `+20`
- 선호 기관: `+15`
- 선호 지역: `+10`
- 지원금액 이상: `+10`
- 제외 키워드: `-30`
- 마감 7일 이하: `-10`

최종 점수는 `0~100` 범위로 보정됩니다.

## Docker

```bash
docker compose up --build
```

서비스:

- `postgres`: PostgreSQL 16
- `api`: FastAPI application

## Migrations

개발 중에는 앱 시작 시 SQLite 테이블을 자동 생성합니다. 운영 DB에서는 Alembic을 사용할 수 있습니다.

```bash
alembic upgrade head
```

## Tests

```bash
pytest
```

## Adding a New Institution

1. `app/connectors/base.py`의 `BaseConnector`를 상속합니다.
2. `fetch_notices()`, `normalize()`, `get_source_name()`을 구현합니다.
3. `CollectorService`의 connector 목록에 추가합니다.
4. normalization 테스트를 추가합니다.

새 기관 추가 시 REST API와 MCP Tool은 같은 service 계층을 쓰므로 별도 라우터 변경 없이 검색/추천 흐름에 포함됩니다.