In the previous lesson, you learned about resources and how they differ from tools.
In this challenge, you will add a resource to your Movies GraphRAG Server that exposes detailed movie information by its tmdbId property,
Challenge Goals
To complete this challenge, you will:
- 
Add a movie resource with a dynamic URI pattern
 - 
Query Neo4j for comprehensive movie details
 - 
Return structured data in a consistent format
 - 
Include cast, genres, directors, and metadata
 - 
Test the resource with the interactive client
 
Solution Available
If you get stuck, you can review the complete solution in the repository at solutions/8c-create-resource/main.py.
To see the solution in action, run:
uv --directory solutions/8c-create-resource run main.pyStep 1: Understanding the Resource URI
Resources use URI patterns to identify what data to fetch.
For a movie resource, we’ll use the pattern: movie://{tmdb_id}
Examples:
- 
movie://603- The Matrix - 
movie://605- The Matrix Reloaded - 
movie://13- Forrest Gump 
This allows clients to request specific movies by their TMDB ID.
Step 2: Create the Resource Function
Add this resource to your server/main.py file, after your existing tools:
@mcp.resource("movie://{tmdb_id}")
async def get_movie(tmdb_id: str, ctx: Context) -> str:
    """
    Get detailed information about a specific movie by TMDB ID.
    Args:
        tmdb_id: The TMDB ID of the movie (e.g., "603" for The Matrix)
    Returns:
        Formatted string with movie details including title, plot, cast, and genres
    """
    await ctx.info(f"Fetching movie details for TMDB ID: {tmdb_id}")
    context = ctx.request_context.lifespan_context
    try:
        records, _, _ = await context.driver.execute_query(
            """
            MATCH (m:Movie {tmdbId: $tmdb_id})
            RETURN m.title AS title,
               m.released AS released,
               m.tagline AS tagline,
               m.runtime AS runtime,
               m.plot AS plot,
               [ (m)-[:IN_GENRE]->(g:Genre) | g.name ] AS genres,
               [ (p)-[r:ACTED_IN]->(m) | {name: p.name, role: r.role} ] AS actors,
               [ (d)-[:DIRECTED]->(m) | d.name ] AS directors
            """,
            tmdb_id=tmdb_id,
            database_=context.database
        )
        if not records:
            await ctx.warning(f"Movie with TMDB ID {tmdb_id} not found")
            return f"Movie with TMDB ID {tmdb_id} not found in database"
        movie = records[0].data()
        # Format the output
        output = []
        output.append(f"# {movie['title']} ({movie['released']})")
        output.append("")
        if movie['tagline']:
            output.append(f"_{movie['tagline']}_")
            output.append("")
        output.append(f"**Runtime:** {movie['runtime']} minutes")
        output.append(f"**Genres:** {', '.join(movie['genres'])}")
        if movie['directors']:
            output.append(f"**Director(s):** {', '.join(movie['directors'])}")
        output.append("")
        output.append("## Plot")
        output.append(movie['plot'])
        if movie['actors']:
            output.append("")
            output.append("## Cast")
            for actor in movie['actors']:
                if actor['role']:
                    output.append(f"- {actor['name']} as {actor['role']}")
                else:
                    output.append(f"- {actor['name']}")
        result = "\n".join(output)
        await ctx.info(f"Successfully fetched details for '{movie['title']}'")
        return result
    except Exception as e:
        await ctx.error(f"Failed to fetch movie: {str(e)}")
        raiseKey points in this code:
- 
URI pattern:
movie://{tmdb_id}- Thetmdb_idparameter is extracted from the URI - 
Comprehensive query: Fetches movie details, genres, cast, and directors in one query
 - 
Structured data: Returns a consistent JSON-compatible dictionary
 - 
Error handling: Handles missing movies gracefully
 
Step 3: Test with the Interactive Client
Start your server in one terminal:
uv --directory server run main.pyIn a separate terminal, run the interactive client from the project root:
uv --directory client run main.pyTest Popular Movies
The client will show available resource templates. Select the movie resource template and enter a TMDB ID when prompted.
Try these TMDB IDs:
- 
603- The Matrix (1999) - 
13- Forrest Gump (1994) - 
550- Fight Club (1999) - 
680- Pulp Fiction (1994) 
The client will prompt you:
tmdb_id (required)
  Type: string
  Enter value: 603You should see structured output like:
{
    "title": "The Matrix",
    "released": 1999,
    "tagline": "Welcome to the Real World",
    "rating": 8.7,
    "runtime": 136,
    "genres": ["Action", "Science Fiction"],
    "directors": ["Lilly Wachowski", "Lana Wachowski"],
    "plot": "Set in the 22nd century, The Matrix tells the story of a computer hacker...",
    "cast": [
        {"name": "Keanu Reeves", "role": "Neo"},
        {"name": "Laurence Fishburne", "role": "Morpheus"},
        {"name": "Carrie-Anne Moss", "role": "Trinity"},
        {"name": "Hugo Weaving", "role": "Agent Smith"},
        {"name": "Gloria Foster", "role": "Oracle"}
    ]
}This structured format makes it easy to use the data programmatically and is perfect for sampling in advanced features.
Summary
In this challenge, you successfully created a movie resource:
- 
Dynamic URI pattern -
movie://{tmdb_id}for flexible resource access - 
Comprehensive query - Fetched movie details, cast, genres, and directors
 - 
Structured data - Returned consistent, JSON-compatible output
 - 
Error handling - Gracefully handled missing movies
 - 
Resource design - Understood when to use resources vs tools
 
Your server now exposes data in two ways: tools for searches and resources for specific entities.
In the next lesson, you’ll learn about pagination for handling large datasets.