Skip to main content
Glama
cyanheads

@cyanheads/pokeapi-mcp-server

by cyanheads

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Public Hosted Server: https://pokeapi.caseyjhand.com/mcp


Overview

Pokémon game data from PokéAPI: Pokémon, moves, abilities, items, and natures. Get a complete Pokémon profile in one call (stats, abilities, evolution, sprites), filter by generation, type, pokédex, or egg group, and compute dual-type matchups.

Tools

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, versioned prices, 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

Resources

Resource

Description

pokeapi://pokemon/{identifier}

Pokémon dossier by name or PokéAPI Pokémon-record ID — 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.


Related MCP server: dexMCP

Capability reference

pokeapi_get_pokemon tool

  • Accepts a lowercase-hyphenated name or numeric PokéAPI Pokémon-record ID as identifier; an unknown entry returns not_found. A species name resolves to its default variety (deoxys returns deoxys-normal, with resolvedFromSpecies: "deoxys").

  • Returns stats, types, ability effects, sprites, evolution chain (every evolutionDetails alternative), varieties, capture and growth rates, gender ratio, and legendary/mythical flags in one dossier.

  • include_moves (default false) adds the move summary; moveCount is always returned. game_version selects flavor text and falls back to the most recent English entry.


pokeapi_get_type_matchups tool

  • Requires exactly one of type (type name) or pokemon (name or PokéAPI Pokémon-record ID); unknown entries return not_found.

  • Species names resolve to their default variety (deoxys uses deoxys-normal); resolvedPokemon and resolvedFromSpecies report the match and are null for direct type queries.

  • Returns offensiveRelations (null for dual-type Pokémon) and defensiveMatchups, with dual-type defenses composed and immunity taking precedence.

  • composedMultipliers carries 0, 0.25, 0.5, 1, 2, or 4 per attacking type; absent types also deal 1×.


pokeapi_get_move tool

  • Accepts a lowercase-hyphenated move name or numeric ID; an unknown entry returns not_found.

  • Returns type, damage class, power, accuracy, PP, priority, target, stat changes, and secondary-effect chance, plus full and short English effect text

  • include_learners (default false) adds the list of Pokémon that can learn the move. learnersIncluded distinguishes an unrequested list from a requested list with no known learners.


pokeapi_get_ability tool

  • Accepts a lowercase-hyphenated ability name or numeric ID

  • Returns full and short English effect text, the generation introduced, and every Pokémon that has the ability, with its hidden-ability flag and slot

  • not_found when the identifier resolves to no ability


pokeapi_get_item tool

  • Accepts a lowercase-hyphenated item name or numeric ID

  • Returns category, fling power, attributes (holdable, consumable, etc.), sprite URL, effect text, and Pokémon that commonly hold it

  • prices lists every version/currency row (versionGroup, currency, purchasePrice, sellPrice); null means not purchasable/sellable there, and an empty list means no price records. cost is the legacy Pokédollar cost, or null.

  • not_found when the identifier resolves to no item


pokeapi_get_nature tool

  • identifier (name or ID 1–25) is optional — omit it to return all 25 natures at once (isListAll: true)

  • Each entry carries the boosted stat, reduced stat, and liked/disliked berry flavor — all null for the 5 neutral natures

  • not_found when a provided identifier resolves to no nature


pokeapi_find_pokemon tool

  • Requires at least one of generation, type, pokedex, and egg_group, combined with AND logic; query (at most 100 characters) adds per-token name matching within them. Unrecognized category names return invalid_filter.

  • Returns id and name entries for follow-up pokeapi_get_pokemon calls, with totalCount before paging. Type-only searches include forms; generation, pokédex, and egg-group filters return species. IDs are PokéAPI IDs, not dex numbers.

  • appliedFilters echoes the filters, query tokens, limit, and offset that were applied. A call with no category returns no entries and a notice saying one is required.

  • limit (default 50) and offset (default 0) paginate the filtered set. A page past the last match keeps totalCount and advises offset: 0; zero matches advise relaxing the filters.


pokeapi://pokemon/{identifier} resource

  • Same payload as pokeapi_get_pokemon with include_moves fixed to false

  • identifier is a name or PokéAPI Pokémon-record ID, including form IDs; a species name resolves to its default variety

  • not_found when the identifier matches no Pokémon record and no species


pokeapi://type/{typeName} resource

  • Returns the raw offensive and defensive damage-relation multiplier table for one type

  • typeName is one of the 18 canonical Pokémon types

  • not_found when the type name doesn't exist in PokéAPI


Features

Built 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:

  • Keyless and read-only — no API key, no auth, no configuration required to run

  • Graph-walk consolidation — pokeapi_get_pokemon fans out across /pokemon, /pokemon-species, /evolution-chain, and N /ability endpoints in two parallel tiers, returning one object

  • Aggressive caching — PokéAPI data is static game data; responses are cached with a configurable TTL (default 6 h) to respect PokéAPI's fair-use policy

  • Input normalization — accepts lowercase-hyphenated names or numeric IDs; trims, lowercases, and hyphenates whitespace. A blank identifier or one over 100 characters returns not_found (invalid_filter for a search filter) without an upstream request

  • English-first — effect_entries and flavor_text_entries are always filtered to language.name === 'en'; absent entries surface as null rather than a foreign-language string

Agent-friendly output:

  • Dual-type composition — pokeapi_get_type_matchups computes the effective matchup matrix from raw damage relations, so agents get a direct answer rather than raw tables to multiply

  • Variant surface — pokeapi_get_pokemon lists all form variants so agents can identify and re-call with specific forms (Alolan, Galarian, Mega, Gigantamax)

  • Nullable details — missing descriptions, sprites, holders, and learners are stated explicitly in text and structured results rather than omitted


Getting started

Public Hosted Instance

A 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"
    }
  }
}

Self-Hosted / Local

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

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).

  • No API key required — PokéAPI is fully public.

Installation

  1. Clone the repository:

git clone https://github.com/cyanheads/pokeapi-mcp-server.git
  1. Navigate into the directory:

cd pokeapi-mcp-server
  1. Install dependencies:

bun install
  1. Configure environment (optional):

cp .env.example .env
# All vars are optional — the server works with defaults

Configuration

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.

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

LOG_TOOL_FAILURE_PAYLOADS

Log failed-call input and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). Secrets inside free-form values are not redacted.

false

OTEL_ENABLED

Enable OpenTelemetry instrumentation.

false

OTEL_EXPORTER_OTLP_LOGS_ENDPOINT

OTLP log export endpoint.

Unset

See .env.example for the full list of optional overrides.

Self-hosting for high-volume use

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.


Running the server

Local development

  • 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       # Offline Vitest suite with deterministic fetch fixtures
    bun run lint:mcp   # Validate MCP definitions against spec

Docker

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.


Project structure

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/.


Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — catch typed upstream errors only to map a declared errors[] contract with ctx.fail(...)

  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage (and caching)

  • Register new tools and resources in the createApp() arrays in src/index.ts

  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields


Contributing

Issues are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.

Related MCP Connectors

Related MCP Servers