
Connects to PokéAPI v2 and surfaces seven tools covering the full Pokémon data surface. The flagship tool is `pokeapi_get_pokemon`, which fans out across multiple endpoints in parallel and returns a denormalized dossier with stats, abilities, evolution chain, sprites, and optionally learnable moves. `pokeapi_get_type_matchups` computes offensive and defensive effectiveness with dual-type composition already handled. The other five tools cover moves, abilities, items, natures, and filtered Pokémon lookups by generation, type, or egg group. No API key needed, aggressive caching to respect fair-use limits, and all responses are English-first. Reach for this when you need structured game data for team building, damage calculations, or any agent workflow that references Pokémon mechanics.
Look up Pokémon, moves, abilities, items, natures, and type matchups from PokéAPI v2 via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://pokeapi.caseyjhand.com/mcp
Pokémon game data from PokéAPI v2 — Pokémon, moves, abilities, items, and natures, plus computed type-effectiveness matchups. Fetch a denormalized Pokémon dossier in a single call, filter Pokémon by generation, type, pokédex, or egg group, and compute dual-type matchups from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| Tool | Description |
|---|---|
pokeapi_get_pokemon | Denormalized Pokémon dossier in one call — stats, types, abilities, evolution chain, sprites, and species data |
pokeapi_get_type_matchups | Computed offensive and defensive type effectiveness for a type or Pokémon, with correctly composed dual-type matchups |
pokeapi_get_move | Move details — type, damage class, power, accuracy, PP, priority, stat changes, and effect text |
pokeapi_get_ability | Ability details — effect text and the Pokémon that have it, with hidden-ability flag and slot |
pokeapi_get_item | Item details — effect text, category, cost, fling power, attributes, and common holders |
pokeapi_get_nature | Nature details — stat boost/penalty and berry flavor preferences; lists all 25 when called without an identifier |
pokeapi_find_pokemon | Filter Pokémon by generation, type, pokédex, or egg group, with name-token matching and pagination |
| Resource | Description |
|---|---|
pokeapi://pokemon/{identifier} | Pokémon dossier by name or dex number — same payload as pokeapi_get_pokemon without moves |
pokeapi://type/{typeName} | Type damage relations — raw multiplier table, offensive and defensive |
All resource data is also reachable via tools.
pokeapi_get_pokemon toolidentifierinclude_moves (default false) adds the learnable-move summary (100–200+ entries); moveCount is always returned regardlessgame_version selects flavor text by game (e.g. "sword", "red"); falls back to the most recent English entry when the version isn't found/pokemon, /pokemon-species, /evolution-chain, and each /ability in a two-tier parallel fetch, returning stats, types, abilities (with effect text), sprites (including official artwork), evolution chain, varieties, capture rate, growth rate, gender rate, and legendary/mythical flags in one objectnot_found when the identifier resolves to no PokéAPI entrypokeapi_get_type_matchups tooltype (type name) or pokemon (name or dex number) is required — providing both or neither is a validation erroroffensiveRelations (super-effective / not-very-effective / no-effect lists) is null for dual-type Pokémon queries, since per-type offense doesn't composedefensiveMatchups (weak-to / resists / immune-to) is always populated and correctly composes both types for dual-type Pokémon — immune in either type winscomposedMultipliers gives the full multiplier (0, 0.25, 0.5, 1, 2, 4) for every attacking type touched, including net-neutral 1× cancellations; a type absent from the map deals 1×not_found when the type name or Pokémon identifier doesn't resolvepokeapi_get_move toolinclude_learners (default false) adds the list of Pokémon that can learn the movenot_found when the identifier resolves to no movepokeapi_get_ability toolnot_found when the identifier resolves to no abilitypokeapi_get_item tool0 when not sold in shops), fling power, attributes (holdable, consumable, etc.), sprite URL, effect text, and Pokémon that commonly hold itnot_found when the identifier resolves to no itempokeapi_get_nature toolidentifier (name or ID 1–25) is optional — omit it to return all 25 natures at once (isListAll: true)not_found when a provided identifier resolves to no naturepokeapi_find_pokemon toolgeneration, type, pokedex, egg_group — are all optional and combined with AND logicquery adds strict per-token name matching on top of at least one category filter; query alone with no category filter returns an empty result and a noticelimit (default 50) and offset (default 0) paginate the filtered set; totalCount reports the full match count before pagingid and name, for follow-up pokeapi_get_pokemon callsinvalid_filter when a generation, type, pokédex, or egg-group name isn't recognizedpokeapi://pokemon/{identifier} resourcepokeapi_get_pokemon with include_moves fixed to falseidentifier is a name or Pokédex numbernot_found when no Pokémon matches the identifierpokeapi://type/{typeName} resourcetypeName is one of the 18 canonical Pokémon typesnot_found when the type name doesn't exist in PokéAPIBuilt on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
PokéAPI-specific:
pokeapi_get_pokemon fans out across /pokemon, /pokemon-species, /evolution-chain, and N /ability endpoints in two parallel tiers, returning one objectctx.state with a configurable TTL (default 6 h) to respect PokéAPI's fair-use policyeffect_entries and flavor_text_entries are always filtered to language.name === 'en'; absent entries surface as null rather than a foreign-language stringAgent-friendly output:
pokeapi_get_type_matchups computes the effective matchup matrix from raw damage relations, so agents get a direct answer rather than raw tables to multiplypokeapi_get_pokemon lists all form variants so agents can identify and re-call with specific forms (Alolan, Galarian, Mega, Gigantamax)null in structured resultsA public instance is available at https://pokeapi.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"pokeapi-mcp-server": {
"type": "streamable-http",
"url": "https://pokeapi.caseyjhand.com/mcp"
}
}
}
No API key required. Add the following to your MCP client configuration file:
{
"mcpServers": {
"pokeapi-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/pokeapi-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"pokeapi-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/pokeapi-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"pokeapi-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/pokeapi-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/pokeapi-mcp-server.git
cd pokeapi-mcp-server
bun install
cp .env.example .env
# All vars are optional — the server works with defaults
| Variable | Description | Default |
|---|---|---|
POKEAPI_BASE_URL | PokéAPI base URL — override for local mirrors or proxies. | https://pokeapi.co/api/v2 |
POKEAPI_CACHE_TTL_SECONDS | How long to cache PokéAPI responses (seconds). | 21600 (6 h) |
POKEAPI_REQUEST_TIMEOUT_MS | Per-request timeout in milliseconds. | 10000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_SESSION_MODE | HTTP session mode: auto, stateful, or stateless. A meaningful env value overrides the app default. The framework schema defaults to auto, which resolves to stateful. Tenant-scoped caching works in every mode. | stateless |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
PokéAPI's Fair Use Policy asks consumers to cache aggressively and points high-volume deployments toward running a local instance. This server already caches responses for 6 hours by default (POKEAPI_CACHE_TTL_SECONDS), which covers most workloads. For hosted or batch-heavy deployments, run the official PokéAPI Docker image locally and point POKEAPI_BASE_URL at it — the server switches transparently.
Build and run:
bun run rebuild
bun run start:stdio
# or
bun run start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t pokeapi-mcp-server .
docker run --rm -p 3010:3010 pokeapi-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/pokeapi-mcp-server. Build with --build-arg OTEL_ENABLED=false to omit OpenTelemetry peer dependencies.
| Path | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools, resources, and inits services. |
src/config/ | Server-specific env var parsing with Zod (server-config.ts). |
src/mcp-server/tools/ | Tool definitions (*.tool.ts). |
src/mcp-server/resources/ | Resource definitions (*.resource.ts). |
src/services/pokeapi/ | PokeApiService — typed fetch methods, caching, retry, timeout. |
tests/ | Vitest test suite mirroring src/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
errors[] contract with ctx.fail(...)ctx.log for request-scoped logging, ctx.state for tenant-scoped storage (and caching)createApp() arrays in src/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.