# LLM이 도구를 직접 호출(MCP)

> tools/war3_mcp.py는 MCP 서버입니다. Claude Code, Claude Desktop 또는 MCP를 지원하는 어떤 클라이언트든 이 서버를 연결하면, LLM이 코드를 먼저 쓰지 않고도 게임 상황을 보고, 명령을 내리고, 화면에서 플레이어에게 말하고, 카드를 띄워 플레이어에게 묻고, 스크린숏으로 화면을 볼 수 있습니다.

출처: https://war3ai.com/ko/docs/mcp/

`tools/war3_mcp.py`는 **MCP 서버**(stdio)입니다. Claude Code, Claude Desktop, 로컬 모델의 Agent 프레임워크 — MCP를 지원하는 어떤 클라이언트든 이 서버를 연결하면, LLM이 코드를 먼저 쓰지 않고도 **직접** 게임 상황을 보고, 명령을 내리고, 게임 화면에서 플레이어에게 말하고, 플레이어에게 묻고, 스크린숏으로 화면을 볼 수 있습니다.

Bot 작성, 참모, 유닛 대사에 이은 또 하나의 연결 방식입니다. **LLM이 스스로 도구의 사용자가 됩니다.**

## 연결하기

```bash
claude mcp add war3 -- python <저장소>\tools\war3_mcp.py --inst 9      # Claude Code. <저장소>는 자신의 openwar3 폴더로 바꾸세요
```

다른 클라이언트는 이 형식으로 설정을 씁니다.

```json
{"mcpServers": {"war3": {"command": "python", "args": ["<저장소>\\tools\\war3_mcp.py", "--inst", "9"]}}}
```

처음 도구를 호출할 때 게임에 연결하므로, 게임은 나중에 켜도 됩니다. 게임을 껐다가 다시 켜면 다음 호출 때 자동으로 다시 연결합니다. `--role`을 붙여 LLM이 할 수 있는 일을 제한합니다.

| 역할 | 쓸 수 있는 것 |
|---|---|
| `dev`(기본값) | `war3_jass`를 포함한 모든 도구 |
| `player --player N` | N번 플레이어의 유닛만 지휘하고, 그 시야만 볼 수 있음(공정 모드). JASS 없음 |
| `observer` | 읽기 전용, 화면에 그릴 수 없고 유닛이 말하게 할 수도 없음. 내린 명령은 런타임이 바로 거부 |

`player` 역할의 제한은 [게이트웨이](https://war3ai.com/ko/docs/gateway/)와 같습니다. 게임 종료, 속도 변경, 일시 정지를 쓸 수 없고, 다른 플레이어의 패를 볼 수 있는 API도 쓸 수 없으며, 플레이어 번호를 받는 조회는 자기 자신만 조회할 수 있습니다.

몇 가지 상한: 도구 결과 하나는 최대 20만 자이며, 넘으면 잘라 내고 범위를 좁히는 방법을 알려 줍니다. `war3_ask_player`는 최대 120초까지 기다립니다. 스크린숏의 `scale`은 0.1에서 1 사이입니다.

## 도구

| 도구 | 하는 일 |
|---|---|
| `war3_overview` | 게임 상황 한 페이지: 시간, 자원, 식량, 아군 유닛 종류별 수, 영웅(체력, 마나, 레벨, 쿨다운), 보이는 적 유닛 종류, 생산. **이것부터 호출하세요** |
| `war3_units` | 유닛 목록(`owner`는 me / enemy / creep / all, `types`로 필터링). `addr`로 명령을 내림 |
| `war3_events` | 지난 호출 이후 일어난 일: 사망, 레벨 업, 시전, 생산 완료, 채팅, 플레이어가 버튼을 클릭함……(기본적으로 너무 자주 발생하는 몇 종류는 제외) |
| `war3_call` | 아무 공개 API나 호출(`move`, `attack_move`, `train`, `build`, `cast`, `learn`, `ui.button`, `canvas.text`……). 유닛은 `{"unit": addr}`로 씀 |
| `war3_api` | API 조회: 키워드로 이름과 설명을 검색 |
| `war3_toast` / `war3_say` | 화면 위쪽에 한 줄 표시 / 유닛 머리 위에 한 마디 |
| `war3_ask_player` | 화면 가운데에 선택 카드 몇 장을 띄우고, 플레이어가 클릭하기를 기다렸다가 무엇을 골랐는지 반환(게임 일시 정지 가능) |
| `war3_screenshot` | 게임 화면 스크린숏(PNG. 창이 가려져 있어도 찍을 수 있고, 포커스를 빼앗지 않음) |
| `war3_jass` | JASS 코드 실행(dev 전용. 월드 변경은 싱글플레이 게임에서만) |

이런 것을 할 수 있습니다.

- **같이 플레이 / 코치**: `war3_overview`로 게임 상황을 보고, `war3_toast`로 화면에 조언을 띄움
- **플레이하면서 플레이어에게 묻기**: `war3_ask_player`로 카드 세 장을 띄우고, 플레이어가 고른 대로 진행
- **해설**: `war3_events`로 무슨 일이 있었는지 읽고, `war3_say`로 유닛이 직접 말하게 함
- **부대 하나를 직접 지휘**: `player` 역할 + `war3_call`. 자기 유닛만 움직일 수 있음
- **화면을 보며 UI 조정**: `war3_screenshot`으로 한 장 찍어, 직접 그린 버튼이 제자리에 있는지 확인

## 대화는 대략 이렇게 흘러갑니다

```text
나: 지금 게임 상황을 보고, 화면에서 나한테 물어봐 줘. 다음은 멀티, 병력 생산, 본진 업그레이드 중 뭘로 할까?

→ war3_overview      {}
← 게임 상황 한 페이지: 게임 시간, 금 500, 식량 10/12, 아군 htow 1 · hpea 5 · Hpal 1, 보이는 적 없음, 생산 중인 것 없음
→ war3_ask_player    {"question": "다음은?", "options": ["병력 생산", "멀티", "본진 업그레이드"], "pause": true}
← {"picked": 1, "option": "멀티"}

모델: 멀티를 고르셨네요. 먼저 war3_units로 놀고 있는 일꾼을 하나 찾고, 가장 가까운 금광이 어디인지 볼게요……
```

## 실측

2026-09-25:

- 자체 MCP 클라이언트로 실제 게임에 연결, 7/7: 핸드셰이크 → 도구 나열(10개) → `war3_overview`(`htow` 1, `hpea` 5) → `war3_units` → `war3_toast` → `war3_screenshot`(PNG 약 20만 바이트) → `war3_ask_player`(카드 세 장, 두 번째 카드 클릭을 시뮬레이션 → `{"picked": 1, "option": "멀티"}`).
- Claude Code 2.1에 실제로 연결: Claude Code가 직접 서버를 띄우고 핸드셰이크했으며, 상태는 `connected`, 도구 10개가 모두 `mcp__war3__*`로 도구 목록에 나타났습니다.

## 구현

- 줄바꿈으로 구분한 JSON-RPC 2.0(`initialize` / `tools/list` / `tools/call` / `ping`), 프로토콜 버전 2025-06-18, 2025-03-26과 2024-11-05도 호환.
- 도구 오류는 MCP 규칙에 따라 결과 안에 담으며(`isError: true`), 연결을 끊지 않습니다.
- [게이트웨이](https://war3ai.com/ko/docs/gateway/)와 같은 역할 화이트리스트, 유닛 인자 형식, "게임 상황 한 페이지"를 공유합니다.
- 로그는 stderr로 보내고, stdout에는 프로토콜만 씁니다.
