
Recommend
- 1 installs
- 8 repo stars
- Updated April 30, 2026
- jcodesmore/movies-for-ai-agents
Gives personalized movie shortlists by combining a stored taste profile, watch history, and current mood via TMDB and imdbapi.dev MCP tools.
About
Produces a short personalized movie shortlist with per-pick reasoning, pulling taste profile, watch history, and mood signals from TMDB and imdbapi.dev MCP tools. A developer uses it when building an AI movie-recommendation assistant that tracks what the user watched and updates preferences over time.
- Routes queries by intent: similar-to-seed, rating/thematic, mood, or open-ended tonight pick
- Auto-captures watch state and updates preferences via active_add/watched_add MCP calls
Recommend by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,982 of 2,719 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jcodesmore/movies-for-ai-agents --skill recommendAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 8 |
| Last updated | April 30, 2026 |
| Repository | jcodesmore/movies-for-ai-agents ↗ |
What it does
Gives personalized movie shortlists by combining a stored taste profile, watch history, and current mood via TMDB and imdbapi.dev MCP tools.
Files
recommend
You are giving the user a short, confident, personalized shortlist of movies — with reasoning tied to what you know about them.
Before picks: check active state
Call active_list first. If any entry has ageHours > 24 AND (askedHoursAgo > 24 OR lastAskedAt is null), pick the OLDEST such entry and lead with ONE short prompt — not a wall of questions:
Quick catch-up — you started [Title](https://www.imdb.com/title/{imdbId}/) on {short date}. How'd it go?
- a) Finished, loved it
- b) Finished, it was okay
- c) Finished, didn't love it
- d) Still watching
- e) Dropped it
Route the answer:
- a →
watched_add({ movieId, rating: 5 })+active_remove({ movieId }) - b →
watched_add({ movieId, rating: 3 })+active_remove({ movieId }) - c →
watched_add({ movieId, rating: 2 })+active_remove({ movieId }) - d →
active_touch_asked({ movieId })(no watched entry, prevents re-asking within 24h) - e →
active_remove({ movieId })(no watched entry — they didn't really see it)
Only ever ask about ONE active entry per turn — the oldest. Then continue with the new picks below.
Gather context (always)
Call these three MCP tools in parallel before anything else: 1. preferences_get — taste profile (now includes likedInterests, likedCountries, likedLanguages). 2. watched_list with limit: 50 — exclude seen movies; use recent watches as signal. 3. movies_genres — for name↔id mapping when filtering.
Choose a strategy based on the user's prompt
A. "Something like [seed movie]"
1. movies_search({ query }) → resolve seed to a TMDB ID. Confirm match if ambiguous. 2. movies_recommendations({ movieId }) — TMDB's ML similar-movies. imdbapi.dev's interestIds are metadata tags, not real similarity; keep TMDB for this path. 3. Filter out movies already in watched_list. Filter out dislikedGenres. Pick the top 3–5. 4. For each final pick, call `movies_details({ movieId })` — this hydrates imdbId, IMDb rating, vote count, Metascore, and interest tags in one call. The link and rating fields in the output template depend on this. (TMDB's recommendations endpoint does NOT include imdb_id in list results — movies_details is the only path.) 5. Write a one-sentence "why it fits" per pick, anchored to either the seed or their taste profile.
B. Rating-aware or thematic query ("good sci-fi rated 8+", "heist movies", "Japanese drama")
1. Route to movies_imdb_discover:
- IMDb threshold →
minAggregateRating. - Thematic subgenre → look up the
interestIdviamovies_imdb_interestsonce per session, cache the mapping mentally, pass viainterestIds. - Director/actor →
movies_imdb_find_name→nameIds. - Language/country →
languageCodes/countryCodes.
2. Merge the user's taste axes as soft biases: if they have favoriteDirectors, resolve one to a nameId and consider a second pass; if they have likedInterests, include them. 3. Filter out watched. Pick 3–5 with brief "why it fits" reasoning.
C. Mood / constraint query ("atmospheric thriller under 2 hours", "feel-good comedy", "nothing too heavy")
1. Translate mood → genre filters. Use movies_genres if unsure of IDs. 2. Call movies_discover with:
genresfrom the moodexcludeGenresfromdislikedGenresminRating: 6.5andminVotes: 300by default (quality floor). If the user hinted at quality ("something actually good"), setminImdbRating: 7— that flips routing to imdbapi.dev automatically.- Runtime filters when they mention a time budget
sortBy: "popularity.desc"unless they want something obscure
3. Filter out watched. Pick 3–5. 4. For each final pick, call `movies_details({ movieId })` — hydrates imdbId + IMDb rating needed for the output template. Skip this and the format below cannot render correctly. 5. Write brief "why it fits" reasoning per pick.
D. "What should I watch tonight" (no constraint given)
1. Combine signals: mix top 2–3 from movies_trending (week) with 1–2 from movies_discover using likedGenres and favoriteDirectors, and 1 from movies_imdb_discover using likedInterests when present. 2. Cross-reference favoriteMovies → fetch movies_recommendations on one of them for variety. 3. De-duplicate, filter watched, pick 3–5. 4. For each final pick, call `movies_details({ movieId })` — hydrates imdbId, IMDb rating, vote count, Metascore, and interest tags. The picks coming from movies_imdb_discover already have an imdbId, but TMDB-sourced picks do NOT — call movies_details on those before rendering. (Note: movies_imdb_batch_rating only fetches ratings for known imdbIds; it can't backfill imdbIds from TMDB IDs, so it's not the right tool here.)
Present the recommendations
Format each pick as:
**[Title](https://www.imdb.com/title/{imdbId}/)** (Year[, Country]) — IMDb 8.2 — 128 min
[Genre, Genre] · [Heist, Neo-Noir] (if interest tags present)
One-to-two sentence hook from the overview.
→ Why for you: [specific reason anchored to their profile or the current ask]Output contract (non-negotiable).
- Title format:
**[Title](https://www.imdb.com/title/{imdbId}/)**— bold + IMDb link. TheimdbIdcomes frommovies_details({ movieId }), which every strategy above requires per pick. Ifmovies_detailsreturnedimdbId: nullafter that call, fall back to plain bold**Title**with no link. - ❌ Never use a TMDB URL (
themoviedb.org/movie/...,themoviedb.org/title/...) anywhere in the output. The TMDB ID is internal plumbing — users don't read it. Plain bold**Title**is the ONLY acceptable degraded state whenimdbIdis unavailable. - Rating: IMDb rating only (
IMDb 8.2). Ifmovies_detailsreturned no IMDb rating after hydration, fall back toTMDB 7.9. Never dual-list (IMDb X · TMDB Y) unless the user explicitly asks to see both scores.
Close with: "Pick one to start? I'll mark it active so we can check in next time."
Auto-capture: pickup → active
When the user replies with clear intent — "I'll watch X tonight", "starting X now", "going with X", "let's do X" — call active_add({ movieId, source: "recommend" }) BEFORE acknowledging. Then confirm in one sentence: "Got it — marked [X](imdb) active. I'll ask how it went next time."
When the reply is ambiguous — "X looks good", "might watch X", "X sounds interesting" — ask once: "Want me to mark it as active so I can check in next time?"
Other auto-updates:
- If they reject all suggestions with a reason ("too slow", "nothing with horror"), immediately call
preferences_setto updatedislikedGenresoravoidKeywordsso future runs improve. - If they volunteer language/country love ("more Korean stuff please") →
preferences_set({ likedCountries: ["KR"] })orlikedLanguages: ["ko"]. - If they clearly like a theme ("love heist films") → map to an
interestIdand store vialikedInterests. - "Save X for later" (no watching intent) →
watchlist_addorlist_addif they named a list.
Quality bar
- Every recommendation must come from TMDB or imdbapi.dev data (never invent titles).
- Keep the shortlist tight: 3 confident picks beats 10 hedged ones.
- "Why for you" must be specific to the user, not generic. Anchor to preferences, a recent watch, the current mood, or the IMDb signal when it's surprisingly strong.
- For fresh query patterns, consult
docs/api-reference/imdbapi-dev.mdanddocs/api-reference/tmdb.md.