Create a Movie Resource
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 using
ResourceTemplate - Query Neo4j for comprehensive movie details
- Return structured data in a consistent format
- Include cast, genres, directors, and metadata
- Test the resource with MCP Inspector
If you get stuck, you can review the complete solution in the repository at solutions/8c-create-resource/index.ts.
Step 1: Understanding the Resource URI
Resources use URI patterns to identify what data to fetch.
For a movie resource, you will use the pattern: movie://{tmdbId}
Examples:
movie://603- The Matrixmovie://605- The Matrix Reloadedmovie://13- Forrest Gump
This allows clients to request specific movies by their TMDB ID.
Step 2: Create the Resource
Add this resource to your server/index.ts file, after your existing tools.
First, import ResourceTemplate from the SDK:
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";Then register the movie resource:
server.registerResource(
"movie",
new ResourceTemplate("movie://{tmdbId}", { list: undefined }),
{ description: "Get detailed information about a specific movie by TMDB ID", mimeType: "application/json" },
async (uri, { tmdbId }) => {
console.error(`Fetching movie details for TMDB ID: ${tmdbId}`);
try {
const { records } = await driver.executeQuery(
`
MATCH (m:Movie {tmdbId: $tmdbId})
RETURN m.title AS title,
m.released AS released,
m.tagline AS tagline,
m.imdbRating AS rating,
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 } ][0..5] AS cast,
[ (d)-[:DIRECTED]->(m) | d.name ] AS directors
`,
{ tmdbId: String(tmdbId) },
{ database }
);
if (records.length === 0) {
return {
contents: [{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify({ error: `Movie with TMDB ID ${tmdbId} not found` }),
}],
};
}
const movie = records[0].toObject();
return {
contents: [{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(movie, null, 2),
}],
};
} catch (error) {
console.error(`Failed to fetch movie: ${error}`);
return {
contents: [{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify({ error: `Failed to fetch movie: ${error}` }),
}],
};
}
}
);The handler receives two arguments:
uri- The parsed URL object for the requested resource{ tmdbId }- The extracted template parameters
The Cypher query fetches comprehensive movie details in a single query, including genres, cast (limited to the first 5), and directors using list comprehension patterns.
Step 3: Test with MCP Inspector
Start the MCP Inspector connected to your server:
npx @modelcontextprotocol/inspector npx tsx index.tsTest Popular Movies
In the Inspector UI:
- Click the Resources tab
- You should see the
movieresource template listed - Enter a TMDB ID in the template parameter field
Try these TMDB IDs:
- Copy - The Matrix (1999)
- Copy - Forrest Gump (1994)
- Copy - Fight Club (1999)
- Copy - Pulp Fiction (1994)
You should see structured output like:
{
"title": "The Matrix",
"released": "1999-03-31",
"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 loading into an LLM's context.