Jeremiah Lowin commited on
Commit
f1f59fd
·
1 Parent(s): 3b5b8a2

Update docs and add_resource_fn

Browse files
docs/getting-started/welcome.mdx CHANGED
@@ -27,9 +27,9 @@ if __name__ == "__main__":
27
  ## What is MCP?
28
  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:
29
 
30
- - Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
31
- - Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
32
- - Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
33
  - And more!
34
 
35
  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.
 
27
  ## What is MCP?
28
  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:
29
 
30
+ - Expose data through `Resources` (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
31
+ - Provide functionality through `Tools` (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
32
+ - Define interaction patterns through `Prompts` (reusable templates for LLM interactions)
33
  - And more!
34
 
35
  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.
docs/patterns/decorating-methods.mdx CHANGED
@@ -5,11 +5,11 @@ description: Properly use instance methods, class methods, and static methods wi
5
  icon: at
6
  ---
7
 
8
- 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()`).
9
 
10
  ## Why Are Methods Hard?
11
 
12
- 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:
13
 
14
  1. For instance methods: The decorator gets the unbound method before any instance exists
15
  2. For class methods: The decorator gets the function before it's bound to the class
@@ -56,7 +56,10 @@ class MyClass:
56
  # Create an instance first, then add the bound methods
57
  obj = MyClass()
58
  mcp.add_tool(obj.add)
59
- mcp.add_resource(obj.get_resource, uri="resource://{param}") # For resources
 
 
 
60
 
61
  # Now you can call it without 'self' showing up as a parameter
62
  await mcp.call_tool('add', {'x': 1, 'y': 2}) # Returns 3
@@ -167,7 +170,7 @@ class ComponentProvider:
167
  def __init__(self, mcp_instance):
168
  # Register methods
169
  mcp_instance.add_tool(self.tool_method)
170
- mcp_instance.add_resource(self.resource_method, uri="resource://data")
171
 
172
  def tool_method(self, x):
173
  return x * 2
@@ -191,8 +194,8 @@ The class automatically registers its methods during initialization, ensuring th
191
  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.
192
 
193
  These patterns apply to all FastMCP decorators and registration methods:
194
- - `@mcp.tool()` and `mcp.add_tool()`
195
- - `@mcp.resource()` and `mcp.add_resource()`
196
- - `@mcp.prompt()` and `mcp.add_prompt()`
197
 
198
  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.
 
5
  icon: at
6
  ---
7
 
8
+ 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()`).
9
 
10
  ## Why Are Methods Hard?
11
 
12
+ 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:
13
 
14
  1. For instance methods: The decorator gets the unbound method before any instance exists
15
  2. For class methods: The decorator gets the function before it's bound to the class
 
56
  # Create an instance first, then add the bound methods
57
  obj = MyClass()
58
  mcp.add_tool(obj.add)
59
+ mcp.add_resource_fn(obj.get_resource, uri="resource://{param}") # For resources or templates
60
+
61
+ # Note: FastMCP provides add_resource() for adding Resource objects directly and
62
+ # add_resource_fn() for adding functions that generate resources or templates
63
 
64
  # Now you can call it without 'self' showing up as a parameter
65
  await mcp.call_tool('add', {'x': 1, 'y': 2}) # Returns 3
 
170
  def __init__(self, mcp_instance):
171
  # Register methods
172
  mcp_instance.add_tool(self.tool_method)
173
+ mcp_instance.add_resource_fn(self.resource_method, uri="resource://data")
174
 
175
  def tool_method(self, x):
176
  return x * 2
 
194
  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.
195
 
196
  These patterns apply to all FastMCP decorators and registration methods:
197
+ - `@tool()` and `add_tool()`
198
+ - `@resource()` and `add_resource_fn()`
199
+ - `@prompt()` and `add_prompt()`
200
 
201
  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.
src/fastmcp/server/server.py CHANGED
@@ -372,7 +372,7 @@ class FastMCP(Generic[LifespanResultT]):
372
 
373
  self._resource_manager.add_resource(resource)
374
 
375
- def add_resource_from_fn(
376
  self,
377
  fn: AnyFunction,
378
  uri: str,
 
372
 
373
  self._resource_manager.add_resource(resource)
374
 
375
+ def add_resource_fn(
376
  self,
377
  fn: AnyFunction,
378
  uri: str,
tests/server/test_server.py CHANGED
@@ -269,7 +269,7 @@ class TestResourceDecorator:
269
  return f"{self.prefix} Hello, world!"
270
 
271
  obj = MyClass("My prefix:")
272
- mcp.add_resource_from_fn(
273
  obj.get_data, uri="resource://data", name="instance-resource"
274
  )
275
 
@@ -286,7 +286,7 @@ class TestResourceDecorator:
286
  def get_data(cls) -> str:
287
  return f"{cls.prefix} Hello, world!"
288
 
289
- mcp.add_resource_from_fn(
290
  MyClass.get_data, uri="resource://data", name="class-resource"
291
  )
292
 
@@ -390,7 +390,7 @@ class TestTemplateDecorator:
390
 
391
  obj = MyClass("My prefix:")
392
 
393
- mcp.add_resource_from_fn(
394
  obj.get_data, uri="resource://{name}/data", name="instance-template"
395
  )
396
 
@@ -407,7 +407,7 @@ class TestTemplateDecorator:
407
  def get_data(cls, name: str) -> str:
408
  return f"{cls.prefix} Data for {name}"
409
 
410
- mcp.add_resource_from_fn(
411
  MyClass.get_data, uri="resource://{name}/data", name="class-template"
412
  )
413
 
 
269
  return f"{self.prefix} Hello, world!"
270
 
271
  obj = MyClass("My prefix:")
272
+ mcp.add_resource_fn(
273
  obj.get_data, uri="resource://data", name="instance-resource"
274
  )
275
 
 
286
  def get_data(cls) -> str:
287
  return f"{cls.prefix} Hello, world!"
288
 
289
+ mcp.add_resource_fn(
290
  MyClass.get_data, uri="resource://data", name="class-resource"
291
  )
292
 
 
390
 
391
  obj = MyClass("My prefix:")
392
 
393
+ mcp.add_resource_fn(
394
  obj.get_data, uri="resource://{name}/data", name="instance-template"
395
  )
396
 
 
407
  def get_data(cls, name: str) -> str:
408
  return f"{cls.prefix} Data for {name}"
409
 
410
+ mcp.add_resource_fn(
411
  MyClass.get_data, uri="resource://{name}/data", name="class-template"
412
  )
413