@cyanheads/pokeapi-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/pokeapi-mcp-serverlook up Pikachu"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
| Denormalized Pokémon dossier in one call — stats, types, abilities, evolution chain, sprites, and species data |
| Computed offensive and defensive type effectiveness for a type or Pokémon, with correctly composed dual-type matchups |
| Move details — type, damage class, power, accuracy, PP, priority, stat changes, and effect text |
| Ability details — effect text and the Pokémon that have it, with hidden-ability flag and slot |
| Item details — effect text, category, versioned prices, fling power, attributes, and common holders |
| Nature details — stat boost/penalty and berry flavor preferences; lists all 25 when called without an identifier |
| Filter Pokémon by generation, type, pokédex, or egg group, with name-token matching and pagination |
Resources
Resource | Description |
| Pokémon dossier by name or PokéAPI Pokémon-record ID — same payload as |
| 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 returnsnot_found. Form IDs identify their own records:charizard-mega-xis10034, while its associated species ischarizard(6).A species name with no Pokémon record of its own resolves to that species' default variety:
deoxysreturns thedeoxys-normaldossier withresolvedFromSpecies: "deoxys".resolvedFromSpeciesis 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
evolutionDetailsalternatives in upstream order, with requirements, version/default metadata, and starting/resulting forms. The existingtrigger,minLevel,item, andconditionsummarize the first alternative. Conditional expressions, variable names, and chance percentages are preserved without evaluation.include_moves(defaultfalse) adds the move summary;moveCountis always returned.game_versionselects 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) orpokemon(name or PokéAPI Pokémon-record ID); unknown entries returnnot_found.Returns
offensiveRelations(null for dual-type Pokémon) anddefensiveMatchups, with dual-type defenses composed and immunity taking precedence.composedMultiplierscarries 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(defaultfalse) adds the list of Pokémon that can learn the move.learnersIncludeddistinguishes 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_foundwhen 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
pricespreserves 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.costpreserves a supplied legacy Pokédollar cost and is null when absent. It is never inferred from a versioned price row.not_foundwhen 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_foundwhen a provided identifier resolves to no nature
pokeapi_find_pokemon tool
Requires at least one of
generation,type,pokedex, andegg_group, combined with AND logic;query(at most 100 characters) adds per-token name matching within them. Unrecognized category names returninvalid_filter.Returns
idandnameentries for follow-uppokeapi_get_pokemoncalls, withtotalCountbefore paging. Every returned name works as apokeapi_get_pokemonidentifier: 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.appliedFiltersechoes normalized nonblank categories, lowercase query tokens joined with single spaces, and acceptedlimit/offsetvalues, including defaults. A call without a category, with or withoutquery, returns no entries and a category-required notice; an unapplied query is omitted from the echo.limit(default 50) andoffset(default 0) paginate the filtered set. A page beyond existing matches retainstotalCountand advises retrying withoffset: 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_pokemonwithinclude_movesfixed tofalseidentifieris a name or PokéAPI Pokémon-record ID, including form IDs; a species name resolves to its default varietynot_foundwhen 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
typeNameis one of the 18 canonical Pokémon typesnot_foundwhen 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_pokemonfans out across/pokemon,/pokemon-species,/evolution-chain, and N/abilityendpoints in two parallel tiers, returning one objectAggressive caching — PokéAPI data is static game data; responses are cached in
ctx.statewith a configurable TTL (default 6 h) to respect PokéAPI's fair-use policy. Only identifiers in PokéAPI's owna–z,0–9, and hyphen alphabet are cached; any other identifier is fetched each timeInput 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, returnsnot_found(invalid_filterfor a search filter) without an upstream request. An identifier outside thea–z,0–9, and hyphen alphabet that PokéAPI refuses with a 400 returns the same errorEnglish-first —
effect_entriesandflavor_text_entriesare always filtered tolanguage.name === 'en'; absent entries surface asnullrather than a foreign-language string
Agent-friendly output:
Dual-type composition —
pokeapi_get_type_matchupscomputes the effective matchup matrix from raw damage relations, so agents get a direct answer rather than raw tables to multiplyVariant surface —
pokeapi_get_pokemonlists 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/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
No API key required — PokéAPI is fully public.
Installation
Clone the repository:
git clone https://github.com/cyanheads/pokeapi-mcp-server.gitNavigate into the directory:
cd pokeapi-mcp-serverInstall dependencies:
bun installConfigure environment (optional):
cp .env.example .env
# All vars are optional — the server works with defaultsConfiguration
Variable | Description | Default |
| PokéAPI base URL — override for local mirrors or proxies. |
|
| How long to cache PokéAPI responses (seconds). |
|
| Per-request timeout in milliseconds. |
|
| Transport: |
|
| HTTP session mode: |
|
| Port for HTTP server. |
|
| Auth mode: |
|
| Log level (RFC 5424). |
|
| Directory for log files (Node.js only). |
|
| Log failed-call input and result, redacted by key name and capped at |
|
| Enable OpenTelemetry instrumentation. |
|
| 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:httpRun 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-serverThe 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 |
|
|
| Server-specific env var parsing with Zod ( |
| Tool definitions ( |
| Resource definitions ( |
|
|
| Vitest test suite mirroring |
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 withctx.fail(...)Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage (and caching)Register new tools and resources in the
createApp()arrays insrc/index.tsWrap 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 testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Pokemon MCP — wraps PokéAPI (free, no auth required)
Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.
Search NPPES providers and resolve NUCC specialty codes via MCP over STDIO or Streamable HTTP.
Provide detailed Pokémon data and information through a standardized MCP interface. Enable LLMs an…
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that interfaces with PokeAPI to provide Pokémon information to LLM applications through JSON-RPC over stdio.-
- AlicenseAqualityCmaintenanceA Model Context Protocol server that wraps pypokedex to provide Pokemon data tools for MCP-compatible applications.101MIT
- AlicenseNot gradedqualityDmaintenanceMCP server providing tools to look up Pokémon, moves, abilities, items, locations, evolutions, and more from the PokéAPI via natural language.70 npm2ISC
- AlicenseNot gradedqualityDmaintenanceProvides Pokemon data access through MCP tools like get_pokemon, list_pokemon, and evolution chains via PokeAPI.11 npmMIT