Skip to main content
Glama

parksapi-mcp

Generic MCP server over @themeparks/parksapi — every destination the library supports (80+ theme parks worldwide) with no per-park code, plus the 8 Orlando parks the library can't serve without app credentials, via the public api.themeparks.wiki APIs (see src/hosted.ts).

Tools

Tool

Description

Input

list_destinations

All destination ids (id, name, category)

{category?}

list_categories

All categories for filtering

—

get_destination

Details for one destination id

{destination}

get_entities

Entities (rides, shows, restaurants…) with hierarchy resolved

{destination, entityType?, limit?}

get_live_data

Live wait times / statuses / queues

{destination, entityId?, limit?}

get_schedules

Operating hours / show times

{destination, entityId?, limit?}

get_wait_history

Historical standby-wait observations or daily summaries

{destination?, entityId?, entityName?, days?, from?, to?, daily?, limit?}

get_wait_statistics

Weekday/time-bucket statistics for choosing lower-wait windows

{destination?, entityId?, entityName?, days?, from?, to?, bucketMinutes?, minSamples?}

export_wait_history

Historical wait data as CSV or JSON text

{destination?, entityId?, entityName?, days?, from?, to?, format?, daily?, limit?}

All tools return JSON as text. entityType filters e.g. ATTRACTION, SHOW, RESTAURANT (case-insensitive). entityId matches entry.id or entry.entityId. limit caps returned items (default 50 when omitted; via MCP it must be a positive int — direct withLimit(arr, 0) also means "all"). category in list_destinations is case-insensitive (disney == Disney). Unknown destinations return a tool result with isError: true (plain message, no protocol error). All tools are read-only (annotations.readOnlyHint: true).

Related MCP server: National Parks MCP Server

Historical wait times

The history tools use the public ThemeParks.wiki v1 history endpoints. They accept days (up to 3660) and split requests into the API's maximum 31-day chunks. entityName is convenient for hosted parks; the current parksapi entity id can also be supplied and is resolved to the v1 UUID. get_wait_statistics groups observed standby changes by the park-local weekday and time bucket and returns min, median, mean, p90, max and sample count. These are observed change points, not a guarantee: a bucket with few samples should be filtered with minSamples, and p50/mean are safer planning signals than a single minimum.

Examples:

{"destination":"universalislandsofadventure","entityName":"Hagrid's Magical Creatures Motorbike Adventure™","days":30,"bucketMinutes":60,"minSamples":3}
{"destination":"universalislandsofadventure","entityName":"Jurassic World VelociCoaster","days":90,"format":"csv"}

History is subject to the upstream account's retention window and rate limits; THEMEPARKS_API_KEY can be set when a longer history window or higher API allowance is needed.

History cache (local, incremental, git-ignored)

History responses are cached in SQLite (HISTORY_CACHE_PATH, default ./history-cache.sqlite, same convention as cache.sqlite) with full hierarchy depth — cidade → destino/parque → atração — so cached data can be listed (listHierarchy) and analyzed (queryPoints) at any level without touching the upstream API.

  • Repeat and overlapping queries fetch only uncovered dates; today + yesterday always re-fetch (upstream keeps appending), older dates are immutable once stored.

  • Anonymous first: live/destination lookups never send the key; history retries keyed only on HISTORY_WINDOW_EXCEEDED. Every keyed call consumes the free budget (300 req/min, 600 history/hour).

  • Responses carry keyUsed (key was needed) and cacheHit (zero upstream calls). HISTORY_CACHE_ENABLED=0 bypasses the cache (fail-soft).

  • The history-cache.sqlite* files are git-ignored on purpose — cached upstream data must never be committed or pushed.

Requirements

Node 22+.

Cache

The vendored upstream library keeps a SQLite cache at ./cache.sqlite (plus -shm/-wal) in the server's working directory — override with CACHE_DB_PATH (e.g. CACHE_DB_PATH="$TMPDIR/parksapi-cache.sqlite"). The files are git-ignored; wipe them with:

npm run clean

The hosted Orlando parks also keep a small in-memory TTL cache (60s for wait times/live, 12h for calendars) capped at 100 entries with LRU eviction.

Run

npm run setup:upstream   # once per clone: install + build vendored lib
npm install
npm run build
npm start                # stdio MCP server

Claude Desktop / Hermes config:

{
  "mcpServers": {
    "parksapi": {
      "command": "node",
      "args": ["/path/to/parksapi-mcp/dist/index.js"],
      "env": { "EFTELING_APIKEY": "..." }
    }
  }
}

Orlando parks (no credentials needed)

The TS library leaves Walt Disney World out of scope (Disney locked down the direct facility-service API) and covers Universal Orlando only with app-extracted API keys (without them universalorlando fails with Invalid URL). This server fills the gap with 8 native destinations (same entity/live/schedule/history interface, no credentials):

Park

destination

Source

Magic Kingdom

waltdisneyworldmagickingdom

preview collector

EPCOT

waltdisneyworldepcot

preview collector

Hollywood Studios

waltdisneyworldhollywoodstudios

preview collector

Animal Kingdom

waltdisneyworldanimalkingdom

preview collector

Universal Studios Florida

universalstudiosflorida

preview collector

Islands of Adventure

universalislandsofadventure

preview collector

Volcano Bay

universalvolcanobay

preview collector

Epic Universe

universalepicuniverse

v1 live + schedule API

7 parks read https://api.themeparks.wiki/preview/parks/<ParkAPIID>/{waittime,calendar} (the HostedPark pattern from the legacy JS library). Epic Universe has no ParkAPIID in the preview feed (404), so it reads the v1 live API (universalresort_orlando/live filtered by Epic parkId) plus the v1 schedule endpoint.

Hosted get_schedules is park-level only: one entry keyed by the park entity (<destination>park, e.g. waltdisneyworldmagickingdompark). Filtering by an attraction id yields no rows — filter by the park id or omit entityId.

To add more hosted parks (e.g. Disneyland California), add one entry to HOSTED_DESTINATIONS in src/hosted.ts.

Credentials

Most library-backed destinations need upstream API credentials as env vars (see the parksapi docs). Public ones such as efteling and all 8 Orlando hosted parks work with no credentials.

Tests (vitest, 41 tests)

npm test   # build + full suite
  • tests/service.test.ts — registry/helpers (offline)

  • tests/hosted.test.ts — WDW + Universal mapping, Epic v1 fallback, registry (offline, stubbed fetch)

  • tests/live.test.ts — Efteling live (no credentials)

  • tests/protocol.test.ts — real server over JSON-RPC stdio

Examples

  • list_destinations → browse ids (efteling, waltdisneyworldmagickingdom, universalepicuniverse…)

  • get_live_data {destination: "waltdisneyworldmagickingdom"} → Magic Kingdom wait times

  • get_live_data {destination: "universalepicuniverse"} → Epic Universe wait times (v1-backed)

  • get_schedules {destination: "efteling"} → operating hours

Upstream

upstream/ is a snapshot of ThemeParks/parksapi (2460a5e). Refresh it with:

rm -rf upstream && git clone --depth 1 https://github.com/ThemeParks/parksapi.git upstream && rm -rf upstream/.git && npm run setup:upstream

Related MCP Connectors

Related MCP Servers