内容
# k-lottery




동행복권 로또 6/45를 대신 사고, 잔액도 보고, 당첨됐는지도 확인해주는 도구예요.
터미널에서 명령어로 써도 되고, Claude Code나 Claude Desktop에서 말로 시켜도 돼요.
CLI 4개랑 MCP 서버가 같은 코어를 써요.
> 직접 쓰려고 만든 개인용 도구예요. **진짜 돈이 나가니까** 쓰기 전에
> [면책](#면책)을 꼭 읽어주세요.
```
$ uv run scripts/balance.py
구매가능금액 12,000 원
총 예치금 12,000 원
마일리지 500 원
오늘 구매액 0 / 150,000 원
이번주 구매액 5,000 원
최근 1달 21,000 원
고정 가상계좌 7010XXXXXXXXXX
```
## 목차
- [무엇을 할 수 있나](#무엇을-할-수-있나)
- [요구사항](#요구사항)
- [빠른 시작](#빠른-시작)
- [MCP 서버 설정](#mcp-서버-설정)
- [안전장치](#안전장치-돈이-움직이는-경로)
- [CLI 사용법](#cli-사용법)
- [환경변수](#환경변수)
- [종료 코드](#종료-코드)
- [자동화 예시 (cron)](#자동화-예시-cron)
- [알아둘 점](#알아둘-점)
- [개발](#개발)
- [기여](#기여) · [면책](#면책) · [라이선스](#라이선스)
## 무엇을 할 수 있나
| CLI | 하는 일 |
| --- | --- |
| `scripts/balance.py` | 예치금·구매 한도·서약 유효성 |
| `scripts/check.py` | 구매 내역과 당첨 결과 (등수는 서버가 계산) |
| `scripts/deposit.py` | 충전용 가상계좌 발급 (이체는 직접) |
| `scripts/buy.py` | 자동번호 구매 (기본 dry-run) |
| MCP 도구 | 파라미터 | 노출 | 하는 일 |
| --- | --- | --- | --- |
| `lotto_status` | — | 항상 | 잔액·한도·서약 유효성·가상계좌(**뒤 4자리만**) |
| `lotto_results` | `days=14`, `round_no?` | 항상 | 구매 내역 + 당첨 결과 |
| `lotto_draw` | `round_no` | 항상 | 공개 추첨 결과 (로그인 불필요) |
| `lotto_buy_precheck` | `games=5` | 항상 | 구매 전 점검만. **절대 사지 않음** |
| `lotto_buy` | `games=5` | 게이트 | 실제 구매 (승인 필수) |
| `lotto_deposit` | `amount` | 게이트 | 가상계좌 발급 (승인 필수) |
## 요구사항
| | |
| --- | --- |
| [uv](https://docs.astral.sh/uv/getting-started/installation/) | 필수예요. Python 3.13은 uv가 `.python-version`을 보고 알아서 받아와요 |
| 동행복권 계정 | 아이디/비밀번호로 로그인하는 계정이요 |
| 건전구매 서약 | 사이트에서 **직접** 하셔야 해요. 만료됐으면 구매가 막혀요 (종료코드 3) |
| 예치금 | 충전하려면 은행 이체가 필요해서 완전 무인화는 안 돼요 |
| OS | macOS에서 확인했어요. Linux도 될 것 같고, Windows는 안 해봤어요 |
## 빠른 시작
```bash
git clone https://github.com/rajephon/k-lottery.git
cd k-lottery
uv sync
cp .env.example .env # 아이디·비밀번호 채우기 (.env는 커밋되지 않아요)
uv run scripts/balance.py
```
## MCP 서버 설정
CLI와 같은 코어 위에 FastMCP(stdio) 서버를 올려뒀어요. 잔액이나 당첨 결과를 대화로 물어볼 수
있고, 원하면 구매·충전까지 열 수 있어요. 다만 실제로 사는 건 **매번 직접 승인**하셔야 해요.
### Claude Code에 등록
```bash
# 조회 전용 (기본). 이 저장소 디렉터리에서만 보여요
claude mcp add klottery -- uv run --directory /절대경로/k-lottery scripts/mcp_server.py
# 어느 디렉터리에서든 쓰려면 `-s user`로 다시 등록하세요
claude mcp add klottery -s user -- uv run --directory /절대경로/k-lottery scripts/mcp_server.py
# 구매·충전까지 열려면 게이트를 환경변수로 넘겨요
claude mcp add klottery -s user \
-e KLOTTERY_MCP_ALLOW_BUY=1 -e KLOTTERY_MCP_ALLOW_DEPOSIT=1 -- \
uv run --directory /절대경로/k-lottery scripts/mcp_server.py
```
> **게이트는 `.env`에 적어도 안 열려요.** `-e` 옵션이나 Desktop 설정의 `env` 블록처럼
> **서버를 띄우는 프로세스 환경**에 넣어야 해요. `.env`는 모델이 고칠 수 있는 파일이거든요.
> 거기서 스위치를 읽으면 "모델이 못 건드리는 곳에 스위치를 둔다"는 전제가 무너져요.
게이트는 **서버가 뜰 때 한 번** 읽고 끝이에요. 나중에 켜거나 끄려면 등록을 지우고 다시 만든 뒤
클라이언트를 재시작하세요 (`claude mcp remove klottery`).
### Claude Desktop에 등록
설정 파일을 열어요. 없으면 새로 만들면 돼요.
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"klottery": {
"command": "/opt/homebrew/bin/uv",
"args": ["run", "--directory", "/절대경로/k-lottery", "scripts/mcp_server.py"],
"env": { "KLOTTERY_MCP_ALLOW_BUY": "1" }
}
}
}
```
- `command`에는 `which uv`로 나온 **절대경로**를 적어요. GUI 앱은 셸 PATH를 물려받지 않거든요.
- `--directory` 뒤도 절대경로여야 해요.
- `env`를 빼면 조회 도구 4개만 떠요.
- 저장했으면 Claude Desktop을 **완전히 껐다가** 다시 켜주세요.
> Claude Desktop이 승인 프롬프트(elicitation)를 지원하는지는 2026년 7월 현재 확인하지
> 못했어요. 지원하지 않으면 조회 도구만 동작하고 구매·충전은 `[APPROVAL_UNSUPPORTED]`로
> 실패해요. 그럴 땐 CLI를 쓰시면 돼요.
### 잘 붙었는지 확인
```bash
claude mcp list # klottery가 ✔ Connected 인지 봐요
```
Claude Code에서 `/mcp`를 치면 어떤 도구가 올라왔는지 보여요. 조회 4개만 있으면 조회 전용이고,
`lotto_buy`까지 보이면 게이트가 열린 거예요. 서버 로그(stderr)에도 남아요.
```
돈 도구 노출: buy=True deposit=False
```
### 구매 승인 화면
모델이 `lotto_buy`를 부르면 **클라이언트가 사람에게** 이 화면을 띄워요. 금액을 직접 쳐야
넘어가요. 모델은 이 답변 경로에 끼어들 수 없어요.
```
로또 6/45 구매 승인 요청
대상 회차 1236회 (추첨 2026/08/08)
게임 수 5게임 (자동)
결제 금액 5,000원
구매가능금액 12,000원 → 구매 후 7,000원
오늘 누적 0원 / 한도 150,000원
승인하려면 결제 금액(원)을 숫자로 입력하세요.
※ 이 요청은 AI 모델이 호출한 것입니다. 방금 직접 지시하지 않았다면 거절하세요.
```
### 문제 해결
| 증상 | 원인과 해결 |
| --- | --- |
| Claude Code에 klottery가 안 보여요 | 기본 스코프가 `local`이라 그래요. 다른 디렉터리에서도 쓰려면 `-s user`로 다시 등록하세요 |
| `lotto_buy`가 목록에 없어요 | 게이트를 `.env`에 넣으셨을 거예요. `-e`로 옮기고 다시 등록한 뒤 재시작하세요 |
| Desktop에서 서버가 안 떠요 | `command`를 `which uv` 절대경로로 바꿔보세요. GUI 앱은 셸 PATH를 못 봐요 |
| `[APPROVAL_UNSUPPORTED]` | 클라이언트가 승인 프롬프트를 지원하지 않아요. CLI로 처리하세요 |
| `[RECENTLY_DECLINED]` | 직전 승인을 거절했거나 취소했어요. 10분 뒤에 다시 하거나 CLI로 처리하세요 |
| `[CLOSED]` | 판매시간(06:00~24:00, 토요일은 20:00 마감)이 아니에요. 시간 지나면 풀려요 |
| `[CONFIG] 건전구매 서약…` | 사이트에서 직접 재서약하셔야 해요 |
| `[BALANCE]` | 예치금이 모자라요. 가상계좌를 받아서 **직접 이체**해야 충전돼요 |
## 안전장치 (돈이 움직이는 경로)
**CLI**는 구매·충전이 기본 dry-run이고, `--execute`를 붙여야 실제로 실행돼요. 확인 프롬프트는
stdin이 tty가 아니면 그냥 **거절**해요. cron 같은 데서 얼떨결에 결제되는 걸 막으려고요.
**MCP엔 tty도 `--execute`도 없어서** 다른 방법이 필요했어요. `execute: bool` 같은 파라미터를
두면 모델이 알아서 `true`를 넣어버릴 수 있거든요. 그건 승인이 아니죠. 그래서 층을 나눴어요
(자세한 근거는 [설계 문서](./docs/2026-07-26_klottery-mcp-server.md)에 있어요).
1. **노출** — 구매·충전은 서버를 띄우는 프로세스 환경에 `KLOTTERY_MCP_ALLOW_*`가 있어야만
목록에 떠요. 모델은 실행 중에도, `.env`를 고쳐서도 이걸 못 바꿔요.
2. **승인** — 실행 직전에 사람이 결제 금액을 직접 입력해야 해요. 프롬프트에는 이 요청을
모델이 했다는 사실도 같이 띄워요. 프롬프트 주입으로 모델이 멋대로 부른 경우를 구분하시라고요.
3. **막히면 멈춰요** — 승인 프롬프트를 지원하지 않는 클라이언트에서는 그냥 실패해요.
네트워크 요청은 한 번도 나가지 않아요.
4. **조르기 차단** — 승인 요청은 한 번에 하나만 떠요. 거절·취소·중단하거나 금액을 틀리게
입력하면 10분 동안 다시 묻지 않아요. 구매와 충전이 이 쿨다운을 같이 써요.
5. **상한** — 한 번에 최대 5게임(5,000원)이고, 중복 구매를 뚫는 `--force`는 MCP에 없어요.
승인을 받은 뒤에도 서버 데이터를 새로 받아 점검을 다시 돌려요.
6. **감사** — 모든 시도가 `data/mcp-audit.jsonl`에 남아요. 상관 ID, 결제 요청을 실제로
보냈는지, 무슨 오류였는지까지 기록해요. 구매 응답 원문은 성공하든 실패하든 저장하고,
기록에 실패해도 결제 결과를 뒤집지 않아요.
7. **정보 차단** — 도구 설명이나 반환값에 우회 방법(명령줄, 플래그)을 적지 않아요. 그걸 읽는 건
사람이 아니라 모델이니까요. 승인에 걸린 시간, 계좌번호 전체, 계정 아이디도
모델에게 넘기지 않아요.
구매 요청을 보내기 전에 다섯 가지를 확인해요. 하나라도 걸리면 요청 자체를 안 보내요.
1. 게임 수가 1~5인지
2. 건전구매 서약이 살아 있는지
3. **같은 회차를 이미 샀는지** (서버 구매내역 기준이에요. CLI의 `--force`로만 넘길 수 있어요)
4. 일 구매한도를 넘지 않는지
5. 잔액이 충분한지
## CLI 사용법
네 스크립트 모두 `--json`(결과 JSON을 stdout으로), `-v`(DEBUG 로그, stderr),
`--env-file <경로>`를 받아요. 사람이 읽는 로그는 `stderr로`, 파이프로 넘길 데이터는 stdout으로
나가요.
### 잔액 확인
```bash
uv run scripts/balance.py
uv run scripts/balance.py --json
```
### 당첨 확인
```bash
uv run scripts/check.py # 최근 14일
uv run scripts/check.py --days 30
uv run scripts/check.py --round 1234
```
등수는 서버가 계산해서 줘요. 내가 산 번호를 따로 저장해둘 필요가 없어요.
사지 않은 회차를 물어보면 공개 추첨 결과를 대신 보여줘요.
### 충전
```bash
uv run scripts/deposit.py --amount 5000 # dry-run
uv run scripts/deposit.py --amount 5000 --execute
```
넣을 수 있는 금액은 `5000` `10000` `20000` `30000` `50000` `100000` `150000`이고,
하루 15만원까지예요.
> **이 명령만으로는 돈이 움직이지 않아요.** 고정 가상계좌에 "얼마 넣을 거다"라고 등록하는
> 게 전부예요. 출력된 계좌로 **직접 이체**해야 예치금이 들어와요.
### 구매
```bash
uv run scripts/buy.py # dry-run (기본 5게임)
uv run scripts/buy.py --games 5 --execute
uv run scripts/buy.py --execute --yes # cron용
```
자동번호로 사요. **기본은 dry-run**이라 `--execute`를 붙여야 실제로 결제돼요.
## 환경변수
계정 정보는 저장소 루트의 `.env`에 넣어요(`cp .env.example .env`). 이 파일은 커밋되지 않아요.
| 환경변수 | 설명 | 기본값 |
| --- | --- | --- |
| `LOTTO_USER_ID` | 동행복권 아이디 | (필수) |
| `LOTTO_PASSWORD` | 동행복권 비밀번호 | (필수) |
| `LOTTO_DATA_DIR` | 쿠키·이력 저장 위치 | `./data` |
| `LOTTO_TIMEOUT` | HTTP 타임아웃(초) | `10` |
| `LOTTO_REQUEST_INTERVAL` | 연속 요청 최소 간격(초) | `0.3` |
| `LOTTO_USER_AGENT` | User-Agent | 크롬 |
MCP 결제 도구를 여는 스위치는 **`.env`가 아니라** 서버를 띄우는 프로세스 환경에서 읽어요.
| 환경변수 | 설명 | 기본값 |
| --- | --- | --- |
| `KLOTTERY_MCP_ALLOW_BUY` | `lotto_buy` 노출 (`1`/`true`/`yes`/`on`) | (안 뜸) |
| `KLOTTERY_MCP_ALLOW_DEPOSIT` | `lotto_deposit` 노출 | (안 뜸) |
> 접두사를 다르게 둔 건 일부러예요. `LOTTO_*`는 `.env`로 들어오는 설정이고,
> `KLOTTERY_MCP_*`는 **`.env`로 들어오면 안 되는** 스위치거든요.
## 종료 코드
cron에서 실패 원인을 구분하시라고 나눠뒀어요.
| 코드 | 의미 | 코드 | 의미 |
| --- | --- | --- | --- |
| 0 | 성공 | 7 | 자동화 차단 (`isAllowed=N`) |
| 1 | 일반 오류 | 8 | 이미 구매한 회차 |
| 2 | 잘못된 인자·값 | 9 | 판매시간 아님·점검중 |
| 3 | 설정/자격증명 | 10 | 접속 대기열 |
| 4 | 인증 실패 | 11 | 사용자가 확인을 거부 |
| 5 | 서버 응답 이상 | 130 | 중단 |
| 6 | 잔액 부족 | | |
재시도해서 의미 있는 건 9번과 10번뿐이에요. 6번이나 8번은 몇 번을 돌려도 결과가 같아요.
## 자동화 예시 (cron)
```cron
# uv는 절대경로로 적어요. cron의 PATH는 셸과 다르거든요 (`which uv` 결과를 쓰면 돼요)
# 매주 월요일 19:00 구매, 일요일 09:00 당첨 확인
0 19 * * 1 cd /절대경로/k-lottery && /opt/homebrew/bin/uv run scripts/buy.py --execute --yes >> data/cron.log 2>&1
0 9 * * 0 cd /절대경로/k-lottery && /opt/homebrew/bin/uv run scripts/check.py --days 7 >> data/cron.log 2>&1
```
`buy.py`는 같은 회차를 이미 샀는지 서버 내역으로 확인하니까 두 번 돌아도 중복으로 사지 않아요.
판매시간(06:00~24:00, 토요일은 20:00 마감)이 아니면 종료코드 9로 끝나요.
예치금이 떨어지면 종료코드 6으로 실패해요. 충전은 은행 이체가 필요해서 여기까지가 한계예요.
## 알아둘 점
- 사이트가 **2026년에 개편**됐어요. 인터넷에 돌아다니는 기존 봇 코드(`common.do?method=...`,
`userSsl.do?method=login`)는 전부 죽은 엔드포인트를 써요.
- 구매 요청에 **자동화 탐지**(`isAllowed=="N"`)가 있어요. 아직 걸려본 적은 없지만, 걸리면
종료코드 7로 확실하게 실패해요.
- 모바일 구매는 토·일에 막혀요. 이 도구는 PC 경로를 써요.
- 판매시간이 아니면 사이트가 HTTP 200으로 멀쩡한 페이지를 주면서 구매 폼만 빼놔요.
이 경우를 `[CLOSED]`로 따로 구분해요.
## 개발
```bash
uv run pre-commit install # 훅 설치 (최초 1회)
uv run ruff check --fix . # 린트
uv run ruff format . # 포맷
uv run ty check # 타입 검사
uv run pytest # 테스트 (네트워크 안 탐)
```
테스트는 실제 네트워크로 나가지 않아요. httpx 호출은 `respx`로 목킹하고, 소켓 가드가 이 규약을
강제해요. 목킹을 빠뜨린 테스트는 통과가 아니라 실패해요.
```
src/klottery/
├── endpoints.py URL·필드명·상수 — 사이트가 바뀌면 여기만 고친다
├── dhlottery.py 사이트 클라이언트
├── models.py 응답 파싱
├── flows.py 구매·충전·조회 조립 (CLI·MCP 공유)
├── payloads.py JSON 빌더 (CLI --json과 MCP 출력의 단일 계약)
├── purchase.py 구매 전 점검 (순수 함수)
├── session.py httpx 세션 + 쿠키 영속화
├── crypto.py 로그인 RSA
├── clock.py KST 시각·날짜 계산
├── cli.py 공통 인자·종료코드 (CLI 전용)
├── config.py 설정
├── errors.py 도메인 예외
├── log.py 로깅·비밀값 마스킹
├── storage.py data/ 원자적 쓰기
└── mcp/ MCP 서버 배선 — 도메인 로직은 안 둔다
├── server.py 조립 + 노출 게이트
├── tools.py 도구 정의
├── confirm.py 승인·쿨다운 (유일 접점)
├── runtime.py 락·에러 변환·감사 로그
└── errors.py 도메인 예외 → ToolError 코드 표
scripts/ 진입점 5개 (CLI 4개 + mcp_server.py)
tests/ pytest (respx 목킹)
data/ 쿠키·이력 (gitignore)
```
- 작업 규약: [CLAUDE.md](./CLAUDE.md)
- 사이트 API 실측 스펙: [docs/dhlottery-api-spec.md](./docs/dhlottery-api-spec.md)
- 설계: [docs/2026-07-26_dhlottery-cli.md](./docs/2026-07-26_dhlottery-cli.md) ·
[docs/2026-07-26_klottery-mcp-server.md](./docs/2026-07-26_klottery-mcp-server.md)
## 기여
개인용 도구라 기능 요청은 받지 않아요. 사이트가 바뀌어서 깨진 부분이라면 이슈나 PR을 환영해요.
다만 그럴 땐 `docs/dhlottery-api-spec.md`에 실제로 캡처한 요청·응답을 같이 올려주세요.
추측으로 쓴 엔드포인트는 머지하지 않아요.
## 면책
- **본인 계정**에 쓰라고 만든 개인용 도구예요. 남의 계정에 쓰라고 만든 게 아니에요.
- 동행복권 이용약관이나 자동화 정책에 걸리는지는 쓰는 분이 판단하셔야 해요. 구매 응답에
자동화 탐지(`isAllowed=="N"`)가 있고, **계정이 정지될 수 있어요.**
- **진짜 돈이 나가요.** 잘못 사거나 잘못 충전해서 생긴 손해는 쓰는 분 몫이에요.
- 복권은 사행성 상품이에요. 자동화하면 나도 모르게 사는 횟수가 늘어요. 동행복권 구매한도랑
이 도구 상한을 같이 걸어두시길 권해요. 혹시 도박 문제로 힘드시다면 국번 없이 **1336**으로
전화해 보세요.
- 사이트가 개편되면 언제든 안 돌아갈 수 있어요. 아무것도 보증하지 않아요(AS-IS).
## 라이선스
[MIT](./LICENSE)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器