Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
- Plex episodes with year-based seasons are mapped to the correct TMDb season
numbers via a helper that matches season names or air-date years to ensure
accurate episode lookups.
- Plex metadata is fetched in batches using `fetchItems` to reduce repeated
network calls when loading library items.

## User Queries
The project should handle natural-language searches and recommendations such as:
Expand Down
19 changes: 9 additions & 10 deletions mcp_plex/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,25 +316,24 @@ async def _augment_episode(
results: List[AggregatedItem] = []
async with httpx.AsyncClient(timeout=30) as client:
movie_section = server.library.section("Movies")
movie_tasks = [
_augment_movie(client, movie.fetchItem(movie.ratingKey))
for movie in movie_section.all()
]
movie_keys = [int(m.ratingKey) for m in movie_section.all()]
movies = server.fetchItems(movie_keys) if movie_keys else []
movie_tasks = [_augment_movie(client, movie) for movie in movies]
if movie_tasks:
results.extend(await _gather_in_batches(movie_tasks, batch_size))

show_section = server.library.section("TV Shows")
for show in show_section.all():
full_show = show.fetchItem(show.ratingKey)
show_keys = [int(s.ratingKey) for s in show_section.all()]
full_shows = server.fetchItems(show_keys) if show_keys else []
for full_show in full_shows:
show_ids = _extract_external_ids(full_show)
show_tmdb: Optional[TMDBShow] = None
if show_ids.tmdb:
show_tmdb = await _fetch_tmdb_show(client, show_ids.tmdb, tmdb_api_key)
episode_keys = [int(e.ratingKey) for e in full_show.episodes()]
Comment on lines +319 to +333
Copy link

Copilot AI Sep 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fetchItems method expects string keys based on the test implementation, but this code converts them to integers. This type mismatch could cause runtime errors when calling the Plex API.

Copilot uses AI. Check for mistakes.
episodes = server.fetchItems(episode_keys) if episode_keys else []
episode_tasks = [
_augment_episode(
client, episode.fetchItem(episode.ratingKey), show_tmdb
)
for episode in full_show.episodes()
_augment_episode(client, episode, show_tmdb) for episode in episodes
]
if episode_tasks:
results.extend(await _gather_in_batches(episode_tasks, batch_size))
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "mcp-plex"
version = "0.26.18"
version = "0.26.19"

description = "Plex-Oriented Model Context Protocol Server"
requires-python = ">=3.11,<3.13"
Expand Down
80 changes: 37 additions & 43 deletions tests/test_load_from_plex.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,61 +8,55 @@


def test_load_from_plex(monkeypatch):
def add_fetch(obj):
obj.fetchItem = lambda key: obj
return obj

movie = add_fetch(
types.SimpleNamespace(
ratingKey="101",
guid="plex://movie/101",
type="movie",
title="Inception",
guids=[
types.SimpleNamespace(id="imdb://tt1375666"),
types.SimpleNamespace(id="tmdb://27205"),
],
)
movie = types.SimpleNamespace(
ratingKey="101",
guid="plex://movie/101",
type="movie",
title="Inception",
guids=[
types.SimpleNamespace(id="imdb://tt1375666"),
types.SimpleNamespace(id="tmdb://27205"),
],
)

ep1 = add_fetch(
types.SimpleNamespace(
ratingKey="102",
guid="plex://episode/102",
type="episode",
title="Pilot",
parentIndex=1,
index=1,
guids=[
types.SimpleNamespace(id="imdb://tt0959621"),
types.SimpleNamespace(id="tmdb://62085"),
],
)
ep1 = types.SimpleNamespace(
ratingKey="102",
guid="plex://episode/102",
type="episode",
title="Pilot",
parentIndex=1,
index=1,
guids=[
types.SimpleNamespace(id="imdb://tt0959621"),
types.SimpleNamespace(id="tmdb://62085"),
],
)
ep2 = add_fetch(
types.SimpleNamespace(
ratingKey="103",
guid="plex://episode/103",
type="episode",
title="Cat's in the Bag...",
guids=[types.SimpleNamespace(id="imdb://tt0959622")],
)
ep2 = types.SimpleNamespace(
ratingKey="103",
guid="plex://episode/103",
type="episode",
title="Cat's in the Bag...",
guids=[types.SimpleNamespace(id="imdb://tt0959622")],
)

show = add_fetch(
types.SimpleNamespace(
ratingKey="201",
guids=[types.SimpleNamespace(id="tmdb://1396")],
episodes=lambda: [ep1, ep2],
)
show = types.SimpleNamespace(
ratingKey="201",
guids=[types.SimpleNamespace(id="tmdb://1396")],
episodes=lambda: [ep1, ep2],
)

movie_section = types.SimpleNamespace(all=lambda: [movie])
show_section = types.SimpleNamespace(all=lambda: [show])
library = types.SimpleNamespace(
section=lambda name: movie_section if name == "Movies" else show_section
)
server = types.SimpleNamespace(library=library)

items = {101: movie, 102: ep1, 103: ep2, 201: show}

def fetchItems(keys):
return [items[int(k)] for k in keys]

server = types.SimpleNamespace(library=library, fetchItems=fetchItems)

async def handler(request):
url = str(request.url)
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.