ParkAlert MCP
# ParkAlert MCP
An MCP server that exposes Disney ride status and wait times as on-demand tools,
backed by the [ThemeParks.wiki](https://api.themeparks.wiki/) API.
This is the pull-based sibling of [ParkAlert](https://github.com/austin5374/parkalert),
a PWA that polls the same API on a timer and pushes a notification through ntfy.sh
when a ride goes down or comes back up. ParkAlert answers "tell me when something
changes." This server answers "what is the situation right now, because I just asked."
The API client is ported from ParkAlert's `server/themeparks.js`; the polling loop,
the transition detection, the trip codes, and the notification fan-out are all
deliberately left behind.
## Tools
| Tool | Arguments | Answers |
| --- | --- | --- |
| `get_ride_status` | `park`, `ride` | Is this ride operating, down, or closed right now? |
| `get_wait_time` | `park`, `ride` | How long is the standby line right now? |
Both tools accept a park by name, alias, or ThemeParks.wiki entity ID
("Magic Kingdom", "dhs", "epcot"), and a ride by however a person would say it.
Partial and near-miss names such as "space mountain" or "tron" are matched, and an
ambiguous name comes back with the candidates it could have meant.
Supported parks: Magic Kingdom, EPCOT, Hollywood Studios, Animal Kingdom,
Disneyland (CA), California Adventure. Add more by appending to `PARKS` in
`src/parkalert_mcp/parks.py`.
## Setup
Requires Python 3.10 or newer, which is the `mcp` SDK's floor. Note that the
system `python3` on macOS may well be older than that, so name the interpreter
explicitly rather than relying on whatever `python3` resolves to.
```bash
python3.12 -m venv .venv
.venv/bin/pip install -e .
```
`requirements-lock.txt` records the exact versions this server is known to work
against, captured from a working environment. It exists because the dependency
that matters here is a moving target: `mcp` 2.0 renamed `FastMCP` to `MCPServer`,
so a rebuild that quietly resolved to a different major version would fail at
import with no hint as to why. To reproduce the known-good environment instead of
resolving fresh versions:
```bash
python3.12 -m venv .venv
.venv/bin/pip install -r requirements-lock.txt
.venv/bin/pip install --no-deps -e .
```
Regenerate the lockfile after changing dependencies:
```bash
.venv/bin/pip freeze --exclude-editable > requirements-lock.txt
```
The `--exclude-editable` flag is load-bearing. A plain `pip freeze` writes this
project back out as a `-e git+https://...@<commit>` line, which would send a
future rebuild off to clone the repository rather than installing the checkout
already in hand.
## Tests
```bash
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest
```
The suite covers the two functions that decide what a caller's words mean:
`find_attraction` in `themeparks.py` and `resolve_park` in `parks.py`. Both run
offline, against a capture of real Magic Kingdom and EPCOT attraction data frozen
in `tests/conftest.py`. The tests therefore describe the matching rules and their
precedence, not today's ride list, and a ride opening or closing upstream will not
turn them red.
One test does reach the network. It fetches `/live` for all six park entity IDs
and asserts that each still returns attractions, which is precisely the failure
the offline tests cannot see. It is marked `network` and deselected by default,
so it runs only when asked for:
```bash
.venv/bin/python -m pytest -m network
```
## Running it
The server speaks stdio, so it is launched by its client rather than run as a
long-lived service. To exercise it by hand:
```bash
.venv/bin/python -m parkalert_mcp.server
```
For an interactive tool browser, the MCP Inspector works against the same command:
```bash
npx @modelcontextprotocol/inspector .venv/bin/python -m parkalert_mcp.server
```
## Claude Desktop
Add the server to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"parkalert": {
"command": "/Users/austin/parkalert-mcp/.venv/bin/python",
"args": ["-m", "parkalert_mcp.server"]
}
}
}
```
The absolute path to the venv's Python matters: Claude Desktop does not run through
a login shell, so a bare `python` would not resolve to this environment. Restart
Claude Desktop after editing, then look for the tools under the connectors icon.
## Credits
Built by Austin Vodrazka with Claude.
TDQS
Scored across 2 tools
The two tools accept the same park/ride arguments and both return status plus wait time, so an agent could reasonably pick either for a wait or status question. However, the descriptions clearly steer status checks to get_ride_status and wait-time questions to get_wait_time, reducing confusion.
Both tools follow the same get_<resource>_<metric> pattern: get_ride_status and get_wait_time. The naming is predictable and mirrors the two core queries perfectly.
Two tools is on the thin side for a general-purpose MCP server, but the scope is intentionally narrow: live Disney ride status and standby wait times. The count feels minimal but not unreasonable for that focused domain.
The core domain is covered: agents can check whether a ride is operating, down, or closed, and get standby wait minutes with status context to interpret Nones. Minor gaps exist, such as no way to list all rides in a park, but the main user intents are served.