Skip to main content
Glama
w3bKodr

PokéWallet MCP

by w3bKodr
README.md
<div align="center">

![PokéWallet MCP hero](docs/assets/pokewallet-mcp-hero.png)

# PokéWallet MCP

### Point your vision model at a card. Get the exact printing—not a confident guess.

[![Python 3.11+](https://img.shields.io/badge/Python-3.11%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
[![MCP](https://img.shields.io/badge/Model_Context_Protocol-ready-5D5FEF)](https://modelcontextprotocol.io/)
[![License: MIT](https://img.shields.io/badge/License-MIT-2ea44f)](LICENSE)
[![Transport](https://img.shields.io/badge/Transport-stdio_%7C_HTTP-00B8D9)](#run-it)

**Vision-guided Pokémon TCG identification, exact-variant price matching, set research, and local collection tools for standards-compliant MCP clients.**

</div>

PokéWallet MCP fixes the dangerous gap between “that looks like a Charizard” and “this is the 1st Edition Shadowless holo printing.” It combines a vision-capable OpenAI-compatible model with PokéWallet catalog data, ranks candidate printings, validates visible edition and foil evidence, and returns only marketplace variants supported by the photo.

## Why collectors need exact-variant matching

Cards sharing the same name and collector number can have radically different values. Edition stamps, foil coverage, holo patterns, regional printings, distribution stamps, and known error markers all matter. A normal name search cannot safely resolve those differences.

PokéWallet MCP uses a staged pipeline:

```text
local photo
  → safe decode + orientation contact sheets
  → structured visual evidence
  → PokéWallet catalog candidates
  → metadata ranking + reference-image verification
  → strict marketplace-variant selection
  → confidence, uncertainty, and data-quality warnings
```

It does **not** authenticate cards, assign a condition or grade, or promise a sale value. It identifies visible printing evidence and keeps uncertainty visible.

## Built for the details that change the price

| Evidence family | Recognized examples |
|---|---|
| Edition and print run | 1st Edition, Unlimited, Shadowless, no-edition mark, `1999–2000` copyright line |
| Core finishes | normal, holofoil, reverse holofoil |
| Foil coverage | artwork-only, card-body, full-card, selective |
| Reverse patterns | Poké Ball, Master Ball, Legendary Collection fireworks, Energy symbol, type symbol, set-logo, gold-border |
| Holo patterns | standard/plain, Cosmos, Galaxy Star, Galaxy, Cracked Ice, Line, Confetti, Etched, Textured, Rainbow |
| Distribution variants | Black Star Promo, Prerelease, STAFF, Pokémon Center, retailer exclusive, League, Winner, World Championships, theme-deck, blister, gift-with-purchase, stamped promo |
| Cautious error markers | gray/ghost stamp, no-symbol, Black Dot, No Damage, evolution/text errors |

Specific evidence is strict. If the image shows a Master Ball reverse pattern, a generic Reverse Holo price is not silently substituted. If it shows Cracked Ice, a generic Holofoil row is not treated as equivalent. Possible error-card markers improve candidate ranking but remain explicitly tentative until independently authenticated.

### Dynamic photos, not scanner-perfect inputs

The image pipeline accepts local paths or base64 data and builds multiple evidence views:

- EXIF-aware orientation correction
- multi-scale, card-aspect region proposals that magnify cards embedded in screenshots or wide scenes
- 0°, 90°, 180°, and 270° views
- high-resolution full-card views plus focused detail crops
- skew/perspective reporting and robust contact sheets
- bounded pixel count, byte size, and image edge length
- optional allowed-root enforcement for local image paths

Acceptance testing includes upright, sideways, upside-down, and crooked card photos. No OpenCV or GPU-heavy detector is required for preprocessing; Pillow prepares the views and your configured vision model performs the visual analysis.

## Real Hermes result

This abridged screenshot was rendered from the live Hermes acceptance test using the photographed Base Set Charizard. Hermes loaded the portable skill, discovered and called `mcp__pokewallet__analyze_pokemon_card`, detected the circular 1st Edition stamp at 100% focused-pass confidence, selected **1st Edition Holofoil**, rejected the Unlimited row, and surfaced inconsistent marketplace fields instead of presenting a misleading number.

![Abridged live Hermes MCP output identifying a 1st Edition Shadowless Charizard](docs/assets/hermes-identification-output.png)

### Natural-language valuation in action

Ask a plain-language question with a card image and the agent can resolve the printing, query PokéWallet marketplace data, keep USD and EUR sources separate, and explain the result in collector-friendly language.

![PokéWallet MCP answering a natural-language Pikachu ex value question](docs/assets/pokewallet-pikachu-natural-language.png)

Marketplace figures are point-in-time source data, not an appraisal. Condition, authenticity, and grade still require independent evaluation.

The structured response includes the evidence—not just the answer:

```json
{
  "status": "likely",
  "identified_card": {
    "name": "Charizard",
    "collector_number": "004/102",
    "set": {"name": "Base Set (Shadowless)"}
  },
  "detected": {
    "edition_guess": "first_edition",
    "finish_guess": "holofoil",
    "foil_pattern_guess": "standard_holofoil",
    "visible_stamps": ["EDITION 1"],
    "field_confidence": {"edition_guess": 1.0}
  },
  "edition_evidence": {
    "edition_guess": "first_edition",
    "visible_stamp_text": ["EDITION 1"],
    "confidence": 1.0
  },
  "matched_price_variants": [{
    "source": "tcgplayer",
    "currency": "USD",
    "variant": {"name": "1st Edition Holofoil"},
    "data_quality_warnings": [
      "Marketplace fields are internally inconsistent; verify recent sold listings."
    ]
  }]
}
```

## Feature set

- **40 MCP tools** for cards, sets, prices, analytics, local collections, watchlists, status, and image identification
- **8 resources** for cards, localized card images, sets, set logos, collection, and watchlist data
- **4 prompts** for image identification, card research, printing comparison, and set browsing
- A standards-based **Agent Skill** with trigger-rich natural-language routing instructions
- MCP initialization instructions and a single high-level `analyze_pokemon_card` entry point that are independent of client-specific tool prefixes
- Exact collector-number parsing for standard, alphanumeric, fraction, promo, and leading-zero formats
- Candidate scoring from title, collector number, set code, HP, stage, visible stamps, variant markers, and possible errors
- Reference-image verification when metadata alone cannot separate nearby printings
- Per-source price variants with TCGPlayer USD and Cardmarket EUR kept separate
- A machine-readable `answer_policy` that forbids harnesses from adding outside auction, grading, sold-listing, or memory-based prices
- Explicit ambiguity states: `confirmed`, `likely`, `ambiguous`, and `not_found`
- Batch image identification, bounded concurrency, caching, retry/backoff, and structured errors
- Local SQLite collection/watchlist storage with JSON and CSV export
- stdio and Streamable HTTP transports
- Non-root Docker image and loopback-only Compose port binding

## Quick start

Requirements:

- Python 3.11 or newer
- [uv](https://docs.astral.sh/uv/)
- A PokéWallet API key
- For image identification, an OpenAI-compatible **vision** endpoint and a vision-capable model

```bash
git clone <your-repository-url>
cd poke-mcp
uv sync --extra dev
cp .env.example .env
```

On PowerShell, use `Copy-Item .env.example .env` for the final command. Then edit `.env`:

```dotenv
POKEWALLET_API_KEY=your_key_here
VISION_API_BASE=http://127.0.0.1:1234/v1
VISION_API_KEY=your_local_provider_key_if_required
VISION_MODEL=your_vision_model_alias
VISION_TIMEOUT_SECONDS=600
VISION_MAX_TOKENS=3000
VISION_DISABLE_THINKING=true
```

Use the model alias exposed by the local provider, not a raw model filename. Some runtimes attach the vision projector only through that alias; selecting the GGUF directly can leave the GPU idle and make image requests behave like text-only calls.

### API keys and secrets

1. Copy `.env.example` to `.env`; never rename or edit `.env.example` with real credentials.
2. Set `POKEWALLET_API_KEY`. This is the only required API credential for text/catalog operations.
3. Set `VISION_MODEL` for image identification, plus `VISION_API_BASE` when the provider is not on the default local URL.
4. Set `VISION_API_KEY` only when the vision provider requires authentication. Local servers commonly accept an empty value; hosted providers usually do not.
5. Keep client configuration examples on `${POKEWALLET_API_KEY}` and `${VISION_API_KEY}` placeholders. Do not paste real keys into committed JSON, YAML, screenshots, or shell scripts.

The included `.gitignore` excludes `.env`, `.env.*`, caches, databases, exports, logs, and local virtual environments while explicitly allowing the safe `.env.example` template. `--check-config` reports only whether keys are configured; it does not print them.

Validate before connecting a client:

```bash
uv run pokewallet-mcp --check-config
uv run pokewallet-mcp --health-check
```

## Universal natural-language routing

PokéWallet's portable routing layer lives in the MCP server, not in a Pi, Hermes, Discord, or other frontend adapter:

1. During the standard MCP initialization handshake, the server sends a routing contract telling the client to call `analyze_pokemon_card` for card-photo identification or value questions.
2. `analyze_pokemon_card` is an explicitly titled, read-only, idempotent high-level tool. Its description contains the complete selection rule and works even when a client adds its own prefix to tool names.
3. [`skills/pokewallet-card-analysis/SKILL.md`](skills/pokewallet-card-analysis/SKILL.md) packages the same workflow in the open Agent Skills format. Any Agent Skills-compatible harness can load that one unchanged skill; only the harness's discovery/install location varies.

No client-specific routing adapter is required for this portable path. Connect the MCP server and, if the harness supports Agent Skills, copy or link `skills/pokewallet-card-analysis` into that harness's normal skills directory. Configure the harness to preload or auto-activate that skill for card-image conversations when its skill implementation requires it. The skill name, content, and MCP tool-selection logic stay unchanged across harnesses; only installation/discovery/activation is harness-owned.

There is one unavoidable protocol boundary: MCP servers do not receive raw chat turns or attachments until the client calls a tool. The MCP specification permits clients to use server initialization instructions, but cannot force them to do so. The client must also expose the attachment as a real path or base64 payload. A client that discards MCP instructions, never selects tools, or hides attachment bytes cannot be made automatic by server code or a skill; that client needs its own routing fix.

## Install on Hermes

The included installer is idempotent and production-safe: it finds the project virtual environment, adds or updates only the `pokewallet` MCP entry, installs the unchanged portable Agent Skill into Hermes's standard `skills` directory, mirrors non-secret project settings, backs up Hermes configuration and any previous skill copy, copies secrets into Hermes's private `.env`, and leaves `${...}` placeholders in YAML. It never prints API keys.

### Windows PowerShell

```powershell
Copy-Item .env.example .env
# Configure .env first, then:
uv run python scripts/install_hermes.py `
  --project . `
  --hermes-home "$env:LOCALAPPDATA\hermes"

hermes gateway restart
```

### macOS or Linux

```bash
cp .env.example .env
# Configure .env first, then:
uv run python scripts/install_hermes.py --project . --hermes-home "$HOME/.hermes"
hermes gateway restart
```

Hermes advertises installed skill metadata to the model, but some local models may start generic vision in parallel with `skill_view` before reading the skill body. Preload the standard skill so its instructions are active before first-turn tool selection:

```bash
hermes chat --skills pokewallet-card-analysis
```

You can also use `-s pokewallet-card-analysis` with a one-shot `hermes chat -q ...` invocation. For a Discord or Slack gateway channel, use Hermes's built-in `channel_skill_bindings` with that channel's ID:

```yaml
discord:
  channel_skill_bindings:
    - id: "YOUR_CHANNEL_ID"
      skills: ["pokewallet-card-analysis"]
```

Once preloaded through Hermes's standard Agent Skill activation mechanisms, natural-language requests such as “what is this Pokémon card worth?” discover deferred MCP tools when necessary and call the high-level analyzer without generic vision or web valuation.

Verify from the Hermes environment:

```bash
python scripts/verify_hermes.py
```

Hermes should report registered `pokewallet` entries and `hermes skills list` should show `pokewallet-card-analysis` as enabled. Then launch **Hermes itself** with the skill preloaded, give it a local card image, and ask it to identify the exact printing and matched marketplace variant. Discord is only a frontend if your Discord bot routes to that Hermes instance; use a standard channel skill binding when you want the same preload there.

## Install in other MCP clients

Any client that supports stdio MCP servers can launch the package directly. Use absolute paths because desktop clients often start outside the repository.

### Generic `mcpServers` configuration

```json
{
  "mcpServers": {
    "pokewallet": {
      "command": "/absolute/path/to/poke-mcp/.venv/bin/python",
      "args": ["-m", "pokewallet_mcp", "--transport", "stdio"],
      "env": {
        "POKEWALLET_API_KEY": "${POKEWALLET_API_KEY}",
        "VISION_API_BASE": "http://127.0.0.1:1234/v1",
        "VISION_API_KEY": "${VISION_API_KEY}",
        "VISION_MODEL": "your_vision_model_alias",
        "VISION_TIMEOUT_SECONDS": "600",
        "VISION_MAX_TOKENS": "3000",
        "VISION_DISABLE_THINKING": "true"
      }
    }
  }
}
```

On Windows, `command` will usually end in `.venv\\Scripts\\python.exe`. The same shape works with clients such as Claude Desktop, Cursor, Windsurf, and VS Code MCP integrations; use the configuration location and environment-variable syntax required by that client. Avoid pasting real keys into a committed JSON file.

For any harness that implements Agent Skills, also copy or link this repository's `skills/pokewallet-card-analysis` directory into its documented skill search path and use that harness's normal auto-activation or preload setting. Harnesses that automatically expand a matching skill need no extra rule; harnesses that expose only metadata until the model calls `skill_view` should preload it to prevent a first-turn generic-vision race. Harnesses that do not implement Agent Skills can still use the MCP initialization instructions and high-level tool. No Pi adapter, Discord adapter, or client-specific Python router is part of this project.

### Streamable HTTP

```bash
uv run pokewallet-mcp --transport streamable-http
```

The default endpoint binds to `127.0.0.1:8765`. For a containerized local deployment:

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

## Configuration

All settings are environment variables. `.env.example` is safe to commit; `.env` and `.env.*` are ignored, with an explicit exception for `.env.example`.

| Variable | Default | Purpose |
|---|---:|---|
| `POKEWALLET_API_KEY` | empty | Required PokéWallet credential |
| `POKEWALLET_BASE_URL` | `https://api.pokewallet.io` | API origin |
| `POKEWALLET_TIMEOUT_SECONDS` | `30` | API timeout, maximum 300 seconds |
| `POKEWALLET_ENABLE_PRO` | `false` | Enables Pro-only endpoints |
| `VISION_API_BASE` | `http://127.0.0.1:1234/v1` | OpenAI-compatible vision API |
| `VISION_API_KEY` | empty | Vision-provider credential, if required |
| `VISION_MODEL` | empty | Provider's vision-capable model alias |
| `VISION_TIMEOUT_SECONDS` | `600` in example | Vision request timeout, maximum 600 seconds |
| `VISION_MAX_TOKENS` | `3000` in example | Structured extraction response budget |
| `VISION_TEMPERATURE` | `0.0` | Deterministic extraction temperature |
| `VISION_DISABLE_THINKING` | `true` in example | Requests direct JSON from compatible local models |
| `CARD_IMAGE_MAX_MB` | `15` | Input byte limit |
| `CARD_IMAGE_MAX_PIXELS` | `40000000` | Decompression-bomb guard |
| `CARD_IMAGE_MAX_EDGE` | `1600` | Prepared-image edge limit |
| `ALLOWED_IMAGE_ROOTS` | empty | Comma-separated local path allowlist |
| `MCP_TRANSPORT` | `stdio` | `stdio` or `streamable-http` |
| `MCP_HOST` / `MCP_PORT` | `127.0.0.1` / `8765` | HTTP bind address |
| `CACHE_ENABLED` | `true` | In-memory and image caching |
| `COLLECTION_ENABLED` | `true` | Local collection/watchlist tools |
| `COLLECTION_DATABASE_PATH` | platform data dir | SQLite database location |
| `COLLECTION_EXPORT_DIRECTORY` | platform data dir | JSON/CSV export destination |

## Tool map

| Area | Tools |
|---|---|
| Identification | `analyze_pokemon_card`, `identify_card_from_image`, `identify_cards_from_images`, `resolve_card` |
| Card discovery | `search_cards`, `search_card_by_name`, `find_card_by_number`, `batch_search_cards`, `get_card` |
| Prices and comparisons | `get_card_prices`, `summarize_card_value`, `compare_card_prices`, `compare_printings`, `compare_cards` |
| Images | `get_card_image` plus image resources |
| Sets | `list_sets`, `search_sets`, `get_set`, `get_set_cards`, `get_complete_set_cards`, `get_set_image` |
| Analytics | set statistics, trending sets, completion value, set prices, price history, top cards |
| Collection | add/update/remove/list/value/export/summary |
| Watchlist | add/remove/list/check |
| Operations | `pokewallet_health`, `pokewallet_api_info` |

## How exact identification works

1. The server rejects remote URLs and safely decodes a local path or base64 image.
2. It proposes colorful, detailed card-shaped regions at multiple scales, allowing a card to be recovered from a screenshot or wide scene without a heavyweight CV dependency.
3. It normalizes EXIF orientation, generates rotated full-card views, and creates targeted crops for fine print, stamps, set symbols, and foil evidence.
4. The vision model returns a strict schema with confidence per field, visible markers, and uncertainties.
5. PokéWallet candidates are ranked by stable metadata and visible variant evidence.
6. Close candidates can be compared against reference card images.
7. A targeted variant pass inspects edition, finish, foil pattern/coverage, distribution stamps, and possible error markers.
8. Early Wizards cards receive an isolated upright edition close-up so a visible circular `EDITION 1` stamp can override an incorrect Unlimited guess without confusing rarity or energy symbols.
9. Marketplace variants that conflict with observed evidence are removed. The response carries only supported rows, preserved currencies, ambiguity flags, and source-data warnings.

## Security posture

- No API key is hard-coded in application code, examples, screenshots, Docker files, or Hermes YAML.
- `.env`, `.env.*`, databases, caches, logs, exports, test environments, IDE metadata, and OS junk are ignored.
- The Hermes installer reads secrets from the project `.env`, writes them only to the private Hermes `.env`, installs the portable skill, and creates timestamped backups.
- Configuration/status output reports only booleans such as `api_key_configured`; it never returns secret values.
- Image tools reject remote URLs, enforce decoded-image limits, and can restrict access to explicit filesystem roots.
- HTTP transport binds to loopback by default; the Docker Compose port is also loopback-only.
- Collection exports are constrained to the configured export directory.

Before publishing a fork, run a secret scan appropriate for your organization. A useful local baseline is:

```bash
git grep -nEi '(api[_-]?key|token|secret|password).{0,30}[=:].{0,5}[A-Za-z0-9_-]{16,}' -- ':!README.md' ':!.env.example'
```

## Tests

```bash
uv run ruff check .
uv run ruff format --check .
uv run pytest -q
```

Live tests are opt-in because they call external services:

```bash
POKEWALLET_RUN_LIVE_TESTS=1 uv run pytest -m integration -q
```

Utility scripts under `scripts/` cover transport smoke tests, live identification, focused edition detection, prepared-sheet inspection, orientation fixtures, vision diagnostics, Hermes installation, and Hermes MCP registration.

## Research and design references

The implementation uses original code, but the photo strategy and variant taxonomy were checked against existing open-source scanners and collector references:

- [MCP lifecycle specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle) defines portable server `instructions` in the initialization response.
- [Agent Skills specification](https://agentskills.io/specification) defines the portable `SKILL.md` package included in this repository.
- [1vcian/Pokemon-TCGP-Card-Scanner](https://github.com/1vcian/Pokemon-TCGP-Card-Scanner) demonstrates contour/aspect-ratio scanning, perceptual matching, oriented bounding boxes, and synthetic rotation/perspective augmentation. PokéWallet MCP adopts the resilience goals without adding its YOLO/OpenCV runtime.
- [hugopeixoto/ptcg-detection](https://github.com/hugopeixoto/ptcg-detection) explores perceptual hashes and set-symbol templates; this server instead combines structured vision with catalog candidates so it is not locked to a single camera resolution or template library.
- [OpenCV card-scanner example](https://gist.github.com/D31T4/af49aaa110523015f80862d1d25482fd) informed the perspective/skew threat model.
- [TCGplayer's rarity guide](https://help.tcgplayer.com/hc/en-us/articles/360025636074-What-are-the-rarities-of-Pok%C3%A9mon-TCG-cards) documents collector numbers, promo stars, and holo versus reverse-holo distinctions.
- [CGC's Pokémon variant guide](https://www.cgccards.com/news/article/8591/pokemon-variants/) documents gray/ghost stamps, Cosmos Machamp, No Damage Ninetales, Black Dot Charizard, evolution errors, and the `1999–2000` print run.
- [CGC's Jungle No Symbol guide](https://www.cgccards.com/news/article/14903/cards-registry-jungle-no-symbol/) covers the missing-set-symbol variant.
- [Bulbapedia's holofoil guide](https://bulbapedia.bulbagarden.net/wiki/Holofoil) catalogs Cosmos, Cracked Ice, set-logo, symbol, gold-border, and other historical patterns.
- [Pokémon Card 151](https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_Card_151_%28TCG%29) documents the distinct Poké Ball and rarer Master Ball mirror-holo patterns in supported Asian-language releases.
- [Prerelease Cards](https://bulbapedia.bulbagarden.net/wiki/Prerelease_Cards_%28TCG%29) covers `PRERELEASE`, expansion-logo, and `STAFF` stamps.

These are visual-identification references, not price sources. Price responses come from the configured PokéWallet API and retain its marketplace/source metadata.

## Limitations

- A single photo often cannot prove authenticity, card stock, surface condition, or exact grade.
- Sleeve glare, compression, shadows, and a missing back photo can hide foil or counterfeit indicators.
- Foil-pattern classification is only as reliable as the image and the configured vision model.
- Error-card markers are reported as possible variants, never certified errors.
- Marketplace data may be stale or internally inconsistent; warnings must be preserved and recent sold listings should be independently verified for consequential decisions.
- Natural-language auto-routing depends on the MCP client honoring server instructions and making attachments available to tool arguments; MCP cannot intercept the client's raw chat input.

## License and trademarks

[MIT](LICENSE). The generated project artwork is original and intentionally avoids official character art, card backs, logos, and trademarked ball symbols.

Pokémon and related names are trademarks of their respective owners. PokéWallet MCP is an independent integration and is not affiliated with, endorsed by, or sponsored by Nintendo, Creatures, GAME FREAK, The Pokémon Company, TCGplayer, Cardmarket, or PokéWallet.

TDQS

B3/5.0

Scored across 40 tools

Disambiguation4/5

Most tools have clearly distinct purposes, such as get_card vs get_card_prices vs summarize_card_value, and search_cards vs search_card_by_name vs find_card_by_number. The only notable overlap is between identify_card_from_image and analyze_pokemon_card, but the description explicitly directs users to prefer analyze_pokemon_card, reducing confusion.

Naming Consistency5/5

Tool names follow a consistent verb_noun snake_case pattern throughout, e.g., list_sets, search_cards, get_set_prices, add_collection_item. There are no mixed conventions or unpredictable naming styles, making the tool set highly predictable.

Tool Count2/5

With 40 tools, the count is well above the typical well-scoped range and falls into the 'too many' category per calibration. While the domain is broad (catalog, pricing, collection, watchlist, image analysis), many tools could be consolidated, such as the multiple identify variants and several price-comparison tools.

Completeness5/5

The tool surface provides comprehensive coverage for a Pokémon card wallet application: card search, pricing, set details, collection CRUD, watchlist management, image identification, and market comparisons. There are no obvious gaps in core lifecycles, and batch operations are included where useful.

Maintenance

ActivityStale
ResponsivenessNo issues