From 63add1897016be3f97ac57abbd21f2b78541206e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 22:34:45 +0000 Subject: [PATCH 1/2] Add list_resources, list_prompts, and get_prompt methods to Context - Add Context.list_resources() to list all available resources - Add Context.list_prompts() to list all available prompts - Add Context.get_prompt() to get a specific prompt with arguments - Update ToolInjectionMiddleware to use new Context methods instead of creating temporary Client instances - Remove unused Client and FastMCPTransport imports from tool_injection.py This improves API consistency by allowing middleware/tools to use Context methods directly without needing to create temporary Client instances. Fixes #2245 Co-authored-by: William Easton --- src/fastmcp/server/context.py | 39 +++++++++++++++++++ .../server/middleware/tool_injection.py | 14 ++----- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/fastmcp/server/context.py b/src/fastmcp/server/context.py index a0fcfc1c2..1c565db55 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,42 @@ 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 + """ + if self.fastmcp is None: + raise ValueError("Context is not available outside of a request") + 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 + """ + if self.fastmcp is None: + raise ValueError("Context is not available outside of a request") + 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 + """ + if self.fastmcp is None: + raise ValueError("Context is not available outside of a request") + return await self.fastmcp._get_prompt_mcp(name, arguments) + async def read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents]: """Read a resource by URI. 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( From 7de74c05cbb6d892fa5579f1087e4e7fa162dc99 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Fri, 24 Oct 2025 19:16:25 -0400 Subject: [PATCH 2/2] Update docs --- docs/servers/context.mdx | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/servers/context.mdx b/docs/servers/context.mdx index 720272fb7..f9c32dacb 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