SkillAgentSearch skills...

cineplex-mcp

MCP server that lets Claude search Cineplex Canada showtimes and filter by seat quality (e.g. "IMAX 70mm, not the first 3 rows, not on the sides"). Unofficial, personal-use — talks directly to Cineplex's undocumented public endpoints.

Install / Use

claude mcp add yinbri -- npx -y github:yinbri/cineplex-mcp

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

83/100

Category

Operations

Supported Platforms

Claude Code
Claude Desktop

Our assessment of cineplex-mcp

cineplex-mcp scores 83/100 on our quality scale, 590th of 757 Operations skills we index.

Its MCP Server is 26 KB long, well organised into 27 sections with 15 code examples: a thorough specification that gives an agent plenty to work with.

It has 3 GitHub stars, so there is little community track record yet; judge it on its content.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
3/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated about 2 months ago, so cineplex-mcp is actively maintained.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 92/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

cineplex-mcp compared with similar skills

All 4 of these similar skills score higher than cineplex-mcp; compare them before choosing.

SkillScoreStarsUpdatedFormat
cineplex-mcp (this skill)by yinbri8332mo agoMCP Server
Agent-Reachby Panniantong100106.6k5d agoCLAUDE.md
headroomby headroomlabs-ai10078.3ktodayCLAUDE.md
CowAgentby zhayujie10047.7ktodayCLAUDE.md
Scraplingby D4Vinci10090.4k1d agoMCP Server

Frequently asked questions

How do I install cineplex-mcp?
Run claude mcp add yinbri -- npx -y github:yinbri/cineplex-mcp. The install tabs above show the steps for each supported agent.
Which AI agents does cineplex-mcp work with?
It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
Is cineplex-mcp safe to use?
It is MIT-licensed and scores 92/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is cineplex-mcp still maintained?
The repository was last updated about 2 months ago, so cineplex-mcp is actively maintained.

cineplex-mcp

An MCP (Model Context Protocol) server that lets Claude look up Cineplex Canada showtimes and find ones with good seats available — e.g. "Find showtimes for The Odyssey in IMAX 70mm near me with good seats, not the first 3 rows, not on the sides."

This is a personal-use tool, not a commercial product. Cineplex has no official partner API for this data; this server calls Cineplex's undocumented public web endpoints directly. It's built to cache aggressively, keep request volume low, and fail gracefully rather than pretend otherwise: calls are throttled rather than fired in bursts, transient failures (429/5xx, dropped sockets) are retried with backoff that honours Retry-After, and anything still broken surfaces as a clear message instead of a crash.

Demo

https://github.com/user-attachments/assets/8b19e98a-921c-4041-920b-d82a6b0f14db

This is a personal-use tool, not a commercial product. ...

Status: all five Cineplex data endpoints are confirmed working

All five calls this server depends on hit real, live apis.cineplex.com endpoints, tested end-to-end against real responses — the original four as of 2026-07-19, the full theatre directory as of 2026-07-31. See CAPTURE.md for how they were found and what to do if Cineplex changes something in the future (e.g. rotates the theatrical API's subscription key).

Setup

npm install

Node.js 18+ is required (for built-in fetch).

No environment variables or session tokens are required — every endpoint this server calls was confirmed to work unauthenticated (theatre/movie/ showtime discovery uses a static, public subscription key baked into cineplexClient.js; seat data needs no key at all).

If Cineplex rotates the subscription key

That key is public — Cineplex ships it to every visitor's browser — but it will eventually be rotated, at which point theatre/movie/showtime lookups start failing with a 401. The server resolves it from three sources, in order:

  1. CINEPLEX_SUBSCRIPTION_KEY (env var) — an explicit override. If set, it always wins and automatic discovery is skipped entirely.
  2. A key discovered automatically. On a 401, the server re-captures the key the same way a human would (per CAPTURE.md): it reads cineplex.com's homepage, walks the _next/static/chunks/*.js it references, and extracts the key sitting next to the theatrical API's URL, then retries the request with it. This runs only after a rejected key, at most once per process, so normal operation costs nothing extra.
  3. The bundled fallback in cineplexClient.js — verified current as of 2026-07-30.

If automatic re-capture also fails, the error tells you so explicitly and points at CAPTURE.md; recovery is then setting the env var, with no code change or redeploy.

The extractor anchors on the theatrical API's URL rather than on the Ocp-Apim-Subscription-Key header name, because Cineplex's bundle ships several different subscription keys (a separate one guards their marketing API, and it appears earlier in the bundle). Matching the header name alone would return that decoy — a key that 401s forever while looking like a successful re-capture.

Running

npm start

This starts the MCP server on stdio, for use by an MCP client (Claude Desktop, Claude Code, etc.) — it's not meant to be run standalone for interactive use.

Claude Desktop configuration

Add to your Claude Desktop config (claude_desktop_config.json):

{
  "mcpServers": {
    "cineplex": {
      "command": "node",
      "args": ["/absolute/path/to/cineplex-mcp/src/index.js"]
    }
  }
}

Restart Claude Desktop after editing the config.

If you ever need to override the subscription key (see above), add an env block — otherwise leave it out:

"cineplex": {
  "command": "node",
  "args": ["/absolute/path/to/cineplex-mcp/src/index.js"],
  "env": { "CINEPLEX_SUBSCRIPTION_KEY": "…" }
}

Claude Code configuration

claude mcp add cineplex -- node /absolute/path/to/cineplex-mcp/src/index.js

With an optional key override:

claude mcp add cineplex -e CINEPLEX_SUBSCRIPTION_KEY=… -- node /absolute/path/to/cineplex-mcp/src/index.js

Running in Docker

The server talks over stdio, so it works fine as a container that an MCP client docker runs per session — no port mapping needed.

Build the image:

docker build -t cineplex-mcp .

Claude Desktop config, using the image instead of a local node install:

{
  "mcpServers": {
    "cineplex": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "cineplex-mcp"]
    }
  }
}

Claude Code:

claude mcp add cineplex -- docker run -i --rm cineplex-mcp

With the subscription key override, pass it through with -e:

claude mcp add cineplex -- docker run -i --rm -e CINEPLEX_SUBSCRIPTION_KEY=… cineplex-mcp

Rebuild the image (docker build -t cineplex-mcp .) after pulling changes to src/ — the client just launches whatever image tag is on disk, so a stale image silently keeps running old code.

Tools exposed

  • find_theatres — { location?, lat?, lon?, rangeKm? } → nearby theatres (id, name, address, distance), nearest first, plus a resolvedLocation block saying how the location was understood.

    Send lat/lon when you can place the location yourself — that is the primary path. Send location for the things that need looking up: a postal code ("M5B 2H1", or a bare FSA like "M5B"), a Cineplex theatre name ("Yonge-Dundas"), or a city that has a Cineplex theatre. See Location input for how the two divide the work.

  • find_movie — { title } → best fuzzy match against Cineplex's full current movie catalog, including the Cineplex movie ID. Cineplex's movies endpoint returns the whole catalog in one response (it reports a totalCount matching the items it returns), so no pagination is involved.

  • find_optimal_showtimes — { movieTitle, theatreId, date, formatMatch?, excludeFrontRows?, excludeSideSeats?, minContiguous? } → showtimes matching a format (default "IMAX", case-insensitive substring match — also works for "IMAX 70mm", "UltraAVX", "Dolby", etc.), scored for seat quality. Returns both the full scored list and an optimal subset.

  • get_optimal_seats — { theatreId, showtimeId, excludeFrontRows?, excludeSideSeats?, minContiguous? } → seat score for a single already-known showtime. Cineplex's seat endpoints are keyed by the (theatreId, showtimeId) pair, not showtimeId alone.

  • render_seat_map_ascii — the default seat-map visualization. { theatreId, showtimeId, partySize?, excludeFrontRows?, excludeSideSeats?, monochrome?, theatreName?, showLabel?, buyUrl? } → a compact ASCII/emoji seat-map diagram as plain text: a centered SCREEN banner, the auditorium as a grid of squares (🟩 open, ⬛ taken, 🟪 accessible), the best partySize-block highlighted (🟦, centered within the run), a one-line recommendation, and a 🎟 Buy tickets link. Works in any MCP client with no extra setup — it's just text. Because most clients keep tool results collapsed behind a "tools used" disclosure, the diagram is only visible if the assistant pastes it into its reply, so the result ships as two blocks: a display instruction, then a ready-to-paste payload fenced by ===== COPY EVERYTHING BELOW THIS LINE ===== markers. The payload arrives pre-formatted — the grid already inside a fence, the buy line already lifted **out** of the fence as a clickable Markdown link (links don't linkify inside) — so displaying it is copy-paste, not reassembly. Pass buyUrl through from find_optimal_showtimes for the correct D-BOX-aware link, or omit it to build a cineplex.com/ticketing/preview link from the IDs. Set monochrome: true (·/▓/+/★) where emoji width misaligns the grid. Rendering logic lives in src/seatMapAscii.js.

  • render_seat_map_html — the opt-in interactive alternative; needs the bundled skill (see below). { movieTitle, theatreId, date, theatreName?, theatreAddress?, distanceKm?, formatMatch?, excludeFrontRows?, excludeSideSeats?, minContiguous? } → a complete, self-contained HTML page visualizing real seat availability: showtime chips, a pannable/zoomable auditorium seat map, live filter controls, and a stats strip. Meant to be rendered inline in the chat as a widget (via the Visualizer's show_widget), not saved to a file, published as a hosted artifact, or read as data — see src/seatMapTemplate.html/.js. The tool only injects real data into an already-built, already-tested template; it never generates new HTML/JS per call, so there's no risk of a fresh generation shipping a UI bug.

theatreId/showtimeId accept either a string or a number — Cineplex's IDs are numeric, and find_theatres/find_optimal_showtimes hand them back as numbers, so chaining one tool's output straight into the next one's input just works.

Location input

Cineplex's theatre search is coordinate-based. find_theatres takes either coordinates or a location string, and the two are meant to split the work rather than compete:

Send lat/lon for anywhere you can already place — cities, neighbourhoods, landmarks, street addresses. A language model converts those accurately and knows when it can't, so a lookup table would only duplicate it. This is the expected path and the most precise one.

Send location for what world knowledge gets wrong:

| Input | Example | Resolved from | |---|---|---| | postal code / FSA | "M5B 2H1", "M5B" | bundled FSA table | | Cineplex theatre name | "Yonge-Dundas", "Courtney Park" | live theatre directory | | city with a theatre | "Mississauga", "London, ON" | live theatre directory | | coordinates as a string | "43.65, -79.38" | parsed, not looked up |

A postal code is also picked up from inside a longer string, so "123 Front St W, Toronto, ON M5J 2M2" resolves by its postal code. Input is case-, punctuation-, and accent-insensitive; a trailing country is ignored ("Halifax, NS, Canada"); provinces work as a code or a full name.

Anything else returns found: false inviting you to pass coordinates. That is the design, not a gap.

Why postal codes specifically

They are the one input neither a model nor an open geocoder handles reliably.

Canada Post's postal file is proprietary, so OSM's coverage is thin: measured against Nominatim on 2026-07-31, four of six sampled postal codes returned no match, and V6B 1A1 — downtown Vancouver — resolved to 48.87, -119.73, about 400 km away near the Washington border.

Recall fares better but fails unpredictably. Claude's own from-memory coordinates for 16 FSAs landed 12 within 10 km — Waterloo 0.1 km, Victoria 0.3 km — but placed T9K in Cold Lake when it is Fort McMurray, 264 km off, stated exactly as confidently as the correct answers. A wrong coordinate doesn't fail loudly; it returns a tidy list of theatres in the wrong city.

The bundled GeoNames table (src/data/postalCodes.json, 41 KB, CC BY 4.0) covers all 1652 FSAs. Rebuild it with npm run build:locations.

Precision

Every result reports how sharp it is:

  • exact — coordinates, or a specific theatre.
  • fsa — an urban postal area, a few blocks across.
  • city — the centroid of that city's Cineplex theatres. Fine for a small city, loose for a big one: "Toronto" lands near Don Mills, because the suburban locations outvote the downtown ones, and returns Don Mills as the nearest theatre where coordinates for downtown return Yonge-Dundas. Prefer lat/lon for large cities.
  • region — a rural FSA (a 0 in the second position, Canada Post's own convention). The

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars3
CategoryOperations
Updated2mo ago
Forks0

Languages

JavaScript

Trust signals

92/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 low