The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Tvmaze MCP Server listing page.
Search TVmaze shows, next episodes in your timezone, episode guides, daily TV schedules, and cast via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://tvmaze.caseyjhand.com/mcp
Television data from TVmaze — a community-maintained database of series, episodes, air times, and credits, served by a keyless public API. Find a show by title or by its IMDb, TheTVDB, or TVRage id, then read its profile, season episode guides, and cast, or ask when the next episode airs in a viewer's timezone. A whole date works as the starting point too: what a country's networks broadcast that day, what the global streaming services released, or both merged. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| Tool | Description |
|---|---|
tvmaze_search_shows | Fuzzy title search returning up to 10 shows with channel, status, genres, rating, and external catalog ids |
tvmaze_get_show | Full profile for one TVmaze id — weekly slot, season list, and the previous and next episode |
tvmaze_lookup_show | Resolve a show from its IMDb, TheTVDB, or TVRage id into the matching TVmaze profile |
tvmaze_get_next_episode | When a show's next episode airs, by TVmaze id or title, converted to a viewer timezone |
tvmaze_get_episodes | Episode guide for one season, one air date, or the whole run, with air times, runtimes, and synopses |
tvmaze_get_schedule | Episodes airing on a date — broadcast and cable networks in one country, streaming services, or both |
tvmaze_get_cast | A show's credited cast and the characters they play, optionally crew; or one episode's guest cast, optionally with its director and writers |
tvmaze_search_shows toolquery against every show title, so minor misspellings still resolveshown / cap, and the notice routes a saturated or empty result to a narrower title or to tvmaze_lookup_showmatch_score, which is comparable only within one result settvmaze_get_show toolshow_id from tvmaze_search_shows, tvmaze_lookup_show, or a schedule row; optional IANA timezone for the rendered episode timesschedule_days / schedule_time, official_site, externals — with every season and the next_episode / previous_episode the source hasRunning show with nothing announced comes back with a notice pointing at previous_episode rather than a silently empty fieldshow_id fails as a typed show_not_foundtvmaze_lookup_show toolsource of three — imdb (a tt id), thetvdb, or tvrage (defunct, present only in older records) — paired with external_idfound: false plus guidance routing to tvmaze_search_showssource and external_id; a hit returns the same show summary the search tool doestvmaze_get_next_episode toolby: "id" takes a TVmaze id; by: "title" resolves a title through a stricter single-match search than tvmaze_search_shows usestimezone; time_known: false means the source announced no clock time, so only the date is reliablemiss_reason — show_not_found on the title arm, no_scheduled_episode for a series between seasons, the latter still carrying previous_episode; the text output's headline names the same missshow_id that resolves to nothing throws show_not_found_by_id; an unresolvable title is a misstvmaze_get_episodes toolseason lists one season (the cheaper path); air_date (YYYY-MM-DD) lists the episodes dated to one day, the direct way to find one night of a daily show; omit both to walk the whole run. season and air_date cannot be combinedair_date matches the source's airdate, the broadcaster's programming day, which can differ by a day from an episode's local_date on a late-night slot. A day with nothing on it returns an empty list with a notice; a date that is not on the calendar fails as invalid_dateinclude_specials defaults to false; every listing, whether season, air date, or whole run, reports how many specials it filtered outlimit 1–250 (default 50) sets the page size on every call, including one that passes cursor; next_cursor / has_more continue the listing, and enrichment carries the pre-page totalCount plus truncated / shown / cap on a partial pageseason_not_found failure names the seasons that do existtvmaze_get_schedule toolscope picks the feed: linear is one country's broadcast and cable networks plus its own streaming services, streaming is global services when country is omitted and that country's local ones when it is given, all merges both across three upstream requestsdate defaults to today in the requested timezone; country is ISO 3166-1 alpha-2 (the United Kingdom is GB) and falls back to the configured default for linear and allfeed (linear / streaming) alongside the episode; a merged query dedupes and sorts by airstampshow is a compact reference — id, name, url, type, genres, and the channel — since a day's listing repeats a show on every episode; tvmaze_get_show returns the full profileapplied_feeds names exactly which upstream feeds answered, e.g. ["linear:GB","web:GB","web:global"]; one feed failing degrades to a notice instead of failing the calllimit 1–250 (default 50) sets the page size on every call, including one that passes cursor — a country day runs to roughly 50 broadcast entries, the global streaming feed to over 120tvmaze_get_cast toolscope: "show" returns the main cast with character names, plus the show's crew when include_crew is set; scope: "episode" returns that episode's guest cast, plus its guest crew (director, writers) when include_crew is set, still in a single upstream requestlimit 1–250 (default 50) and cursor, with cast rows first and crew rows after them in one sequence, split back into cast and crew on each page; cast_total / crew_total and the enrichment totalCount count every pageas_self and voice_only; crew credits carry credit_type and no characterBuilt 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.
TVmaze-specific:
Retry-After, in front of an in-process response cache shared across tenantsairstamp alone; the airdate / airtime pair is the broadcaster's programming-day convention and diverges by a full day on overnight slotsAgent-friendly output:
time_known: false and a date only, and absent upstream fields render as Not available rather than 0 or ""reason plus a recovery hint that reaches both structuredContent and the text surfacetvmaze_lookup_show and the title arm of tvmaze_get_next_episode return found: false with guidance for the next callapplied_feeds, pre-page totals, and truncation against the source's own capsData comes from TVmaze and is licensed CC BY-SA. Credit TVmaze as the source and keep the url field that every show, episode, and person record carries — linking back is what satisfies attribution. Under ShareAlike, an adaptation of this data must be shared under the same licence.
TVmaze rate-limits to at least 20 calls every 10 seconds per IP address and answers a burst past that with HTTP 429; the server paces itself under that budget and backs off when one arrives. Upstream caches its output for 60 minutes, so a schedule change or a newly announced episode can take up to an hour to appear; the local response cache (TVMAZE_CACHE_TTL_S, default 300 s) sits well inside that window.
A public instance is available at https://tvmaze.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
Add the following to your MCP client configuration file. No API key is required.
Or with npx (no Bun required):
Or with Docker:
For Streamable HTTP, set the transport and start the server:
TVMAZE_DEFAULT_TIMEZONE and TVMAZE_DEFAULT_COUNTRY once if the calls should default to somewhere other than UTC and the US.| Variable | Description | Default |
|---|---|---|
TVMAZE_BASE_URL | TVmaze API base URL. Override to point at an enterprise endpoint. | https://api.tvmaze.com |
TVMAZE_USER_AGENT | User-Agent sent on every upstream request; TVmaze asks that clients identify themselves. | server name, version, and repository URL |
TVMAZE_DEFAULT_TIMEZONE | IANA timezone used when a tool call omits timezone. | UTC |
TVMAZE_DEFAULT_COUNTRY | ISO 3166-1 alpha-2 country used for tvmaze_get_schedule scopes linear and all when country is omitted. | US |
TVMAZE_CACHE_TTL_S | Seconds to hold an upstream response in the in-process cache. 0 disables caching. | 300 |
TVMAZE_MAX_CONCURRENCY | Concurrent upstream requests (1–16). | 4 |
TVMAZE_REQUEST_TIMEOUT_MS | Per-request timeout in milliseconds (1000–120000). | 10000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
MCP_HTTP_ENDPOINT_PATH | Path the MCP server is mounted at. | /mcp |
MCP_SESSION_MODE | HTTP session mode. This server declares stateless in code — no tool asks the caller for input mid-handler. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs). | false |
See .env.example for the full list of optional overrides.
Build and run:
Run checks and tests:
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/tvmaze-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers the seven tools, server instructions, and the service lifecycle. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts) and the output schemas they share. |
src/services/tvmaze | TVmaze REST client — pacing, retries, response cache, and normalization into the domain types. |
tests/ | Unit and integration tests mirroring src/. |
docs/ | Design document and the generated project tree. |
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging; every upstream call goes through TvmazeService, never fetch from a handlercreateApp() arrays in src/index.tsIssues are welcome. Run checks and tests before submitting:
Apache-2.0 — see LICENSE for details.