Skip to main content
Glama
KiraPC

italian-cinema-mcp

by KiraPC

italian-cinema-mcp

A local Model Context Protocol server that lets an LLM compare showtimes across Italian cinema chains. Spawn it as an MCP host (claude, Cursor, …) and ask things like "what's on tonight after 20:00 near me?" — the server fans the question out to UCI Cinemas and The Space Cinema, shrinks the ~100 KB per-cinema JSON payload into a compact text view, and returns every option in one answer.

Status

MVP. UCI Cinemas (33 venues) and The Space Cinema (35 venues) are both wired in. Both upstream APIs are unofficial and may change without notice.

Related MCP server: Allociné MCP Server

Disclaimer

This project is not affiliated with, endorsed by, or sponsored by UCI Cinemas or The Space Cinema, and "UCI Cinemas", "The Space Cinema", and any other brand or venue names referenced here are the property of their respective owners. The server relies on the same undocumented JSON endpoints that the official websites call from the browser; it does not authenticate, and those endpoints may change, rate-limit, or stop working at any time without notice. It is intended for personal use; requests are cached (cinema metadata for 24 h, showtimes for 5 min) and dispatched with bounded concurrency so upstream is only contacted when the user actually asks something.

Tools

Tool

Inputs

Output

list_cinemas

chain? (uci | thespace)

every cinema: id, name, chain, city

list_films

cinema_ids[], date?

titles with duration and the cinemas showing them, no times

get_showtimes

cinema_ids[], date?, from_time?, to_time?, title_contains?, include_links?

film → cinema → showtimes with format, language, sold-out flag, booking URL

Cinema ids are namespaced by chain — uci:uci-cinemas-romaest-roma, thespace:1021. date is YYYY-MM-DD, defaults to today in Europe/Rome. Times are HH:MM Europe/Rome.

Recommended call flow: list_cinemas once → pick ids → list_films for a cheap overview → get_showtimes with title_contains or a time window.

Errors from one cinema never fail the whole call; the rest are returned alongside a short note about which cinema failed and why.

Booking links are off by default (include_links=true to surface them).

Example output

Resident Evil (1h30)
The Space Roma Moderno           22:45
The Space Roma Parco de' Medici  21:05, 22:25, 23:25
UCI Porta di Roma                22:10
UCI Roma Est                     21:40, 22:30, 23:50

Showtime tags: just HH:MM by default. Only non-default format/language gets a tag — 21:30 IMAX, 20:20 EN, 22:10 OV, 21:30 ISENSE. Italian is the default and is never printed. Sold-out shows add (sold out). Booking links are off by default; pass include_links=true to surface them.

Build

npm install
npm run build      # tsc → dist/
npm run dev        # tsx src/server.ts (no build step)
npm test           # vitest, offline only
LIVE=1 npm test    # also runs the live smoke tests against UCI and The Space

Requirements: Node.js >= 20 (uses the global fetch).

Run

The server speaks MCP over stdio, so an MCP host launches it as a subprocess. Register it once and forget it.

Claude Code

claude mcp add --transport stdio --scope user italian-cinema-mcp \
  -- node /absolute/path/to/italian-cinema-mcp/dist/server.js

(or npm run dev if you prefer running from source).

Claude Desktop

Add the server in claude_desktop_config.json:

{
  "mcpServers": {
    "italian-cinema-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/italian-cinema-mcp/dist/server.js"]
    }
  }
}

Tests

npm test runs vitest on:

  • unit tests for the date helper, the formatter, and per-chain connector mappers (fixture-driven, no network);

  • the cinema service tests (filtering, per-cinema failures, batch merging);

  • an opt-in live smoke test (LIVE=1) that hits both upstream APIs.

Fixtures under test/fixtures/{uci,thespace}/ are trimmed real responses, kept in-repo so npm test doesn't need network access.

Project layout

src/
  server.ts               MCP server with three tools
  service.ts              CinemaService: chains, caching, parallel fetch, filter
  connectors/uci.ts       UCI Cinemas connector
  connectors/thespace.ts  The Space Cinema connector
  format.ts               compact text renderer for showtimes
  cache.ts                tiny TTL cache
  http.ts                 fetch wrapper, retries, session cookie replay
  dates.ts                today-in-Rome, date validation, time compare
  types.ts                internal model shared by all connectors
test/
  *.test.ts               vitest unit tests
  fixtures/{uci,thespace} saved real responses, trimmed
scripts/
  mcp-call.mjs            tiny JSON-RPC stdio driver used to verify end-to-end
  AGENTS.md               design brief

Upstream APIs (unofficial, no auth)

UCI Cinemas

https://myuci---uci-backend-production-nfluwp7wga-oc.a.run.app/api

  • GET /theatres — list (id, name, slug, is_luxe, latitude, …). The slug is the cinema id.

  • GET /theatres/{slug}/programming/{YYYY-MM-DD} — the programming for one day. cart_link is relative to https://ucicinemas.it.

The Space Cinema

https://www.thespacecinema.it/api/microservice/showings

  • GET /cinemas — {result: [{alpha, cinemas: [cinema]}]}. No city field: fullName is best-effort, exposed as-is.

  • GET /cinemas/{cinemaId}/films?showingDate=YYYY-MM-DDT00:00:00&minEmbargoLevel=3&includesSession=true&includeSessionAttributes=true One query string, not all separate. bookingUrl is relative to https://www.thespacecinema.it/.

An in-memory cookie jar in src/http.ts preserves the session cookies the site sets across calls, the way a browser would, so consecutive requests in the same session are accepted. We do not perform any challenge solving or attempt to bypass upstream policies — we only store and replay whatever the server gave us. Cinema metadata is cached for 24 h, showtimes for 5 min (src/service.ts).

Out of scope (for now)

Remote HTTP transport, Webtic/18tickets connectors, seat maps.

Available Tools

3 tools
get_showtimesA

Showtimes for the given cinemas on a date, with optional time window and title substring filters. Returns a compact text view grouped by film and cinema: time, and only the format/language tags that deviate from the chain default (2D in Italian -> nothing; e.g. '21:30 IMAX', '20:20 EN', '21:30 ISENSE' otherwise). Italian is the default language and is omitted; EN, OV are normalised. Sold-out shows are tagged '(sold out)'. Booking links stay off by default; pass include_links=true to add them. Pass chain to restrict to one chain or a list (e.g. chain: 'uci' for loyalty promotions); cinema ids that belong to other chains are dropped.

Time axis: each requested date is a 'cinema day' that spans [date 06:00, date+1 06:00) in Europe/Rome. from_time/to_time earlier than 06:00 means the next calendar day (e.g. to_time '01:00' is 'until 01:00+1'). Showtimes after midnight are rendered with a '+1' marker ('22:00+1' is too far east to happen in practice; '00:30+1' is the usual case). If a film has only out-of-window showtimes at a cinema, that cinema line becomes 'cinema - none in window (N earlier, last HH:MM)'; if the film has zero in-window shows anywhere, an 'Outside the time window:' line is appended.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateNoYYYY-MM-DD in Europe/Rome; defaults to today.
chainNoRestrict the query to one chain or a list of chains. Cinema ids that do not belong to the allowed chain(s) are skipped. Use this for loyalty promotions (e.g. only uci) or to compare apples to apples.
to_timeNoLatest showtime to include (HH:MM).
from_timeNoEarliest showtime to include (HH:MM).
cinema_idsYesCinema ids from list_cinemas.
include_linksNoIf true, append the booking URL inside [brackets] next to each showtime.
title_containsNoCase-insensitive substring the film title must contain.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and discloses output format (compact text grouped by film and cinema), default language omission, sold-out tagging, and the time axis convention (06:00 boundary, +1 marker). It also explains out-of-window handling, providing an unusually detailed behavioral contract.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though lengthy, every sentence adds necessary behavioral detail; the first sentence front-loads the core purpose. The text is structured into general behavior and time-axis specifics without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain return values, and it does so exhaustively: formatting, language tags, sold-out marks, links, and edge cases. For a 7-parameter tool with no annotations, this is complete enough to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds value by explaining the date's 'cinema day' span and the meaning of from_time/to_time earlier than 06:00. It also clarifies chain filtering behavior and include_links default, which the schema only names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with 'Showtimes for the given cinemas on a date, with optional time window and title substring filters,' naming the resource and filters. It clearly distinguishes from siblings list_cinemas and list_films by focusing on showtimes for specific cinemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives usage context for chain ('Pass chain to restrict to one chain... e.g. chain: 'uci' for loyalty promotions') and include_links ('Booking links stay off by default; pass include_links=true'). It implies the tool is for retrieving showtimes, but it does not explicitly name alternative tools or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_cinemasA

List every cinema we know about, optionally filtered to a single chain. Call this once at the start of a session to discover cinema ids. Ids are namespaced like uci:slug or thespace:numericId and are needed by the other tools.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNouci or thespace; omit for both.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It transparently discloses that it lists all known cinemas, optionally filters by chain, and that IDs follow a namespaced format ('uci:slug' or 'thespace:numericId'). It does not mention return structure beyond IDs or pagination, but for a simple list tool this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each carrying distinct information: what the tool does, when to call it, and the format/importance of the IDs. No wasted words or repetitive content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

In the absence of an output schema and annotations, the description gives essential operational context: when to call, the purpose (discovering IDs), the ID namespace, and their role in the broader API. It could be more precise about the full result shape, but it is sufficient for an agent to use the tool correctly in a discovery workflow.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents the 'chain' parameter with its enum and 'omit for both' behavior. The description only restates the optional filter, adding nothing beyond what the schema provides, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource ('List every cinema we know about') and mentions the optional chain filter. It also states that the returned cinema IDs are needed by the other tools, which clearly distinguishes it from the sibling tools list_films and get_showtimes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use guidance: 'Call this once at the start of a session to discover cinema ids.' It also explains that the IDs are needed by other tools, establishing it as a prerequisite. However, it does not explicitly contrast it with alternatives or state when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_filmsA

Cheap overview of the films playing in the given cinemas on the given date, without showtimes. Use this after list_cinemas to discover which films are worth querying with get_showtimes. Pass chain to restrict to one chain or a list of chains (e.g. chain: 'uci' for loyalty promotions); cinema ids that belong to other chains are dropped.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateNoYYYY-MM-DD in Europe/Rome; defaults to today.
chainNoRestrict the query to one chain or a list of chains. Cinema ids that do not belong to the allowed chain(s) are skipped. Use this for loyalty promotions (e.g. only uci) or to compare apples to apples.
cinema_idsYesCinema ids from list_cinemas.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that the tool is 'cheap' (cost/performance), that it returns 'without showtimes' (content limitation), and that 'cinema ids that belong to other chains are dropped' (filtering behavior). These go beyond the schema and give the agent a realistic expectation of the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler. The first sentence front-loads the core purpose and limitation, the second provides workflow and parameter context. Every sentence earns its place, and the structure is easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must convey what the tool returns. It states it provides an 'overview of the films playing' and that it's used to 'discover which films are worth querying,' implying it returns film identifiers. While it doesn't enumerate exact fields or pagination, it's sufficient for a simple listing tool in the given workflow. Minor gap: no explicit mention of return format, but not critical.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds extra semantic value for the chain parameter by explaining its use case ('loyalty promotions', 'compare apples to apples') and reiterating the filtering behavior. This goes beyond the schema's description and helps the agent choose the right value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb ('list') and resource ('films'), and adds critical scope: 'playing in the given cinemas on the given date, without showtimes.' It also differentiates from siblings by explicitly positioning it between list_cinemas and get_showtimes, so an agent can immediately tell what this tool does and how it fits.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit workflow guidance: 'Use this after list_cinemas to discover which films are worth querying with get_showtimes.' It also explains the chain parameter's purpose ('for loyalty promotions') and the filtering behavior, leaving no ambiguity about when and how to invoke the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedget_showtimes
    • First observedlist_cinemas
    • First observedlist_films

TDQS

A4.6/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct role: list_cinemas discovers venue identifiers, list_films provides a film overview, and get_showtimes gives detailed timings. There is no overlap or ambiguity between them.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern: list_cinemas, list_films, get_showtimes. The 'list_' prefix for overviews and 'get_' for detailed retrieval is a clear and predictable convention.

Tool Count5/5

Three tools is well-scoped for a cinema showtimes server. Each tool serves a necessary step in the discovery workflow, and none feels redundant or extraneous.

Completeness5/5

The tool surface covers the full user journey: discover cinemas, identify films, and retrieve showtimes. There are no obvious gaps; the inclusion of filters and options makes the workflow complete for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Provides a comprehensive movie booking experience for AMC Theatres, enabling users to discover movies, find showtimes, select seats, and process payments through conversational AI. Supports multi-location theater search with real-time seat availability and booking management.
    6
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables users to search for movies and retrieve showtimes from Allociné, including cinema locations, screening times, and formats (VF, VOST, 3D, IMAX) for specific cities or postal codes in France.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides movie listings, showtimes, and personalized recommendations for Amsterdam cinemas by scraping filmladder.nl, with support for filtering by date, cinema, rating, and preferred showtimes.
    1
    -