Skip to main content
Glama
joonhyungkimweb

pokemon-champions-mcp

README.md
# Pokémon Champions MCP

LLM이 직접 호출할 수 있는 Pokémon Champions 싱글 배틀용 1:1 매치업 계산기입니다. 턴 단위 시뮬레이션 대신 두 포켓몬의 스탯·스피드 구간·타입 상성·양방향 데미지를 한 번에 구조화된 JSON으로 반환합니다.

이 프로젝트는 비공식 팬 제작 도구이며 Nintendo, The Pokémon Company 또는 GAME FREAK와
제휴하거나 이들로부터 승인·후원받지 않았습니다. Pokémon 및 관련 명칭은 각 권리자의 상표입니다.

현재 MVP는 **Pokémon Champions Regulation M-C / Singles / Lv. 50**에 고정되어 있습니다.

## 제공 기능

- Champions 전용 스탯 포인트 계산: 스탯당 `0-32`, 총합 `66` 이하
- 현재 세트의 실능 및 랭크 적용 스탯
- 최저속·무보정·준속·최속별 `기본 / 구애스카프 / +1 / 구애스카프 +1` 스피드
- 마비, 스피드 랭크, 구애스카프, 순풍, 날씨 특성, 트릭룸을 반영한 선공 비교
- 양쪽이 지정한 기술의 16개 데미지 난수와 실제 HP 손실, 1타 확률
- 메가진화, 날씨·필드, 벽, 상태이상, 특성·아이템 상호작용
- 방어 타입 기준 약점·반감·무효 전체 표
- Regulation M-C 개별 세트 적법성 검사
- 포켓몬·폼·기술·특성·도구·성격·타입·배틀 상태의 한국어 입력과 한·영 병기 출력
- 동일 코어를 사용하는 JSON CLI와 MCP 도구 `analyze_matchup`
- 부분 한국어·영어·별칭으로 게임 데이터를 탐색하는 `search_game_data`
- 여러 세트와 상대의 교차 매치업을 요약 비교하는 `compare_matchups`
- 비공식 Champions Battle Data의 기술·도구·동료·성격·스탯 포인트·특성 사용률 조회

계산 흐름은 다음처럼 단순하게 분리되어 있습니다.

```text
LLM / CLI
    ↓
Zod 입력 검증 및 기본값 확정
    ↓
오프라인 한국어 이름 → Showdown 식별자 해석
    ↓
Pokémon Showdown Champions 어댑터
    ↓
스탯 · 스피드 · 타입 · 데미지 결과 집계
```

## 실행

개발 환경은 `mise.toml`에서 Node.js `26.7.0`과 pnpm `10.28.2`로 고정합니다.
Node.js 최소 지원 버전은 `22.18.0`입니다. Python은 프로젝트의 직접 의존성이 아닙니다.
설치 시 고정한 Showdown 소스를 빌드하므로 개발 의존성과 `postinstall` 실행이 필요합니다.

mise가 설치된 환경에서 저장소 루트에서 실행합니다.

```bash
mise trust
mise install
mise exec -- pnpm install --frozen-lockfile
mise exec -- pnpm test
mise exec -- pnpm cli -- --file examples/garchomp-vs-charizard-y.json
```

셸에 mise를 활성화했다면 `pnpm`을 직접 실행할 수 있습니다. zsh에서는
`~/.zshrc`에 `eval "$(mise activate zsh)"`를 추가하고 새 셸을 엽니다.

```bash
pnpm test
pnpm cli -- --file examples/garchomp-vs-charizard-y.json
pnpm cli -- --file examples/korean-matchup.json
```

JSON을 인자로 직접 넘기거나 표준 입력으로 전달할 수도 있습니다.

```bash
pnpm cli -- '{"left":{"species":"Garchomp"},"right":{"species":"Charizard"}}'
pnpm cli -- '{"left":{"species":"한카리아스"},"right":{"species":"리자몽"}}'
pnpm cli < examples/garchomp-vs-charizard-y.json
```

## MCP로 LLM에 연결

### Codex에서 이 저장소에만 연결

프로젝트 전용 `.codex/config.toml`을 로컬에서 만들면 사용자 전역 설정을 변경하지 않고 이
저장소에서만 `pokemon-champions-mcp` MCP 서버를 사용할 수 있습니다. `.codex/`는 로컬 절대
경로나 개인 설정이 공개 저장소에 올라가지 않도록 Git에서 제외됩니다.

먼저 의존성을 설치하고 설정 디렉터리를 만듭니다.

```bash
mise trust
mise install
mise exec -- pnpm install --frozen-lockfile
mkdir -p .codex
```

`.codex/config.toml`을 아래처럼 작성하고 `cwd`를 클론한 저장소의 실제 절대 경로로 바꿉니다.

```toml
[mcp_servers.pokemon-champions-mcp]
command = "mise"
args = ["exec", "--", "node", "--import", "tsx", "src/mcp.ts"]
cwd = "/absolute/path/to/pokemon-champions-mcp"
enabled = true
startup_timeout_sec = 20
tool_timeout_sec = 60
```

그다음 이 저장소 루트에서 Codex를 새로 시작합니다. 프로젝트를 신뢰해야 프로젝트 전용 설정이
로드됩니다.

```bash
cd /path/to/pokemon-champions-mcp
codex
```

Codex TUI에서는 다음 명령으로 연결 상태와 도구를 확인합니다.

```text
/mcp
```

터미널에서 설정만 확인하려면 저장소 루트에서 실행합니다.

```bash
codex mcp list
```

설정 변경은 이미 실행 중인 세션의 도구 목록에 즉시 반영되지 않습니다. 새 Codex 세션을
시작하거나 데스크톱 앱/IDE 확장을 재시작해야 합니다. 공식 설정 형식과 프로젝트 범위 동작은
[Codex MCP 문서](https://developers.openai.com/codex/mcp)와
[Codex 고급 설정 문서](https://developers.openai.com/codex/config-advanced)를 참고하세요.

### 다른 MCP 클라이언트에서 연결

Codex 프로젝트 설정을 읽지 않는 클라이언트에서는 아래 STDIO 명령을 직접 등록합니다. `cwd`는
이 저장소의 절대 경로로 바꿉니다.

```json
{
  "mcpServers": {
    "pokemon-champions-mcp": {
      "command": "mise",
      "args": ["exec", "--", "node", "--import", "tsx", "src/mcp.ts"],
      "cwd": "/absolute/path/to/pokemon-champions-mcp"
    }
  }
}
```

서버는 읽기 전용 도구 네 개를 노출합니다.

- `analyze_matchup`: 두 포켓몬의 Champions 싱글 매치업을 한 번에 분석
- `search_game_data`: 포켓몬·폼·기술·특성·도구·성격을 부분 이름으로 검색
- `compare_matchups`: 여러 세트와 상대를 최대 16개 조합으로 일괄 비교
- `get_usage_statistics`: 한국어 또는 영어 포켓몬명으로 참고용 싱글 사용 통계 조회

이름이나 폼이 확실하지 않을 때는 먼저 검색 결과의 `id` 또는 `name`을
`analyze_matchup`에 전달합니다. 검색은 오프라인이며 결과 수는 기본 10개, 최대 50개입니다.

`compare_matchups`는 `leftSets × rightSets` 조합의 선공, 적법성, 기술별 HP 손실률과
1타 확률을 간결하게 반환합니다. 승자를 단정하거나 턴 진행을 시뮬레이션하지 않으며 조합은
최대 16개로 제한됩니다.

통계 도구는 원격 API를 호출하므로 네트워크가 필요합니다. 응답에는 제공자, 조회 URL, 시즌,
생성 시각과 함께 `official: false`, `upstreamSource: "undisclosed"`,
`purpose: "reference-only"`가 포함됩니다. 수집 원천과 방법이 공개되지 않은 비공식 통계이므로
정확한 계산 결과와 구분해 참고용으로 사용해야 합니다.

## 한국어 입력 예시

```json
{
  "left": {
    "species": "한카리아스",
    "ability": "까칠한피부",
    "item": "생명의구슬",
    "nature": "명랑",
    "statPoints": { "atk": 32, "spd": 2, "spe": 32 },
    "boosts": { "spe": 0 },
    "moves": ["지진", "스톤샤워"]
  },
  "right": {
    "species": "리자몽",
    "ability": "맹화",
    "item": "리자몽나이트Y",
    "nature": "겁쟁이",
    "statPoints": { "hp": 2, "spa": 32, "spe": 32 },
    "megaEvolution": true,
    "moves": ["용의파동", "에어슬래시"]
  },
  "field": {
    "weather": "자동",
    "terrain": "자동",
    "trickRoom": false,
    "left": { "reflect": false, "tailwind": false },
    "right": { "lightScreen": false, "tailwind": false }
  }
}
```

기술은 문자열 또는 크리티컬 여부를 포함한 객체로 입력할 수 있습니다.

```json
{ "name": "Rock Slide", "criticalHit": true }
```

### 기본값

- 성격: `Serious`
- 스탯 포인트와 랭크: 전부 `0`
- 특성: 해당 폼의 첫 번째 기본 특성
- 아이템: 없음
- 현재 HP: `100%`
- 날씨·필드: `auto` — 등장 및 메가진화 특성으로 생긴 상태를 유지
- 배틀 형식: `pokemon-champions / M-C / singles`

이름 필드는 한국어 정식명, 지원하는 통용 별칭, 영어 정식명, Pokémon Showdown 식별자를 모두 받습니다. 띄어쓰기와 일부 문장부호는 무시하며, `알로라 나인테일`처럼 폼 이름의 자연스러운 한국어 어순도 해석합니다. 결과에는 계산용 영어 정식명과 `speciesKo`, `moveKo`, `typesKo` 같은 한국어 필드가 함께 들어갑니다.

메가진화할 때 `ability`는 진화 전 포켓몬의 특성을 입력하거나 생략합니다. 진화 후 특성과 폼 이름은 엔진이 자동으로 적용합니다. 동일한 한국어 이름이 여러 폼을 가리킬 수 있으면 임의 선택하지 않고 더 구체적인 폼을 요청하는 오류를 반환합니다.

## 결과 읽기

- `pokemon`: 최종 폼, 타입, 특성, HP, 표시 스탯, 랭크 적용 스탯, 적법성
- `field`: 요청한 필드와 특성까지 반영된 실제 날씨·필드·벽
- `speed.actual`: 현재 세트끼리의 실효 스피드와 선공 측
- `speed.leftProfiles/rightProfiles`: 최저속·무보정·준속·최속 벤치마크
- `typeMatchups`: 방어 타입만으로 본 4배·2배·반감·무효
- `damage.leftToRight/rightToLeft`: 각 기술의 양방향 계산

데미지에는 두 범위가 함께 들어갑니다.

- `rawDamage`: 데미지 공식 결과. 최대 HP를 넘는 값도 그대로 보여 줌
- `hpLoss`: 현재 HP 상한과 물흡수·기합의띠·옹골참 같은 실제 명중 처리까지 반영한 HP 감소량

기술은 명중한 상황을 전제로 계산하므로 명중률 자체는 확률에 섞지 않습니다. `ohkoChancePercent`는 16개 데미지 난수 중 실제로 쓰러뜨리는 비율입니다.

## MVP 범위와 한계

- 연속기 데미지 범위는 부정확하게 근사하지 않고 `unsupported`로 반환합니다.
- 변화기 효과는 턴 진행 없이 `non-damaging`으로 분류합니다.
- 우선도 기술끼리의 행동 순서는 비교하지 않습니다. 스피드 비교는 동일 우선도 구간 기준입니다.
- 교체, 엔트리 해저드, 매 턴 회복, 이전 턴 카운터 등 턴 히스토리는 모델링하지 않습니다.
- 타입 약점 표는 타입 상성만 보여 주며, 특성·아이템에 의한 무효화는 실제 데미지 결과에 반영됩니다.
- 현재 Champions Dex에서 사용 가능한 정식 항목의 한국어명은 포함하지만, 커뮤니티 은어·축약어는 자주 쓰는 일부만 지원합니다. 정식명이 가장 안정적입니다.
- 과거 세대 전용·G-Max 등 Champions에서 사용할 수 없는 비표준 폼은 한국어 완전성 보장 대상이 아닙니다.

## 데이터와 재현성

계산 엔진은 Pokémon Showdown 커밋 `d849b220082e113d8a17303509fb44d420c543d5`의 `champions` 모드와 `[Gen 9 Champions] BSS Reg M-C` 규칙을 고정해서 사용합니다. npm 배포본 `0.11.11`에는 M-C가 없어 커밋별 소스 아카이브를 설치하고 `scripts/build-showdown.mjs`로 JavaScript와 타입 선언을 빌드합니다. `engine.version`에도 소스 커밋을 포함합니다. 규정이나 게임 데이터가 바뀌면 엔진 고정값, 기대값 테스트, `engine` 메타데이터를 함께 갱신해야 합니다.

한국어명은 PokéAPI 저장소의 고정 커밋 `17dd3092872cabcb7c008051771d2a2fd8c8c260`에서 생성한 정적 테이블입니다. Champions에만 존재하는 메가폼·메가스톤·특성은 별도 보정합니다. 따라서 일반 계산과 MCP 호출 중에는 외부 API나 RPC를 호출하지 않습니다.

단, MCP의 `get_usage_statistics`는 [Champions Battle Data](https://championsbattledata.com/)의
비공식 원격 API를 호출합니다. 이 제공자는 원천 데이터의 수집 경로와 방법을 공개하지 않았으며,
API 응답의 `source` 값은 제공자 내부 CSV 경로입니다.

데이터를 새로 생성하려면 네트워크가 가능한 환경에서 실행합니다.

```bash
pnpm sync:korean
```

- [Pokémon Champions 공식 Gameplay](https://champions.pokemon.com/en-us/gameplay/)
- [Pokémon Champions Regulation M-C 공식 소개](https://www.pokemon.com/us/news/get-ready-for-regulation-set-m-c-in-pokemon-champions)
- [Pokémon Showdown Champions 모드](https://github.com/smogon/pokemon-showdown/tree/master/data/mods/champions)
- [PokéAPI API 문서](https://pokeapi.co/docs/v2)
- [고정한 PokéAPI 데이터 커밋](https://github.com/PokeAPI/pokeapi/tree/17dd3092872cabcb7c008051771d2a2fd8c8c260)

재배포되는 한국어 데이터의 라이선스는 [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md)에 기록했습니다.

## 검증

```bash
pnpm check
pnpm test
pnpm build
```

테스트는 Champions 스탯 공식, 준속·최속 구간, 메가진화와 날씨, 16개 난수, 흡수 특성, 기합의띠, 스카프·랭크·트릭룸, 잘못된 스탯 포인트를 고정 검증합니다. 또한 완전한 한국어 매치업, 한국어 폼·상태·날씨, Champions 전용 메가폼, 현재 Champions 표준 Dex 전체의 한국어 이름 누락 여부를 검사합니다.

## 라이선스

프로젝트 코드는 [MIT License](./LICENSE)로 배포됩니다. 별도로 고지된 제3자 데이터와 상표에는
[THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md)의 조건이 적용됩니다.