From 0cc7d88bd76dc897532cd3b009657f6b14deb89c Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:54:56 -0400 Subject: [PATCH] Update docs and add_resource_fn --- docs/getting-started/welcome.mdx | 6 +++--- docs/patterns/decorating-methods.mdx | 17 ++++++++++------- src/fastmcp/server/server.py | 2 +- tests/server/test_server.py | 8 ++++---- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/getting-started/welcome.mdx b/docs/getting-started/welcome.mdx index b0b116649..b8d80dee1 100644 --- a/docs/getting-started/welcome.mdx +++ b/docs/getting-started/welcome.mdx @@ -27,9 +27,9 @@ if __name__ == "__main__": ## What is MCP? The Model Context Protocol lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. It is often described as "the USB-C port for AI", providing a uniform way to connect LLMs to resources they can use. It may be easier to think of it as an API, but specifically designed for LLM interactions. MCP servers can: -- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context) -- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) -- Define interaction patterns through **Prompts** (reusable templates for LLM interactions) +- Expose data through `Resources` (think of these sort of like GET endpoints; they are used to load information into the LLM's context) +- Provide functionality through `Tools` (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) +- Define interaction patterns through `Prompts` (reusable templates for LLM interactions) - And more! There is a low-level Python SDK available for implementing the protocol directly, but FastMCP aims to make that easier by providing a high-level, Pythonic interface. diff --git a/docs/patterns/decorating-methods.mdx b/docs/patterns/decorating-methods.mdx index c49fe07a6..906142c44 100644 --- a/docs/patterns/decorating-methods.mdx +++ b/docs/patterns/decorating-methods.mdx @@ -5,11 +5,11 @@ description: Properly use instance methods, class methods, and static methods wi icon: at --- -FastMCP's decorator system is designed to work with functions, but you may see unexpected behavior if you try to decorate an instance or class method. This guide explains the correct approach for using methods with all FastMCP decorators (`@mcp.tool()`, `@mcp.resource()`, and `@mcp.prompt()`). +FastMCP's decorator system is designed to work with functions, but you may see unexpected behavior if you try to decorate an instance or class method. This guide explains the correct approach for using methods with all FastMCP decorators (`@tool()`, `@resource()`, and `@prompt()`). ## Why Are Methods Hard? -When you apply a FastMCP decorator like `@mcp.tool()`, `@mcp.resource()`, or `@mcp.prompt()` to a method, the decorator captures the function at decoration time. For instance methods and class methods, this poses a challenge because: +When you apply a FastMCP decorator like `@tool()`, `@resource()`, or `@prompt()` to a method, the decorator captures the function at decoration time. For instance methods and class methods, this poses a challenge because: 1. For instance methods: The decorator gets the unbound method before any instance exists 2. For class methods: The decorator gets the function before it's bound to the class @@ -56,7 +56,10 @@ class MyClass: # Create an instance first, then add the bound methods obj = MyClass() mcp.add_tool(obj.add) -mcp.add_resource(obj.get_resource, uri="resource://{param}") # For resources +mcp.add_resource_fn(obj.get_resource, uri="resource://{param}") # For resources or templates + +# Note: FastMCP provides add_resource() for adding Resource objects directly and +# add_resource_fn() for adding functions that generate resources or templates # Now you can call it without 'self' showing up as a parameter await mcp.call_tool('add', {'x': 1, 'y': 2}) # Returns 3 @@ -167,7 +170,7 @@ class ComponentProvider: def __init__(self, mcp_instance): # Register methods mcp_instance.add_tool(self.tool_method) - mcp_instance.add_resource(self.resource_method, uri="resource://data") + mcp_instance.add_resource_fn(self.resource_method, uri="resource://data") def tool_method(self, x): return x * 2 @@ -191,8 +194,8 @@ The class automatically registers its methods during initialization, ensuring th While FastMCP's decorator pattern works seamlessly with regular functions and static methods, for instance methods and class methods, you should add them after creating the instance or class. This ensures that the methods are properly bound before being registered. These patterns apply to all FastMCP decorators and registration methods: -- `@mcp.tool()` and `mcp.add_tool()` -- `@mcp.resource()` and `mcp.add_resource()` -- `@mcp.prompt()` and `mcp.add_prompt()` +- `@tool()` and `add_tool()` +- `@resource()` and `add_resource_fn()` +- `@prompt()` and `add_prompt()` Understanding these patterns allows you to effectively organize your components into classes while maintaining proper method binding, giving you the benefits of object-oriented design without sacrificing the simplicity of FastMCP's decorator system. diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index 1633e9d0d..a6e7119b2 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -372,7 +372,7 @@ class FastMCP(Generic[LifespanResultT]): self._resource_manager.add_resource(resource) - def add_resource_from_fn( + def add_resource_fn( self, fn: AnyFunction, uri: str, diff --git a/tests/server/test_server.py b/tests/server/test_server.py index 9c479a6de..004e113cd 100644 --- a/tests/server/test_server.py +++ b/tests/server/test_server.py @@ -269,7 +269,7 @@ class TestResourceDecorator: return f"{self.prefix} Hello, world!" obj = MyClass("My prefix:") - mcp.add_resource_from_fn( + mcp.add_resource_fn( obj.get_data, uri="resource://data", name="instance-resource" ) @@ -286,7 +286,7 @@ class TestResourceDecorator: def get_data(cls) -> str: return f"{cls.prefix} Hello, world!" - mcp.add_resource_from_fn( + mcp.add_resource_fn( MyClass.get_data, uri="resource://data", name="class-resource" ) @@ -390,7 +390,7 @@ class TestTemplateDecorator: obj = MyClass("My prefix:") - mcp.add_resource_from_fn( + mcp.add_resource_fn( obj.get_data, uri="resource://{name}/data", name="instance-template" ) @@ -407,7 +407,7 @@ class TestTemplateDecorator: def get_data(cls, name: str) -> str: return f"{cls.prefix} Data for {name}" - mcp.add_resource_from_fn( + mcp.add_resource_fn( MyClass.get_data, uri="resource://{name}/data", name="class-template" )