npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cyanheads/pokeapi-mcp-server

v0.2.0

Published

Look up Pokémon, moves, abilities, items, natures, and type matchups from PokéAPI v2 via MCP. STDIO or Streamable HTTP.

Readme

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

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.


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. Form IDs identify their own records: charizard-mega-x is 10034, while its associated species is charizard (6).
  • A species name with no Pokémon record of its own resolves to that species' default variety: deoxys returns the deoxys-normal dossier with resolvedFromSpecies: "deoxys". resolvedFromSpecies is null when the identifier names a record directly.
  • Returns stats, types, ability effects, sprites, evolution chain, varieties, capture and growth rates, gender ratio, and legendary/mythical flags in one dossier.
  • Each evolution step includes all evolutionDetails alternatives in upstream order, with requirements, version/default metadata, and starting/resulting forms. The existing trigger, minLevel, item, and condition summarize the first alternative. Conditional expressions, variable names, and chance percentages are preserved without evaluation.
  • 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 when unavailable.

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.
  • 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 for every attacking type touched, including neutral 1× cancellations; 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 preserves every version/currency row (versionGroup, currency, purchasePrice, sellPrice). Null purchase/sell values mean not purchasable/not sellable in that row; zero is a literal amount. An empty list means price records are unavailable.
  • cost preserves a supplied legacy Pokédollar cost and is null when absent. It is never inferred from a versioned price row.
  • 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. Every returned name works as a pokeapi_get_pokemon identifier: a species name resolves to its default variety. Type catalogs supply Pokémon-record IDs, including forms; generation, pokédex, and egg-group catalogs supply species IDs. These are PokéAPI IDs, not regional dex positions or National Pokédex numbers for forms.
  • appliedFilters echoes normalized nonblank categories, lowercase query tokens joined with single spaces, and accepted limit/offset values, including defaults. A call without a category, with or without query, returns no entries and a category-required notice; an unapplied query is omitted from the echo.
  • limit (default 50) and offset (default 0) paginate the filtered set. A page beyond existing matches retains totalCount and advises retrying with offset: 0; true zero matches advise relaxing the filters. Echoes and notices appear in structured results and the text trailer.

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 in ctx.state with a configurable TTL (default 6 h) to respect PokéAPI's fair-use policy. Only identifiers in PokéAPI's own a–z, 0–9, and hyphen alphabet are cached; any other identifier is fetched each time
  • Input normalization — accepts lowercase-hyphenated names or numeric IDs; trims, lowercases, and hyphenates whitespace, then URL-encodes the identifier once when the request is built. A blank, ., or .. identifier, or one over 100 characters, returns not_found (invalid_filter for a search filter) without an upstream request. An identifier outside the a–z, 0–9, and hyphen alphabet that PokéAPI refuses with a 400 returns the same error
  • 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 — meaningful missing scalars and empty lists are explicit in text as well as structured results: unavailable descriptions and sprites, no known holders or learners, no stat changes, neutral flavor preferences, and empty type relations. Regular/hidden abilities and default/alternative varieties retain their labels.

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. 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 | | 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 | Explicit OTLP log export endpoint; the base OTLP endpoint enables traces and metrics only. | 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       # Vitest test suite
    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.