Uniform Resource Identifiers (URIs) serve as the addressing system for the Model Context Protocol. While the Client-Host-Server topology creates the communication pipeline, URIs provide the specific coordinates required to locate and retrieve data. When an LLM or client application needs to access a specific piece of context, such as a file, a row in a database, or a system log, it relies on a structured string to uniquely identify that item.
In MCP, URIs are not merely static addresses. They function alongside URI Templates, which allow servers to advertise classes of available resources rather than listing every single item individually. This distinction is critical for performance. A server wrapping a database with millions of rows cannot send a list of millions of URIs to the client during the initialization handshake. Instead, it sends a template showing the pattern for accessing those rows.
MCP URIs follow the standard syntax defined in RFC 3986. Understanding this structure is necessary for designing intuitive and collision-resistant resource names. A typical URI consists of a scheme, an optional authority, and a path.
URI = scheme ":" ["//" authority] path ["?" query] ["#" fragment]
In the context of MCP servers, the components function as follows:
file, http, and https are common, MCP servers often define custom schemes like linear, postgres, or app-logs to namespace their resources.The following diagram outlines how an MCP server parses these components to route a request to the correct internal handler.
Flow of a URI request through the server parsing logic to a specific function handler.
A static resource represents a single, unchanging URI, such as config://application/settings. This works well for singular assets. However, most applications deal with dynamic collections of data. To handle this, MCP utilizes URI Templates (RFC 6570).
A template includes variables enclosed in braces, such as file:///{path}. When a server registers this resource, it tells the client: "I can handle any URI that matches this pattern."
When a client requests file:///Users/jdoe/project/readme.md, the MCP SDK automatically performs pattern matching. It extracts /Users/jdoe/project/readme.md from the URI and passes it as an argument to your registered function. This separation of the interface (the template) from the implementation (the function) allows for scalable resource exposure.
When using the Python SDK, you define these patterns using decorators. The framework handles the routing logic.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("FileSystemServer")
# Static Resource: No variables
@mcp.resource("app://metadata")
def get_metadata() -> str:
return "Version 1.0.0 - File Reader System"
# Dynamic Resource: Uses a template variable {path}
@mcp.resource("file:///{path}")
def read_file(path: str) -> str:
"""Reads a file from the local filesystem."""
try:
# In a real implementation, validate 'path' to prevent directory traversal
with open(path, "r") as f:
return f.read()
except FileNotFoundError:
return "Error: File not found."
In this example, the SDK registers the pattern file:///{path}. If the LLM generates a request for file:///etc/hosts, the variable path receives the value /etc/hosts.
Selecting the correct scheme is an architectural decision that affects how the LLM interprets the data context. A clear, semantic scheme helps the model understand the nature of the data before it even reads the content.
file://. This signals to the client that the path likely conforms to filesystem conventions.slack://channels/{id} is more descriptive than app://slack/channels/{id}.http/https for Proxies: Unless your resource is literally a web page being fetched, avoid http or https. If your server fetches data from a REST API and returns a JSON object, define a custom scheme like api://. Using https might confuse the model into thinking it can browse the web directly, rather than interacting with your specific API wrapper.The matching process within an MCP server follows a specific precedence. Understanding this helps avoid routing conflicts, especially when you have overlapping patterns.
Generally, exact matches take precedence over template matches. If you define both a generic file reader and a specific handler for a readme file, the specific handler should trigger when that exact URI is requested.
Consider the routing logic for a database server exposing user records:
Decision tree for routing incoming URIs to the appropriate handler.
MCP URIs support query parameters, which are useful for filtering or modifying the resource representation without changing the resource identity. For instance, you might want to retrieve only the last 50 lines of a log file.
The URI might look like logs://system/error.log?lines=50.
In your resource handler, parsing these parameters depends on the specific SDK implementation details, but generally, the full URI is available for inspection. When defining patterns, it is common practice to define the path in the template (logs://{type}/{name}) and treat the query string as optional metadata handled inside the function logic.
users://123/profile is superior to data://obj?id=5921&type=u.By rigorously defining your URI schemes and patterns, you create a predictable map of your data. This allows the LLM to act as an intelligent navigator, requesting exactly the context it needs to answer user queries.
Was this section helpful?
© 2026 ApX Machine LearningEngineered with