diff --git a/docs/servers/context.mdx b/docs/servers/context.mdx
index cb4fe52ad..c33f1812c 100644
--- a/docs/servers/context.mdx
+++ b/docs/servers/context.mdx
@@ -14,7 +14,8 @@ The `Context` object provides a clean interface to access MCP features within yo
- **Logging**: Send debug, info, warning, and error messages back to the client
- **Progress Reporting**: Update the client on the progress of long-running operations
-- **Resource Access**: Read data from resources registered with the server
+- **Resource Access**: List and read data from resources registered with the server
+- **Prompt Access**: List and retrieve prompts registered with the server
- **LLM Sampling**: Request the client's LLM to generate text based on provided messages
- **User Elicitation**: Request structured input from users during tool execution
- **State Management**: Store and share data between middleware and the handler within a single request
@@ -177,16 +178,40 @@ See [Progress Reporting](/servers/progress) for detailed patterns and examples.
### Resource Access
-Read data from resources registered with your FastMCP server, allowing access to files, configuration, or dynamic content.
+List and read data from resources registered with your FastMCP server, allowing access to files, configuration, or dynamic content.
```python
+# List available resources
+resources = await ctx.list_resources()
+
+# Read a specific resource
content_list = await ctx.read_resource("resource://config")
content = content_list[0].content
```
-**Method signature:**
+**Method signatures:**
+- **`ctx.list_resources() -> list[MCPResource]`**: Returns list of all available resources
- **`ctx.read_resource(uri: str | AnyUrl) -> list[ReadResourceContents]`**: Returns a list of resource content parts
+### Prompt Access
+
+
+
+List and retrieve prompts registered with your FastMCP server, allowing tools and middleware to discover and use available prompts programmatically.
+
+```python
+# List available prompts
+prompts = await ctx.list_prompts()
+
+# Get a specific prompt with arguments
+result = await ctx.get_prompt("analyze_data", {"dataset": "users"})
+messages = result.messages
+```
+
+**Method signatures:**
+- **`ctx.list_prompts() -> list[MCPPrompt]`**: Returns list of all available prompts
+- **`ctx.get_prompt(name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult`**: Get a specific prompt with optional arguments
+
### State Management
diff --git a/src/fastmcp/server/context.py b/src/fastmcp/server/context.py
index a0fcfc1c2..b5dbc5533 100644
--- a/src/fastmcp/server/context.py
+++ b/src/fastmcp/server/context.py
@@ -22,6 +22,7 @@ from mcp.types import (
AudioContent,
ClientCapabilities,
CreateMessageResult,
+ GetPromptResult,
ImageContent,
IncludeContext,
ModelHint,
@@ -32,6 +33,8 @@ from mcp.types import (
TextContent,
)
from mcp.types import CreateMessageRequestParams as SamplingParams
+from mcp.types import Prompt as MCPPrompt
+from mcp.types import Resource as MCPResource
from pydantic.networks import AnyUrl
from starlette.requests import Request
from typing_extensions import TypeVar
@@ -215,6 +218,36 @@ class Context:
related_request_id=self.request_id,
)
+ async def list_resources(self) -> list[MCPResource]:
+ """List all available resources from the server.
+
+ Returns:
+ List of Resource objects available on the server
+ """
+ return await self.fastmcp._list_resources_mcp()
+
+ async def list_prompts(self) -> list[MCPPrompt]:
+ """List all available prompts from the server.
+
+ Returns:
+ List of Prompt objects available on the server
+ """
+ return await self.fastmcp._list_prompts_mcp()
+
+ async def get_prompt(
+ self, name: str, arguments: dict[str, Any] | None = None
+ ) -> GetPromptResult:
+ """Get a prompt by name with optional arguments.
+
+ Args:
+ name: The name of the prompt to get
+ arguments: Optional arguments to pass to the prompt
+
+ Returns:
+ The prompt result
+ """
+ return await self.fastmcp._get_prompt_mcp(name, arguments)
+
async def read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents]:
"""Read a resource by URI.
@@ -224,8 +257,6 @@ class Context:
Returns:
The resource content as either text or bytes
"""
- if self.fastmcp is None:
- raise ValueError("Context is not available outside of a request")
return await self.fastmcp._read_resource_mcp(uri)
async def log(
diff --git a/src/fastmcp/server/middleware/tool_injection.py b/src/fastmcp/server/middleware/tool_injection.py
index 8df5d18a4..7914c5eca 100644
--- a/src/fastmcp/server/middleware/tool_injection.py
+++ b/src/fastmcp/server/middleware/tool_injection.py
@@ -10,8 +10,6 @@ from mcp.types import Prompt
from pydantic import AnyUrl
from typing_extensions import override
-from fastmcp.client.client import Client
-from fastmcp.client.transports import FastMCPTransport
from fastmcp.server.context import Context
from fastmcp.server.middleware.middleware import CallNext, Middleware, MiddlewareContext
from fastmcp.tools.tool import Tool, ToolResult
@@ -55,9 +53,7 @@ class ToolInjectionMiddleware(Middleware):
async def list_prompts(context: Context) -> list[Prompt]:
"""List prompts available on the server."""
-
- async with Client[FastMCPTransport](context.fastmcp) as client:
- return await client.list_prompts()
+ return await context.list_prompts()
list_prompts_tool = Tool.from_function(
@@ -73,9 +69,7 @@ async def get_prompt(
] = None,
) -> mcp.types.GetPromptResult:
"""Render a prompt available on the server."""
-
- async with Client[FastMCPTransport](context.fastmcp) as client:
- return await client.get_prompt(name=name, arguments=arguments)
+ return await context.get_prompt(name=name, arguments=arguments)
get_prompt_tool = Tool.from_function(
@@ -93,9 +87,7 @@ class PromptToolMiddleware(ToolInjectionMiddleware):
async def list_resources(context: Context) -> list[mcp.types.Resource]:
"""List resources available on the server."""
-
- async with Client[FastMCPTransport](context.fastmcp) as client:
- return await client.list_resources()
+ return await context.list_resources()
list_resources_tool = Tool.from_function(
diff --git a/uv.lock b/uv.lock
index 3c06bb91d..01c073600 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,5 +1,5 @@
version = 1
-revision = 2
+revision = 3
requires-python = ">=3.10"
resolution-markers = [
"python_full_version >= '3.11'",
@@ -566,7 +566,6 @@ dependencies = [
{ name = "py-key-value-aio", extra = ["disk", "keyring", "memory"] },
{ name = "pydantic", extra = ["email"] },
{ name = "pyperclip" },
- { name = "pytest-asyncio" },
{ name = "python-dotenv" },
{ name = "rich" },
{ name = "websockets" },
@@ -591,6 +590,7 @@ dev = [
{ name = "pyinstrument" },
{ name = "pyperclip" },
{ name = "pytest" },
+ { name = "pytest-asyncio" },
{ name = "pytest-cov" },
{ name = "pytest-env" },
{ name = "pytest-flakefinder" },
@@ -617,7 +617,6 @@ requires-dist = [
{ name = "py-key-value-aio", extras = ["disk", "keyring", "memory"], specifier = ">=0.2.6,<0.3.0" },
{ name = "pydantic", extras = ["email"], specifier = ">=2.11.7" },
{ name = "pyperclip", specifier = ">=1.9.0" },
- { name = "pytest-asyncio", specifier = ">=1.2.0" },
{ name = "python-dotenv", specifier = ">=1.1.0" },
{ name = "rich", specifier = ">=13.9.4" },
{ name = "websockets", specifier = ">=15.0.1" },
@@ -637,6 +636,7 @@ dev = [
{ name = "pyinstrument", specifier = ">=5.0.2" },
{ name = "pyperclip", specifier = ">=1.9.0" },
{ name = "pytest", specifier = ">=8.3.3" },
+ { name = "pytest-asyncio", specifier = ">=1.2.0" },
{ name = "pytest-cov", specifier = ">=6.1.1" },
{ name = "pytest-env", specifier = ">=1.1.5" },
{ name = "pytest-flakefinder" },