io.github.cyanheads/tvmaze-mcp-server
TVmaze shows, people, next episodes in your timezone, episode guides, schedules, and credits.
What can you do with io.github.cyanheads/tvmaze-mcp-server?
- Keyless — no account, no API key, and every tool works on a fresh install with nothing configured
- Requests are paced under TVmaze's per-IP limit, back off on 429 (honoring
Retry-After), and are cached in-process - Air times are computed from
airstampalone, sinceairdate/airtimecan be a full day off on overnight slots - Community-authored HTML summaries are stripped to plain text
- No fabricated clock times: a record with no announced time reports
time_known: falseand a date only, and absent fields render asNot availablerather than0or"" - Typed errors on every tool, each with a
reasonand a recovery hint - Resolution misses are results:
tvmaze_lookup_showand the title arm oftvmaze_get_next_episodereturnfound: falsewithguidancefor the next call - Output states what a call covered: the echoed query,
applied_feeds, pre-page totals, and truncation against the source's caps
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
claude mcp add --transport http tvmaze-mcp-server 'https://tvmaze.caseyjhand.com/mcp'
{
"mcpServers": {
"tvmaze-mcp-server": {
"type": "http",
"url": "https://tvmaze.caseyjhand.com/mcp"
}
}
}
@cyanheads/tvmaze-mcp-serverclaude mcp add tvmaze-mcp-server -e 'TVMAZE_BASE_URL=https://api.tvmaze.com' -e 'TVMAZE_USER_AGENT=<TVMAZE_USER_AGENT>' -e 'TVMAZE_DEFAULT_TIMEZONE=UTC' -e 'TVMAZE_DEFAULT_COUNTRY=US' -e 'TVMAZE_CACHE_TTL_S=300' -e 'TVMAZE_MAX_CONCURRENCY=4' -e 'TVMAZE_REQUEST_TIMEOUT_MS=10000' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/tvmaze-mcp-server@0.3.0
{
"mcpServers": {
"tvmaze-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/tvmaze-mcp-server@0.3.0"
],
"env": {
"TVMAZE_BASE_URL": "https://api.tvmaze.com",
"TVMAZE_USER_AGENT": "<TVMAZE_USER_AGENT>",
"TVMAZE_DEFAULT_TIMEZONE": "UTC",
"TVMAZE_DEFAULT_COUNTRY": "US",
"TVMAZE_CACHE_TTL_S": "300",
"TVMAZE_MAX_CONCURRENCY": "4",
"TVMAZE_REQUEST_TIMEOUT_MS": "10000",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Environment variables
TVMAZE_BASE_URLTVmaze API base URL. Override to point at an enterprise endpoint.TVMAZE_USER_AGENTUser-Agent sent on every upstream request. TVmaze asks that clients identify themselves. Defaults to the server name, version, and repository URL.TVMAZE_DEFAULT_TIMEZONEIANA timezone used when a tool call omits 'timezone' (e.g. 'America/Los_Angeles').TVMAZE_DEFAULT_COUNTRYISO 3166-1 alpha-2 country used for tvmaze_get_schedule scopes 'linear' and 'all' when 'country' is omitted.TVMAZE_CACHE_TTL_SSeconds to hold an upstream response in the in-process cache. 0 disables caching.TVMAZE_MAX_CONCURRENCYConcurrent upstream requests.TVMAZE_REQUEST_TIMEOUT_MSPer-request timeout in milliseconds.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
@cyanheads/tvmaze-mcp-serverclaude mcp add tvmaze-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'TVMAZE_BASE_URL=https://api.tvmaze.com' -e 'TVMAZE_USER_AGENT=<TVMAZE_USER_AGENT>' -e 'TVMAZE_DEFAULT_TIMEZONE=UTC' -e 'TVMAZE_DEFAULT_COUNTRY=US' -e 'TVMAZE_CACHE_TTL_S=300' -e 'TVMAZE_MAX_CONCURRENCY=4' -e 'TVMAZE_REQUEST_TIMEOUT_MS=10000' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/tvmaze-mcp-server@0.3.0
{
"mcpServers": {
"tvmaze-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/tvmaze-mcp-server@0.3.0"
],
"env": {
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"TVMAZE_BASE_URL": "https://api.tvmaze.com",
"TVMAZE_USER_AGENT": "<TVMAZE_USER_AGENT>",
"TVMAZE_DEFAULT_TIMEZONE": "UTC",
"TVMAZE_DEFAULT_COUNTRY": "US",
"TVMAZE_CACHE_TTL_S": "300",
"TVMAZE_MAX_CONCURRENCY": "4",
"TVMAZE_REQUEST_TIMEOUT_MS": "10000",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_AUTH_MODE": "none",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Environment variables
MCP_TRANSPORT_TYPESelects the HTTP transport.TVMAZE_BASE_URLTVmaze API base URL. Override to point at an enterprise endpoint.TVMAZE_USER_AGENTUser-Agent sent on every upstream request. TVmaze asks that clients identify themselves. Defaults to the server name, version, and repository URL.TVMAZE_DEFAULT_TIMEZONEIANA timezone used when a tool call omits 'timezone' (e.g. 'America/Los_Angeles').TVMAZE_DEFAULT_COUNTRYISO 3166-1 alpha-2 country used for tvmaze_get_schedule scopes 'linear' and 'all' when 'country' is omitted.TVMAZE_CACHE_TTL_SSeconds to hold an upstream response in the in-process cache. 0 disables caching.TVMAZE_MAX_CONCURRENCYConcurrent upstream requests.TVMAZE_REQUEST_TIMEOUT_MSPer-request timeout in milliseconds.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Contents
@cyanheads/tvmaze-mcp-server
Search TVmaze shows and people, next episodes in your timezone, episode guides, daily schedules, and credits via MCP. STDIO or Streamable HTTP.
8 Tools
Public Hosted Server: https://tvmaze.caseyjhand.com/mcp
Overview
TV data from TVmaze: shows, episode guides, cast, and air times. Find a show by title or IMDb/TheTVDB id, see when the next episode airs in your timezone, or check what aired and streamed on any date. No API key required.
Tools
| 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_get_person | Search person names for candidates, or page one person's cast, guest, or crew credits |
Capability reference
tvmaze_search_shows tool
- Fuzzy-matches
queryagainst every show title, so minor misspellings still resolve; blank titles are rejected - Returns at most 10 shows with no pagination; output reports
shown/capand points a full or empty result to a narrower title ortvmaze_lookup_show - Rows carry the shared show summary plus
match_score, comparable only within one result set
tvmaze_get_show tool
show_idfromtvmaze_search_shows,tvmaze_lookup_show, or a schedule row; optional IANAtimezonefor episode times- Returns the full profile (
schedule_days/schedule_time, optionalschedule_timezone,official_site,externals) with every season plusnext_episode/previous_episode. ARunningshow with nothing announced comes back with a notice pointing atprevious_episode - An unknown
show_idfails asshow_not_found
tvmaze_lookup_show tool
sourceisimdb(attid),thetvdb, ortvrage(defunct, present only in older records), paired withexternal_id- IMDb ids also accept bare digits, uppercase
TT, andimdb.comtitle URLs - A show absent from TVmaze is a result, not an error:
found: falseplusguidancerouting totvmaze_search_shows. A hit echoessourceandexternal_idand returns the same show summary as search
tvmaze_get_next_episode tool
by: "id"takes a TVmaze id;by: "title"resolves a non-blank title through a stricter single-match search thantvmaze_search_shows- Air times render in the requested IANA
timezone;time_known: falsemeans no clock time was announced, so only the date is reliable - Misses carry a typed
miss_reason:show_not_found(title) orno_scheduled_episode(between seasons, withprevious_episode). Ashow_idthat resolves to nothing throwsshow_not_found_by_id
tvmaze_get_episodes tool
seasonlists one season;air_date(YYYY-MM-DD) lists one day's episodes; omit both for the whole run. They cannot be combined. An empty day returns an empty list with a notice, an impossible date fails asinvalid_date, andseason_not_foundnames the seasons that existair_datematches the source'sairdate, which can differ by a day from an episode'slocal_dateon late-night slotsinclude_specialsdefaults to false, and each listing reports how many specials it filtered out.limit(default 50, max 250) sets page size;next_cursor/has_morecontinue the listing andtotalCountcounts before paging
tvmaze_get_schedule tool
scopepicks the feed:linearis one country's broadcast and cable networks plus its own streaming services,streamingis global services whencountryis omitted and that country's local ones when given,allmerges bothdatedefaults to today in the requestedtimezone;countryis ISO 3166-1 alpha-2 (the United Kingdom isGB) and falls back to the configured default forlinearandall; optionalchannelfilters by exact, case-insensitive channel name;limitdefaults to 50 (max 250)- Entries carry
feed(linear/streaming) and a compactshowreference (tvmaze_get_showreturns the full profile).applied_feedsnames the feeds that answered, e.g.["linear:GB","web:GB","web:global"]; one failing feed degrades to a notice instead of failing the call
tvmaze_get_cast tool
scope: "show"returns the main cast with character names;scope: "episode"returns that episode's guest cast.include_crewadds the show's crew, or the episode's guest crew (director, writers)- Optional
namefilters by substring of performer, character, or crew role (crew only withinclude_crew: true). Paged withlimit(default 50, max 250) andcursor;cast_total/crew_totalcount all matching credits - Cast credits carry
as_selfandvoice_only; crew credits carrycredit_typeand no character. A show's cast list does not separate recurring from guest performers, so check an episode's guest cast. Missing credits arrive as a notice, not an error
tvmaze_get_person tool
- Supply exactly one of
query(name search) orperson_id(from cast credits or a candidate). Search returns compact candidates with source scores and never picks one for you; ten candidates may mean the source cap, so narrow the name - A
person_idreturns the person and onecredit_kind:cast(default),guest, orcrew;limit(default 50, max 250) andcursorapply only here. Guestepisode_idchains totvmaze_get_cast;show_idchains totvmaze_get_showortvmaze_get_episodes - No candidates or credits is an empty success; a missing id is
person_not_found
Features
Built 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:
- Keyless — no account, no API key, and every tool works on a fresh install with nothing configured
- Requests are paced under TVmaze's per-IP limit, back off on 429 (honoring
Retry-After), and are cached in-process - Air times are computed from
airstampalone, sinceairdate/airtimecan be a full day off on overnight slots - Community-authored HTML summaries are stripped to plain text
Agent-friendly output:
- No fabricated clock times: a record with no announced time reports
time_known: falseand a date only, and absent fields render asNot availablerather than0or"" - Typed errors on every tool, each with a
reasonand a recovery hint - Resolution misses are results:
tvmaze_lookup_showand the title arm oftvmaze_get_next_episodereturnfound: falsewithguidancefor the next call - Output states what a call covered: the echoed query,
applied_feeds, pre-page totals, and truncation against the source's caps
Data and licensing
Data 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.
Getting started
Public Hosted Instance
A public instance is available at https://tvmaze.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"tvmaze-mcp-server": {
"type": "streamable-http",
"url": "https://tvmaze.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file. No API key is required.
{
"mcpServers": {
"tvmaze-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/tvmaze-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"tvmaze-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/tvmaze-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"tvmaze-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/tvmaze-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No TVmaze account or API key. Set
TVMAZE_DEFAULT_TIMEZONEandTVMAZE_DEFAULT_COUNTRYonce if the calls should default to somewhere other than UTC and the US.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/tvmaze-mcp-server.git
- Navigate into the directory:
cd tvmaze-mcp-server
- Install dependencies:
bun install
- Configure environment (optional):
cp .env.example .env
# every variable is optional — edit only what you want to override
Configuration
| 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 is always stateless. | 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 |
LOG_TOOL_FAILURE_PAYLOADS | Log a failed tool call's arguments and result (key-name redaction only). | false |
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.
Running the server
Local development
- Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http - Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t tvmaze-mcp-server .
docker run --rm -p 3010:3010 tvmaze-mcp-server
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.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers the eight 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. |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging; every upstream call goes throughTvmazeService, neverfetchfrom a handler - Register new tools in the
createApp()arrays insrc/index.ts - Keep the upstream boundary in the service: validate raw → normalize to the domain type → return the output schema, and never fabricate a missing field — an absent air time stays absent
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Frequently asked questions
What is io.github.cyanheads/tvmaze-mcp-server?
TVmaze shows, people, next episodes in your timezone, episode guides, schedules, and credits.
How do I install io.github.cyanheads/tvmaze-mcp-server?
It runs as a remote server. In Claude Code: claude mcp add --transport http tvmaze-mcp-server 'https://tvmaze.caseyjhand.com/mcp'. For other clients, paste the JSON configuration from this page into their MCP settings.
Does io.github.cyanheads/tvmaze-mcp-server need an API key?
Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.
Is io.github.cyanheads/tvmaze-mcp-server open source?
Yes. Its code is on GitHub under the Apache-2.0 license.
Who maintains io.github.cyanheads/tvmaze-mcp-server?
It is published by cyanheads. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.