MCP-AppleMusic
by kennethreitz
Verified
import subprocess
from mcp.server.fastmcp import FastMCP
def run_applescript(script: str) -> str:
"""Execute an AppleScript command via osascript and return its output."""
result = subprocess.run(["osascript", "-e", script], capture_output=True, text=True)
if result.returncode != 0:
return f"Error: {result.stderr.strip()}"
return result.stdout.strip()
# Instantiate the MCP server.
mcp = FastMCP("iTunesControlServer")
@mcp.tool()
def itunes_play() -> str:
"""Start playback in Music (iTunes)."""
script = 'tell application "Music" to play'
return run_applescript(script)
@mcp.tool()
def itunes_pause() -> str:
"""Pause playback in Music (iTunes)."""
script = 'tell application "Music" to pause'
return run_applescript(script)
@mcp.tool()
def itunes_next() -> str:
"""Skip to the next track."""
script = 'tell application "Music" to next track'
return run_applescript(script)
@mcp.tool()
def itunes_previous() -> str:
"""Return to the previous track."""
script = 'tell application "Music" to previous track'
return run_applescript(script)
@mcp.tool()
def itunes_search(query: str) -> str:
"""
Search the Music library for tracks whose names contain the given query.
Returns a list of tracks formatted as "Track Name - Artist".
"""
script = f"""
tell application "Music"
set trackList to every track of playlist "Library" whose name contains "{query}"
set output to ""
repeat with t in trackList
set output to output & (name of t) & " - " & (artist of t) & linefeed
end repeat
return output
end tell
"""
return run_applescript(script)
@mcp.tool()
def itunes_play_song(song: str) -> str:
"""
Play the first track whose name exactly matches the given song name.
Returns a confirmation message.
"""
script = f"""
tell application "Music"
set theTrack to first track of playlist "Library" whose name is "{song}"
play theTrack
return "Now playing: " & (name of theTrack) & " by " & (artist of theTrack)
end tell
"""
return run_applescript(script)
@mcp.tool()
def itunes_create_playlist(name: str, songs: str) -> str:
"""
Create a new playlist with the given name and add tracks to it.
'songs' should be a comma-separated list of exact track names.
Returns a confirmation message including the number of tracks added.
"""
# Split the songs string into a list.
song_list = [s.strip() for s in songs.split(",") if s.strip()]
if not song_list:
return "No songs provided."
# Build a condition string that matches any one of the song names.
# Example: 'name is "Song1" or name is "Song2"'
conditions = " or ".join([f'name is "{s}"' for s in song_list])
script = f"""
tell application "Music"
set newPlaylist to make new user playlist with properties {{name:"{name}"}}
set matchingTracks to every track of playlist "Library" whose ({conditions})
repeat with t in matchingTracks
duplicate t to newPlaylist
end repeat
return "Playlist \\"{name}\\" created with " & (count of tracks of newPlaylist) & " tracks."
end tell
"""
return run_applescript(script)
@mcp.tool()
def itunes_library() -> str:
"""
Return a summary of the Music library, including total tracks and user playlists.
"""
script = """
tell application "Music"
set totalTracks to count of every track of playlist "Library"
set totalPlaylists to count of user playlists
return "Total tracks: " & totalTracks & linefeed & "Total playlists: " & totalPlaylists
end tell
"""
return run_applescript(script)
def main():
mcp.run()
if __name__ == "__main__":
main()