Skip to main content
Glama
davehenke

rekordbox-mcp

get_track_details

Retrieve detailed track metadata, cue points, and play history from rekordbox DJ databases using a unique track identifier.

Instructions

Get detailed information about a specific track.

Args: track_id: The unique track identifier

Returns: Detailed track information including metadata, cue points, and play history

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
track_idYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The handler function for the 'get_track_details' tool, registered via @mcp.tool() decorator. It handles input validation via type hints, fetches the track from the RekordboxDatabase instance, and returns the track details as a dictionary using model_dump().
    @mcp.tool()
    async def get_track_details(track_id: str) -> Dict[str, Any]:
        """
        Get detailed information about a specific track.
        
        Args:
            track_id: The unique track identifier
            
        Returns:
            Detailed track information including metadata, cue points, and play history
        """
        if not db:
            raise RuntimeError("Database not initialized.")
        
        track = await db.get_track_by_id(track_id)
        if not track:
            raise ValueError(f"Track with ID {track_id} not found")
        
        return track.model_dump()
  • Pydantic BaseModel defining the output schema for track details, used in the tool's return value via model_dump().
    class Track(BaseModel):
        """
        Rekordbox track model with comprehensive metadata.
        """
        
        id: str = Field(..., description="Unique track identifier")
        title: str = Field(..., description="Track title")
        artist: str = Field(..., description="Track artist")
        album: Optional[str] = Field(None, description="Album name")
        genre: Optional[str] = Field(None, description="Musical genre")
        bpm: float = Field(0.0, description="Beats per minute")
        key: Optional[str] = Field(None, description="Musical key (e.g., '5A', '12B')")
        rating: int = Field(0, ge=0, le=5, description="Track rating (0-5)")
        play_count: int = Field(0, ge=0, description="Number of times played")
        length: int = Field(0, ge=0, description="Track length in seconds")
        file_path: Optional[str] = Field(None, description="Path to audio file")
        date_added: Optional[str] = Field(None, description="Date track was added to library")
        date_modified: Optional[str] = Field(None, description="Date track was last modified")
        
        # Additional metadata
        bitrate: Optional[int] = Field(None, description="Audio bitrate in kbps")
        sample_rate: Optional[int] = Field(None, description="Audio sample rate in Hz")
        color: Optional[str] = Field(None, description="Track color tag")
        comments: Optional[str] = Field(None, description="Track comments")
        
        @field_validator('key')
        @classmethod
        def validate_key(cls, v):
            """Validate musical key format."""
            if v and v not in []:  # Add valid key formats
                # Basic validation - could be more sophisticated
                pass
            return v
        
        def duration_formatted(self) -> str:
            """Get track duration in MM:SS format."""
            if self.length <= 0:
                return "0:00"
            
            minutes = self.length // 60
            seconds = self.length % 60
            return f"{minutes}:{seconds:02d}"
  • Supporting method in RekordboxDatabase class that retrieves a track by ID from the pyrekordbox database instance, filtering soft-deleted tracks and converting to Track model.
    async def get_track_by_id(self, track_id: str) -> Optional[Track]:
        """
        Get a specific track by its ID.
        
        Args:
            track_id: The track's unique identifier
            
        Returns:
            Track object if found, None otherwise
        """
        if not self.db:
            raise RuntimeError("Database not connected")
        
        try:
            # Get all content and find by ID, filtering out soft-deleted tracks
            all_content = list(self.db.get_content())
            active_content = [c for c in all_content if getattr(c, 'rb_local_deleted', 0) == 0]
            content_id = int(track_id)
            
            # Find content by ID
            for content in active_content:
                if content.ID == content_id:
                    return self._content_to_track(content)
            
            return None
        except (ValueError, Exception):
            return None
  • Private helper method that maps raw pyrekordbox Content objects to the structured Track Pydantic model, handling data type conversions and object extractions.
    def _content_to_track(self, content) -> Track:
        """
        Convert pyrekordbox content object to our Track model.
        
        Args:
            content: pyrekordbox content object
            
        Returns:
            Track model instance
        """
        # Handle BPM - it's stored as integer * 100 in the database
        bpm_value = getattr(content, 'BPM', 0) or 0
        bpm_float = float(bpm_value) / 100.0 if bpm_value else 0.0
        
        # Handle artist - it might be an object or string
        artist_name = ""
        if hasattr(content, 'ArtistName'):
            artist_name = content.ArtistName or ""
        elif hasattr(content, 'Artist'):
            artist_obj = content.Artist
            if hasattr(artist_obj, 'Name'):
                artist_name = artist_obj.Name or ""
            else:
                artist_name = str(artist_obj) if artist_obj else ""
        
        # Handle key - it might be an object
        key_name = ""
        if hasattr(content, 'KeyName'):
            key_name = content.KeyName or ""
        elif hasattr(content, 'Key'):
            key_obj = content.Key
            if hasattr(key_obj, 'Name'):
                key_name = key_obj.Name or ""
            else:
                key_name = str(key_obj) if key_obj else ""
        
        # Handle album - it might be an object
        album_name = ""
        if hasattr(content, 'AlbumName'):
            album_name = content.AlbumName or ""
        elif hasattr(content, 'Album'):
            album_obj = content.Album
            if hasattr(album_obj, 'Name'):
                album_name = album_obj.Name or ""
            else:
                album_name = str(album_obj) if album_obj else ""
        
        # Handle genre - it might be an object
        genre_name = ""
        if hasattr(content, 'GenreName'):
            genre_name = content.GenreName or ""
        elif hasattr(content, 'Genre'):
            genre_obj = content.Genre
            if hasattr(genre_obj, 'Name'):
                genre_name = genre_obj.Name or ""
            else:
                genre_name = str(genre_obj) if genre_obj else ""
        
        return Track(
            id=str(content.ID),
            title=content.Title or "",
            artist=artist_name,
            album=album_name,
            genre=genre_name,
            bpm=bpm_float,
            key=key_name,
            rating=int(getattr(content, 'Rating', 0) or 0),
            play_count=int(getattr(content, 'DJPlayCount', 0) or 0),
            length=int(getattr(content, 'Length', 0) or 0),
            file_path=getattr(content, 'FolderPath', '') or "",
            date_added=getattr(content, 'DateCreated', '') or "",
            date_modified=getattr(content, 'StockDate', '') or "",
            bitrate=int(getattr(content, 'BitRate', 0) or 0),
            sample_rate=int(getattr(content, 'SampleRate', 0) or 0),
            comments=getattr(content, 'Commnt', '') or ""
        )
  • The @mcp.tool() decorator on the handler function registers 'get_track_details' as an MCP tool with FastMCP, using the function signature for input schema.
    @mcp.tool()
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions returning 'detailed track information including metadata, cue points, and play history,' which hints at read-only behavior, but doesn't clarify permissions, rate limits, error handling, or data freshness. This is a significant gap for a tool with no annotation coverage.

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

Conciseness4/5

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

The description is appropriately sized and front-loaded, starting with a clear purpose statement followed by structured sections for Args and Returns. Every sentence adds value, with no redundant information, though the formatting could be slightly more streamlined.

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?

Given the tool's low complexity (1 parameter) and the presence of an output schema (which handles return values), the description is reasonably complete. It covers the core purpose and parameter semantics adequately, though it lacks behavioral details like error cases or usage context, which would be beneficial for full completeness.

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?

The description adds meaningful context for the single parameter 'track_id' by explaining it as 'The unique track identifier,' which clarifies its purpose beyond the schema's minimal title 'Track Id.' With 0% schema description coverage, this compensates well, though it doesn't specify format or constraints like length or pattern.

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

Purpose4/5

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

The description clearly states the tool's purpose with a specific verb ('Get') and resource ('detailed information about a specific track'), making it easy to understand what it does. However, it doesn't explicitly differentiate from sibling tools like 'get_track_file_path' or 'search_tracks', which also retrieve track-related information but with different scopes or filters.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. With siblings like 'get_track_file_path' (for file paths) and 'search_tracks' (for broader searches), there's no indication that this tool is for detailed metadata of a single track identified by ID, leaving the agent to infer usage context.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/davehenke/rekordbox-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server