Skip to main content
Glama
mingun-kim

MTGDecks Metagame MCP Server

by mingun-kim
README.md
# MTGDecks Metagame MCP

[MTGDecks.net](https://mtgdecks.net)의 공개 페이지를 읽어 메타게임과 덱 정보를 일관된 JSON 형태로 정규화하는 Python/MCP PoC입니다.

문서화된 공개 API가 확인되지 않아 사이트의 공개 HTML과 URL 기반 필터를 사용합니다. 브라우저 로그인이나 쿠키는 필요하지 않습니다.

## 제공 기능

```python
get_metagame(
    format: str,
    source: str = "all",
)

get_recent_decks(
    format: str,
    platform: str | None = None,
    game_type: str | None = None,
    max_pages: int = 3,
)

get_archetype_decks(
    format: str,
    archetype: str,
    limit: int = 20,
)

get_top_performing_decks(
    format: str,
    platform: str | None = None,
    min_players: int | None = None,
    limit: int = 20,
)
```

각 기능은 Python 함수와 MCP 도구로 모두 제공됩니다.

## 요구 사항

- Python 3.10 이상
- [`uv`](https://docs.astral.sh/uv/) 권장

## 설치

```powershell
git clone <repository-url>
cd Metagame-MCP
uv sync
```

개발 및 테스트 의존성까지 설치하려면 다음 명령을 사용합니다.

```powershell
uv sync --extra dev
```

## MCP 서버 실행

서버는 기본적으로 stdio 전송 방식으로 실행됩니다.

```powershell
uv run mtgdecks-mcp
```

MCP 호스트 설정 예시는 다음과 같습니다. `cwd`는 이 저장소의 실제 절대 경로로 변경해야 합니다.

```json
{
  "mcpServers": {
    "mtgdecks": {
      "command": "uv",
      "args": ["run", "mtgdecks-mcp"],
      "cwd": "C:\\path\\to\\Metagame-MCP"
    }
  }
}
```

등록되는 MCP 도구는 다음 네 개입니다.

- `get_metagame`
- `get_recent_decks`
- `get_archetype_decks`
- `get_top_performing_decks`

## Python에서 사용

```python
from mtgdecks_mcp import (
    get_archetype_decks,
    get_metagame,
    get_recent_decks,
    get_top_performing_decks,
)

metagame = get_metagame("Modern", source="mtgo")

recent = get_recent_decks(
    "Modern",
    platform="mtgo",
    game_type="BO3",
    max_pages=1,
)

archetype = get_archetype_decks(
    "Modern",
    "Boros Energy",
    limit=5,
)

top = get_top_performing_decks(
    "Modern",
    platform="mtgo",
    min_players=64,
    limit=10,
)
```

여러 번 조회할 때는 HTTP 연결을 재사용할 수 있도록 클라이언트를 직접 사용하는 편이 효율적입니다.

```python
from mtgdecks_mcp import MTGDecksClient

with MTGDecksClient() as client:
    modern = client.get_metagame("Modern")
    pioneer = client.get_metagame("Pioneer")
```

## 인자

### `format`

MTGDecks.net에서 사용하는 포맷 이름입니다. 예: `Standard`, `Pioneer`, `Modern`, `Legacy`, `Pauper`, `Commander`, `Duel-Commander`.

### `source`

| 값 | 의미 |
| --- | --- |
| `all` | 전체 메타게임 |
| `mtgo` | MTGO 이벤트 메타게임 |
| `major` | 최근 주요 이벤트 메타게임 |

`mtgo-events`, `major-events`, `recent-major-events`도 별칭으로 사용할 수 있습니다.

### `platform`

- `mtgo`
- `arena`
- `tabletop`

대소문자는 구분하지 않습니다.

### `game_type`

- `BO1`
- `BO3`

대소문자는 구분하지 않습니다.

### 조회 범위 제한

- `max_pages`: `1`~`10`
- `limit`: `1`~`100`
- `min_players`: 양의 정수

## 응답 구조

### 메타게임

```json
{
  "format": "Modern",
  "source": "all",
  "url": "https://mtgdecks.net/Modern",
  "selected_deck_count": 10994,
  "updated_at": "2026-08-21 06:47:39",
  "archetypes": [
    {
      "name": "Boros Energy",
      "url": "https://mtgdecks.net/Modern/boros-energy",
      "meta_share_percent": 7.98,
      "trend_percent": -2.85,
      "tier": "A",
      "win_rate_percent": 49.0,
      "top_25_conversion": 0.95,
      "deck_count": 877,
      "price_usd": 1109.0
    }
  ]
}
```

### 덱 목록

덱 조회 기능은 공통적으로 `pages`와 `decks`를 반환합니다. `pages`에는 실제로 조회한 원본 페이지 URL이 들어갑니다.

```json
{
  "format": "Modern",
  "pages": ["https://mtgdecks.net/Modern/decklists/page:1"],
  "decks": [
    {
      "name": "deck",
      "url": "https://mtgdecks.net/Modern/example-decklist-123",
      "author": "Player",
      "archetype": "Boros Energy",
      "game_type": "BO3",
      "platform": "mtgo",
      "event": "MTGO Modern Challenge",
      "event_level": 3,
      "players": 94,
      "spiciness_percent": 30.0,
      "date": "2026-08-20",
      "price_usd": 1112.0,
      "placement": "1st",
      "wins": 5,
      "losses": 0,
      "draws": 0,
      "win_rate_percent": 100.0
    }
  ]
}
```

MTGDecks 페이지에서 값을 제공하지 않는 필드는 `null`일 수 있습니다. 가격은 페이지의 Paper/TCGPlayer 기준 USD 값입니다.

`get_top_performing_decks`는 자체 성과 점수를 계산하지 않고 MTGDecks의 `rank` 오름차순 정렬을 사용합니다. 따라서 우승, 준우승, Top 8 등의 이벤트 성적이 좋은 덱부터 반환됩니다.

## 테스트

```powershell
uv run pytest
```

테스트는 외부 사이트에 접속하지 않고 저장된 HTML 예시와 `httpx.MockTransport`를 사용합니다.

## 프로젝트 구조

```text
src/mtgdecks_mcp/
├── __init__.py   # 공개 Python API
├── parsers.py    # MTGDecks HTML 정규화
├── server.py     # MCP 도구 등록과 stdio 서버
└── service.py    # URL 구성, HTTP 클라이언트, 네 가지 기능

tests/
├── test_parsers.py
└── test_service.py
```

## 제한 사항과 이용 조건

- 이 프로젝트는 공개 HTML 구조에 의존하므로 MTGDecks.net의 마크업이나 경로가 변경되면 파서 수정이 필요할 수 있습니다.
- 대량 크롤링, 병렬 수집, 캐시/데이터베이스 영속화는 PoC 범위에 포함하지 않았습니다.
- 원본 데이터의 정확성과 가용성은 MTGDecks.net에 의존합니다.
- 모든 정규화 결과에는 추적 가능한 원본 URL을 포함합니다.
- MTGDecks 이용약관은 콘텐츠를 개인·비상업적 용도로 제한합니다. 상업 서비스나 지속적인 대량 수집으로 확장하기 전에 MTGDecks 측의 허락 또는 API 파트너십을 확인하십시오.

관련 문서: [MTGDecks 이용약관](https://mtgdecks.net/pages/terms)

TDQS

B3.4/5.0

Scored across 4 tools

Disambiguation4/5

The tools are mostly distinct: get_metagame provides aggregate archetype shares, get_recent_decks provides unfiltered recent deck lists, get_archetype_decks filters recent decks by a specific archetype, and get_top_performing_decks sorts by finish. However, get_recent_decks and get_archetype_decks both return recent decks and could be confused when a user wants all decks versus a single archetype.

Naming Consistency5/5

All four tool names follow a consistent get_ prefix with snake_case, and three use the get_<adjective>_decks pattern. get_metagame is the only outlier, but it still shares the verb-first style and is clear and predictable.

Tool Count5/5

Four tools is a well-scoped count for a metagame analysis server. Each tool addresses a distinct query need without unnecessary bloat or minimalism, fitting comfortably within the ideal 3-15 range.

Completeness4/5

The tool surface covers the core metagame queries: aggregate shares, all recent decks, archetype-filtered decks, and top performers. Minor gaps like deck detail lookup or archetype listing exist, but agents can answer most metagame questions using these four tools.

Maintenance

ActivityMaintained
ResponsivenessNo issues