- Python 97.3%
- Shell 2.7%
| .github/workflows | ||
| src/apple_tv_mcp | ||
| tests | ||
| .gitignore | ||
| .sanity-patterns.json | ||
| check_pyatv_update.sh | ||
| LICENSE | ||
| pair_companion.py | ||
| pair_interactive.py | ||
| pyproject.toml | ||
| qa.py | ||
| README.md | ||
| WHITEPAPER.md | ||
apple-tv-mcp
Local MCP server that controls your Apple TV 4K over the LAN, using pyatv's Companion protocol with stored pairing credentials, plus YouTube cast control via the YouTube Lounge API.
License: MIT
The problem it solves
Automating the Apple TV normally requires Siri, the physical remote, or Shortcuts. This server exposes the Apple TV as MCP tools so any connected LLM can press buttons, switch apps, type text, and play YouTube videos directly, with no on-screen keyboard navigation and no manual remote needed.
Install
This is a Python MCP server installed in a local venv. Install once, then register it as a stdio transport in your MCP client.
# From the repo root
python -m venv .venv
.venv/bin/pip install -e .
# Run directly
.venv/bin/apple-tv-mcp
For one-shot install via uvx (Python public repo pattern):
uvx --from git+https://github.com/nidamen/apple-tv-mcp apple-tv-mcp
MCP client config
Add the following to your MCP client config (e.g. ~/.claude.json under
mcpServers):
{
"mcpServers": {
"appletv": {
"command": "/path/to/apple-tv-mcp/.venv/bin/apple-tv-mcp",
"args": [],
"env": {
"APPLE_TV_HOST": "192.168.1.14",
"APPLE_TV_CREDS": "~/.config/apple-tv-mcp/companion.creds"
}
}
}
}
Restart Claude Code (or your MCP client) after registering. The tools appear
under the prefix appletv_ and youtube_.
Pairing (one-time setup)
Companion (remote control)
# Start pairing -- a PIN appears on the Apple TV screen
APPLE_TV_HOST=192.168.1.14 .venv/bin/python pair_companion.py &
# Write the PIN when it appears on screen
echo 1234 > /tmp/atv_pin
# Copy credentials to the config directory
mkdir -p ~/.config/apple-tv-mcp
cp /tmp/atv_companion_creds.txt ~/.config/apple-tv-mcp/companion.creds
The PIN window is short (about 2 minutes). If it expires, rerun pair_companion.py.
AirPlay (optional, for now-playing metadata)
On tvOS 15+, the now-playing/metadata feed is tunnelled over AirPlay. Without
AirPlay credentials appletv_now_playing returns state Idle. Pair AirPlay
by setting PAIR_PROTOCOL=airplay and running pair_companion.py again, then
save the result to ~/.config/apple-tv-mcp/airplay.creds.
YouTube (cast control)
Open the YouTube app on the Apple TV, go to Settings, select "Link with TV code",
and pass the displayed code to youtube_pair. This stores a lounge token at
~/.config/apple-tv-mcp/youtube_lounge.json and enables cast playback.
Complete tool reference
Apple TV control tools
| Tool | Parameters | Purpose |
|---|---|---|
appletv_status |
none | Report paired/reachable/connected status, device model, and tvOS version |
appletv_now_playing |
none | Return current title, app, device state, position, and total time |
appletv_press |
key (str, required), repeat (int, 1-50, default 1) |
Press a remote key N times |
appletv_type_text |
text (str, required) |
Set the focused on-screen text field to this string in one shot |
appletv_clear_text |
none | Clear the focused on-screen text field |
appletv_wake |
none | Wake the Apple TV by pressing Home; via HDMI-CEC this also makes the Apple TV the active TV input |
appletv_launch_app |
app (str, required) |
Launch an app by friendly name or raw tvOS bundle id |
appletv_app_list |
none | List installed apps and their bundle ids (may error on tvOS 26) |
appletv_keys |
none | Return the accepted key names and known app friendly names |
Accepted key names for appletv_press:
up, down, left, right, select (aliases: ok, enter), menu / back,
home, home_hold, play_pause, play, pause, stop, next, previous / prev,
rewind / skip_backward, fast_forward / forward / skip_forward,
volume_up, volume_down
Known app names for appletv_launch_app:
netflix, youtube, prime / prime video, disney / disney+,
hulu, max / hbo max, appletv / apple tv / tv, music,
spotify, plex, twitch, paramount / paramount+, peacock,
espn, tubi
YouTube tools
| Tool | Parameters | Purpose |
|---|---|---|
youtube_pair |
code (str, required) |
One-time pairing with the Apple TV's YouTube app using the "Link with TV code" |
youtube_search |
query (str, required), limit (int, 1-20, default 5) |
Search YouTube and return video ids, titles, uploaders, and durations |
youtube_play |
query (str, required) |
Resolve query to top result and cast it to the Apple TV's YouTube app |
youtube_enqueue |
query (str, required) |
Add the top result to the YouTube up-next queue without interrupting current playback |
youtube_play_video_id |
video_id (str, required) |
Cast a specific YouTube video id directly |
youtube_watch |
query (str, required) |
Reliably play a video end-to-end: opens YouTube, casts, and confirms playback position is advancing, automatically clearing the profile picker or any modal |
youtube_status |
none | Report whether YouTube is paired and the cast session can reach the app |
Environment variables
| Variable | Default | Purpose |
|---|---|---|
APPLE_TV_HOST |
192.168.1.14 |
IP address of the Apple TV |
APPLE_TV_CREDS |
~/.config/apple-tv-mcp/companion.creds |
Path to Companion pairing credentials |
APPLE_TV_AIRPLAY_CREDS |
~/.config/apple-tv-mcp/airplay.creds |
Path to AirPlay credentials (optional, enables now-playing metadata) |
YOUTUBE_LOUNGE_CREDS |
~/.config/apple-tv-mcp/youtube_lounge.json |
Path to YouTube Lounge token (set by youtube_pair) |
Transport
stdio, local only. The server runs on the same machine as the MCP client (or on
a Raspberry Pi via SSH-stdio). It connects to the Apple TV at
APPLE_TV_HOST over the LAN using pyatv's Companion protocol.
Usage examples
"Is the Apple TV on and what is playing?"
Call appletv_status to check connectivity, then appletv_now_playing for the
current title and app.
"Play 2Pac - Changes on YouTube"
Call youtube_watch "2pac changes". It opens YouTube, resolves the query to a
video id via yt-dlp, casts it, and confirms playback is advancing before returning.
"Turn the volume down 5 times"
Call appletv_press with key="volume_down" and repeat=5.
Limitations
- Requires the Apple TV to be reachable on the LAN at
APPLE_TV_HOST. - pyatv Companion pairing must be completed once before any control tool works.
appletv_now_playingreturnsIdlestate unless AirPlay credentials are also paired (tvOS 15+ tunnels metadata over AirPlay).appletv_app_listmay return an error on tvOS 26 due to Apple API restrictions.- YouTube cast (
youtube_play,youtube_enqueue,youtube_play_video_id,youtube_watch) requires the YouTube lounge token fromyoutube_pairand the YouTube app to be open on the Apple TV. - tvOS profile picker (the "who's watching" prompt) blocks YouTube casts;
youtube_watchauto-clears it by pressing select and retrying, but the otheryoutube_play*tools do not. - AirPlay creds have no standard revoke/refresh UI; if the Apple TV is reset, both Companion and AirPlay credentials must be re-paired.