Building Dynamic MCP Resources with Templates (Python)
Let’s extend our MCP server’s capabilities using resource templates – one of the most powerful features of the Model Context Protocol (MCP) ecosystem.
What Are Resource Templates?
Resource templates allow you to define dynamic resources using URI patterns. Unlike static resources with fixed URIs, templates let you create resources whose URIs and content can be generated based on parameters.
Think of them like URL patterns in a web frameworkโwhere a resource is determined by a tag or IDโletting you match and handle entire families of resources using a single definition.

MCP Server Resource Templates
Why Use Resource Templates?
Resource templates become essential when you need to:
- Handle dynamic data (e.g., user profiles, product info)
- Generate content on demand (e.g., reports, analytics)
- Create parameter-based resources (e.g., search filters)
Real-World Examples
Dynamic Data
users://{user_id} โ User profiles
products://{sku} โ Product information
Example Interaction:
๐ฌ User: “Can you tell me about user 34567?”
๐ค AI Assistant: “Looking up user 34567… They joined in 2022 and have made 50 purchases.”
On-Demand Content
reports://{year}/{month} โ Monthly reports
analytics://{dateRange} โ Custom analytics
Example Interaction:
๐ฌ User: “Show me the report for May 2024”
๐ค AI Assistant: “Accessing May 2024 report… Revenue was up 15% compared to February.”
Parameter-Based Resources
search://{query} โ Search results
filter://{type}/{value} โ Filtered data
Example Interaction:
๐ฌ User: “Find all transactions above ยฃ1000”
๐ค AI Assistant: “Using the filter resource… Found 23 transactions matching your criteria.”
Not entirely cool! – The gubberment will be doing this to us soon.
Organizing Our Code
As our MCP server grows, it’s important to maintain a clean code structure. We’ll separate our handlers into a dedicated file (handlers.py
), keeping our main file (server.py
) minimal and focused.
Step 1: Create handlers.py
# handlers.py
# DON'T initialize a new server here
# Instead, import the server from server.py
# Define your resource handlers without initializing a new server
def register_handlers(mcp):
# List available resources
@mcp.resource("list://resources")
def list_resources() -> dict:
"""Return a list of all available resources in this server."""
return {
"resources": [
{
"uri": "hello://world",
"name": "Hello World Message",
"description": "A simple greeting message",
"mime_type": "text/plain",
},
{
"uri": "greetings://{nabankstersme}",
"name": "Personal Greeting",
"description": "A personalized greeting using a name parameter",
"mime_type": "text/plain",
}
]
}
# Provide static resource content
@mcp.resource("hello://world")
def get_hello_message() -> str:
"""Return a simple hello world message."""
return "Hello, World! This is my first MCP resource."
# Define a resource template with a parameter
@mcp.resource("greetings://{name}")
def get_greeting(name: str) -> str:
"""Generate a personalized greeting for the given name."""
return f"Hello, {name}! Welcome to MCP."
Step 2: Update server.py
Now, let’s update our main server file to import and register the handlers:
# server.py
from mcp.server.fastmcp import FastMCP
from handlers import register_handlers
# Initialize the server
mcp = FastMCP("MCP Demo Server")
# Register all handlers
register_handlers(mcp)
# Start the MCP server
if __name__ == "__main__":
mcp.run()
Understanding the Code
Handler Organization
- We’ve moved all resource handlers to
handlers.py
to keep our codebase modular as it grows - Importing
handlers
inserver.py
automatically registers all resources with the MCP server - This pattern makes maintenance easier as you add more resources and templates
Template Definition
greetings://{name}
defines a template with a variable part ({name}
)- It defines the structure that clients would use to make requests
- The curly braces indicate a parameter that will be extracted from the URI
- The parameter matches the function argument in our handler function
Parameter Extraction
- When a request like
greetings://Alice
arrives from the client (Claude Desktop or similar) - , MCP automatically:
- Matches it against the template pattern
- Extracts “Alice” as the
name
parameter - Calls
get_greeting("Alice")
with the extracted parameter - Returns the personalized greeting to the LLM
Testing with MCP Inspector
The MCP Inspector is a powerful tool for testing your MCP server during development:
mcp dev server.py # if you have issues with this, it will be to do with your PATH
Test Static Resource
- Click the “Resources” tab
- Select “Hello World Message”
- You should see:
{
"contents": [
{
"uri": "hello://world",
"text": "Hello, World! This is my first MCP resource."
}
]
}
Test Resource Template
- Click the “Resource Templates” tab
- Select “Personal Greeting”
- Type “Alice” in the parameter field
- Expected result:
{
"contents": [
{
"uri": "greetings://Alice",
"text": "Hello, Alice! Welcome to MCP."
}
]
}


More Advanced Resource Templates
Let’s enhance our server with a more complex template example that handles multiple parameters:
# Add this to handlers.py
@mcp.resource("products://{category}/{product_id}")
def get_product_info(category: str, product_id: str) -> dict:
"""Retrieve detailed information about a specific product.
Args:
category: The product category (e.g., "electronics", "books")
product_id: The unique identifier for the product
Returns:
A dictionary containing product details
"""
# In a real application, you would query a database here
sample_products = {
"electronics": {
"e123": {"name": "Smartphone XYZ", "price": 999.99, "in_stock": True},
"e456": {"name": "Laptop ABC", "price": 1299.99, "in_stock": False}
},
"books": {
"b789": {"name": "Python Programming", "price": 49.99, "in_stock": True},
"b101": {"name": "AI Fundamentals", "price": 59.99, "in_stock": True}
}
}
if category in sample_products and product_id in sample_products[category]:
return {
"product": sample_products[category][product_id],
"category": category,
"id": product_id
}
else:
return {"error": f"Product {product_id} in category {category} not found"}
In your config.json – (for Claude Desktop users ) – Add lines 25 – 34 below:

This update adds the product resource to the list of available resources with:
- The correct URI template pattern:
products://{category}/{product_id}
- A descriptive name: “Product Information”
- A clear description explaining its purpose
- The appropriate MIME type:
application/json
since it returns a dictionary/JSON - Example URIs showing how to use the resource with real parameter values
Adding example URIs is particularly helpful for Claude to understand how to use the resource template with appropriate parameters. The complete resource listing now correctly represents all three resources available in your MCP server.


Claude Desktop Integration
Once your server is ready, you can install it in Claude Desktop for immediate interaction:
mcp install server.py
Try asking Claude these questions:
๐ฌ User: “Can you get a greeting for Alice?”
๐ค Claude: “I’ll check the personalized greeting… It says: ‘Hello, Alice! Welcome to MCP.'”
๐ฌ User: “What information do you have on the Laptop ABC product?”
๐ค Claude: “Let me check the product details… The Laptop ABC costs $1,299.99 but is currently out of stock.”
Conclusion
Resource templates are a fundamental feature of MCP that enable your AI assistants to access dynamic, parameter-based information. By using them effectively, you can create flexible, powerful integrations that respond intelligently to a wide range of user requests.
In the next part of our series, we’ll explore how to combine resources with tools to create interactive experiences that go beyond just providing information.
Additional Resources
- MCP Official Documentation
- FastMCP API ReferenceBuilding Dynamic MCP Resources with Templates
- Resource Templates Best Practices

model context protocol
How Claude Desktop Makes Use of MCP Resources?
When you integrate your MCP server with Claude Desktop, it creates a powerful connection between your custom data/functionality and Claude’s capabilities. Here’s how the whole process works:
The Integration Process
- Installation: When you run
mcp install server.py
, Claude Desktop registers your MCP server and makes its resources and tools available to Claude. - Resource Discovery: Claude Desktop automatically discovers all the resources and templates exposed by your server.
- Contextual Usage: During conversations, Claude can access these resources when relevant to the conversation.
How Claude Uses Your Resources
Direct Queries
When a user explicitly asks about something that matches your resource patterns, Claude will:
- Recognize the need for external information
- Query the appropriate resource on your MCP server
- Incorporate the retrieved information in its response
For example:
User: "Can you get a greeting for Alice?"
Claude: [Internally accesses greetings://Alice]
Claude: "I'll check the personalized greeting... It says: 'Hello, Alice! Welcome to MCP.'"
Contextual Awareness
Claude will also proactively use your resources when they’re relevant to the conversation, even if not directly requested:
User: "I need information about user profiles."
Claude: [Recognizes this relates to user data]
Claude: "I can help with that. I can access user profile information through the MCP server. Would you like me to look up a specific user?"
Resource Template Parameters
For resource templates with parameters, Claude understands how to:
- Extract the necessary parameters from the conversation
- Format them correctly for the template
- Request the specific resource with the filled-in parameters
User: "What information do we have on electronics product e123?"
Claude: [Recognizes pattern matching products://{category}/{product_id}]
Claude: "Let me check that for you... The Smartphone XYZ costs $999.99 and is currently in stock."
Behind the Scenes
Here’s what’s happening technically:
- Claude Desktop maintains a registry of installed MCP servers
- During conversations, Claude analyzes which resources might be relevant
- When needed, Claude Desktop sends requests to your MCP server
- Your server processes these requests and returns the appropriate data
- Claude incorporates this data into its reasoning and responses
Testing the Integration
After installing your server with mcp install server.py
, you can verify the integration by:
- Asking about available resources:
User: "What resources do you have access to from my MCP server?"
- Requesting specific resources:
User: "Can you show me the greeting for David?"
- Using resources in context:
User: "I'm looking for information about the Python Programming book."
Example Conversation
Here’s a sample conversation showing how Claude uses your MCP resources:
User: "I just set up an MCP server with resource templates. How can you use it?"
Claude: "Great! I can access the resources you've created on your MCP server. For example, I can retrieve personalized greetings or product information. Would you like me to demonstrate by accessing a specific resource?"
User: "Yes, can you get information about the laptop product?"
Claude: "Let me check the product details for that laptop. Based on your MCP server, the Laptop ABC costs $1,299.99 but is currently out of stock. This information comes from the products://electronics/e456 resource on your server."
User: "Can you also show me a greeting for my friend Sarah?"
Claude: "Of course! I'll access the personalized greeting for Sarah... The greeting says: 'Hello, Sarah! Welcome to MCP.'"
Practical Tips
- Name resources clearly: Use intuitive URI patterns so Claude* can easily understand when to use them. (or other LLM provider)*
- Add descriptive documentation: Well-documented resources help Claude understand their purpose
- Test thoroughly: Use the MCP Inspector to verify your resources work before integration
- Start simple: Begin with a few well-defined resources before expanding
With this understanding, you can create MCP resources that Claude can seamlessly integrate into conversations, enhancing its capabilities with your custom data and logic.
Claude Desktop maintains a registry of installed MCP servers in a json file:

How does Claude Decide whether to use an MCP Resource?
Claude’s decision to use an MCP resource is based on a sophisticated combination of factors. Understanding this process can help you design more effective MCP servers that Claude will use appropriately.
Key Factors in Claude’s Decision-Making
1. Relevance to User Query
Claude analyzes the user’s message to determine if it explicitly or implicitly relates to information that might be provided by one of your resources.
Examples:
- Explicit: “Can you get a greeting for Alice?” โ clearly maps to
greetings://Alice
- Implicit: “Tell me about Alice” โ might suggest using the greeting resource contextually
2. Pattern Matching
Claude looks for patterns in the conversation that match your resource URI templates.
Examples:
- User mentions a product ID โ might trigger
products://{category}/{id}
- User asks about a specific date โ might trigger
reports://{year}/{month}
3. Contextual History
Claude considers the full conversation history to determine if a resource is relevant.
Examples:
- If you’ve been discussing products, Claude is more likely to use product resources
- If previous messages established a user’s name is “Bob,” Claude might proactively use
greetings://Bob
4. Resource Metadata
Claude uses resource descriptions and names to understand their purpose.
Examples:
- A resource named “Personal Greeting” with a clear description helps Claude understand when it’s appropriate to use
- Resources with vague names or descriptions may be used less frequently
5. Previous Successful Usage
Claude learns from the conversation flow and is more likely to use resources that have previously provided helpful information.
Practical Implementation
To maximize the chances Claude will use your resources appropriately:
1. Clear Resource URIs
Design URI patterns that clearly communicate their purpose:
#Good: Clear purpose and parameter@mcp.resource("weather://{city}")
# Less clear: Purpose and parameters ambiguous
@mcp.resource("data://{param}")
2. Comprehensive Resource Listings
Implement a thorough list://resources
endpoint:
@mcp.resource("list://resources")
def list_resources() -> dict:
return {
"resources": [
{
"uri": "greetings://{name}",
"name": "Personal Greeting",
"description": "Generates a friendly greeting for a specified person",
"mime_type": "text/plain",
"examples": ["greetings://Alice", "greetings://Bob"]
},
# Additional resources with detailed metadata
]
}
3. Descriptive Documentation
Add clear docstrings to your resource handlers:
@mcp.resource("products://{category}/{id}")
def get_product_info(category: str, id: str) -> dict:
"""Retrieve detailed product information by category and ID.
This resource provides pricing, availability, specifications,
and other details for products in our catalog.
Examples:
- products://electronics/e123 โ Smartphone XYZ
- products://books/b789 โ Python Programming book
"""
# Implementation...
4. Error Handling
Implement graceful error handling so Claude learns when resources are appropriate:
@mcp.resource("users://{user_id}")
def get_user(user_id: str) -> dict:
try:
# Attempt to fetch user
user = db.get_user(user_id)
if user:
return {"success": True, "user": user}
else:
# Informative error helps Claude learn
return {
"success": False,
"reason": "User not found",
"valid_format": True,
"suggestion": "Try a different user ID"
}
except ValueError:
# Format error helps Claude learn pattern constraints
return {
"success": False,
"reason": "Invalid user ID format",
"valid_format": False,
"expected_format": "Numeric ID between 1000-9999"
}
Testing Resource Discovery
To verify if Claude is discovering and understanding your resources:
- Ask directly: Copy
"What resources do you have access to from my MCP server?"
- Request resource examples: Copy
"Can you give me examples of how to use the resources in my MCP server?"
- Check specific resources: Copy
"Do you have access to a greeting resource? How would you use it?"
By implementing these best practices, you significantly increase the likelihood that Claude will identify and use your MCP resources at the appropriate times, creating a more seamless and intelligent interaction for your users.