Skip to main content
Glama

FreqBlog Music Metadata

Get Recommendations

get_recommendations
Read-only

Recommended tracks for one or more seed tracks — the drop-in for Spotify's removed GET /v1/recommendations. Blends up to 5 catalog seed tracks into a single point in audio-feature space and returns the nearest catalogue tracks, RE-RANKED by genre affinity (so a feature-close cross-genre track doesn't outrank same-genre picks).

Returns `seeds` (each {id, found}), `count`, and `tracks` (each {track, score,
genre_relation}; each track carries its `genre`). `genre_relation` is "same", "compatible"
(different but mixable family), "cross" (unrelated), or "unknown" (either side has no mapped
genre), measured against the PRIMARY seed — the first of your seed_tracks we could actually
use, so reordering seed_tracks changes it and a skipped seed never becomes the reference.
With a SINGLE seed the field is the ranking's own verdict, so it explains the order (same as
suggest_next_track). With SEVERAL seeds the ranking considers ALL of them while the label stays
relative to your primary seed, so a "cross" label on a multi-seed call does NOT mean the track
was pushed down — it may share a family with another of your seeds. `score` is the raw
audio-feature cosine similarity in [0,1]; genre affinity influences the ORDER, not the score,
so the list is NOT strictly score-descending.
Use cross_genre=strict to return same-genre-family tracks ONLY (off-genre dropped
server-side), or allow to disable the genre ranking. seed_tracks are catalog itunes_track_ids
from search_catalog or the itunes_track_id field of a get_audio_features result.

NO id? Pass `track` (+ optional `artist`) instead and we resolve the name to the best catalog
match and seed on it — the resolved track is echoed back as `seed_query`; seed_tracks wins if
both are given.

TUNING: `min`/`max` are HARD filters and `target` is a preference (nearer ranks higher,
nothing removed), over acousticness, danceability, duration_ms, energy,
loudness, tempo and valence. NOTE: `popularity` (2026-08-27), `liveness`, `speechiness`
(2026-09-26) and `instrumentalness` (2026-09-27) are RETIRED as tunables and return a 400 —
popularity recorded how a track entered our catalogue, not audience size; the other three
are returned as null for catalogue tracks. Values are FreqBlog's own (not Spotify's):
energy/valence on our raw scale, danceability/acousticness on AcousticBrainz's scale —
derive thresholds from our values rather than reusing Spotify-tuned ones. e.g. min={"tempo": 100},
max={"tempo": 130}, target={"energy": 0.8} for energetic 100-130 BPM tracks. When you tune,
the response adds a `filters` block saying what applied, how many tracks each bound removed
(`dropped_by`) and whether the bounds ran out of catalogue before `limit` (`limit_reached`)
— if the list comes back short, read that BEFORE assuming the catalogue is thin.
Costs 2 quota units.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
maxNoHARD upper bounds, e.g. {'tempo': 130}. Same attributes as `min`. Combine the two for a range.
minNoHARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, loudness, tempo, valence.
limitNoNumber of recommendations to return (default 20).
trackNoSeed by track NAME instead of an id — resolved to the best catalog match (echoed back as seed_query). Pair with artist to disambiguate. Ignored when seed_tracks is given.
artistNoArtist name narrowing the track seed (case-insensitive).
targetNoPREFERRED values, e.g. {'energy': 0.8}. Tracks nearer the value rank higher; unlike min/max nothing is removed. Same attributes as `min`.
cross_genreNoGenre handling (mirrors suggest_next_track): 'auto' (default) re-ranks by genre affinity so a feature-close cross-genre track can't outrank same-genre picks; 'strict' = same genre-family only (off-genre dropped server-side); 'allow' = genre-blind (pure audio-feature cosine).auto
seed_tracksNo1-5 catalog itunes_track_ids to base recommendations on, e.g. ['apple_ad1829eeccb70f9a'] (blended into a feature-space centroid). Omit and use track(+artist) to seed by name instead.
exclude_seed_artistsNoDrop tracks by any of the seed artists (default false).

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / min / description
      Previous value: -"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, loudness, tempo, valence."New value: +"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, loudness, tempo, valence."
  2. Changed1 schema field changed
    • changedInput schema / properties / min / description
      Previous value: -"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, loudness, speechiness, tempo, valence."New value: +"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, loudness, tempo, valence."
  3. Changed1 schema field changed
    • changedInput schema / properties / min / description
      Previous value: -"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, liveness, loudness, speechiness, tempo, valence."New value: +"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, loudness, speechiness, tempo, valence."
  4. Changed1 schema field changed
    • changedInput schema / properties / min / description
      Previous value: -"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, liveness, loudness, popularity, speechiness, tempo, valence."New value: +"HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, liveness, loudness, speechiness, tempo, valence."
  5. Changed3 schema fields changed
    • addedInput schema / properties / max
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": {
      +        "type": "number"
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "HARD upper bounds, e.g. {'tempo': 130}. Same attributes as `min`. Combine the two for a range.",
      +  "title": "Max"
      +}
    • addedInput schema / properties / min
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": {
      +        "type": "number"
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "HARD lower bounds, e.g. {'tempo': 100, 'energy': 0.5}. Tracks below the bound — and tracks we hold no analysed value for — are dropped. Attributes: acousticness, danceability, duration_ms, energy, instrumentalness, liveness, loudness, popularity, speechiness, tempo, valence.",
      +  "title": "Min"
      +}
    • addedInput schema / properties / target
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": {
      +        "type": "number"
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "PREFERRED values, e.g. {'energy': 0.8}. Tracks nearer the value rank higher; unlike min/max nothing is removed. Same attributes as `min`.",
      +  "title": "Target"
      +}
  6. Changed10 schema fields changed
    • addedInput schema / properties / artist
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 200,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Artist name narrowing the track seed (case-insensitive).",
      +  "title": "Artist"
      +}
    • addedInput schema / properties / seed_tracks / anyOf
      Added value: +[
      +  {
      +    "items": {
      +      "type": "string"
      +    },
      +    "maxItems": 5,
      +    "type": "array"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedInput schema / properties / seed_tracks / default
      Added value: +null
    • changedInput schema / properties / seed_tracks / description
      Previous value: -"1-5 catalog itunes_track_ids to base recommendations on, e.g. ['apple_ad1829eeccb70f9a'] (blended into a feature-space centroid)."New value: +"1-5 catalog itunes_track_ids to base recommendations on, e.g. ['apple_ad1829eeccb70f9a'] (blended into a feature-space centroid). Omit and use track(+artist) to seed by name instead."
    • removedInput schema / properties / seed_tracks / items
      Removed value: -{
      -  "type": "string"
      -}
    • removedInput schema / properties / seed_tracks / maxItems
      Removed value: -5
    • removedInput schema / properties / seed_tracks / minItems
      Removed value: -1
    • removedInput schema / properties / seed_tracks / type
      Removed value: -"array"
    • addedInput schema / properties / track
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 200,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Seed by track NAME instead of an id — resolved to the best catalog match (echoed back as seed_query). Pair with artist to disambiguate. Ignored when seed_tracks is given.",
      +  "title": "Track"
      +}
    • removedInput schema / required
      Removed value: -[
      -  "seed_tracks"
      -]
  7. Changed1 schema field changed
    • addedInput schema / properties / cross_genre
      Added value: +{
      +  "default": "auto",
      +  "description": "Genre handling (mirrors suggest_next_track): 'auto' (default) re-ranks by genre affinity so a feature-close cross-genre track can't outrank same-genre picks; 'strict' = same genre-family only (off-genre dropped server-side); 'allow' = genre-blind (pure audio-feature cosine).",
      +  "title": "Cross Genre",
      +  "type": "string"
      +}
  8. Added

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only supply readOnlyHint and openWorldHint; the description carries the rest and does so well — 2 quota units cost, retired tunables returning 400, server-side dropping in strict mode, null values for liveness/speechiness/instrumentalness, and the filters/dropped_by/limit_reached diagnostic. It also warns that the list is NOT strictly score-descending, which is exactly the kind of non-obvious behavior an agent would otherwise get wrong.

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?

Purpose is front-loaded and each paragraph has a distinct job (returns, seeding, tuning). It is long for a tool description and repeats some schema-level detail, notably re-explaining the three cross_genre modes that the schema already documents, but almost no sentence is pure filler given the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter, zero-required, tuning-heavy tool with only two terse annotations, the description covers seeding, ranking semantics, hard vs soft filters, deprecated parameters, quota cost, and short-result diagnostics. An output schema exists, yet the return explanation is still useful for interpreting genre_relation relative to the primary seed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds material meaning beyond it: the retired attributes list (popularity/liveness/speechiness/instrumentalness) that the schema still exposes as valid keys, the seed_tracks-over-track precedence, the primary-seed definition for genre_relation, and the FreqBlog-vs-Spotify value-scale caveat for tuning thresholds.

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

Purpose5/5

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

Opens with a specific verb+resource ('Recommended tracks for one or more seed tracks') and immediately positions itself as the drop-in replacement for Spotify's removed endpoint, which tells an agent exactly what it produces. It also names the sibling it relates to (suggest_next_track for single-seed semantics) and the tools that supply its inputs (search_catalog, get_audio_features), so it is distinguishable without opening any schema.

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

Usage Guidelines5/5

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

Explicit routing rules: use seed_tracks (catalog itunes_track_ids) or fall back to track(+artist) when no id exists, with seed_tracks winning if both are given. It gives when-to-use for each cross_genre mode (strict vs allow vs auto), explains when to read the filters block, and contrasts min/max (hard filters) with target (preference).

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources