From b3f80c5374cecf7dd66a86024e25284766867fef Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:39:57 -0400 Subject: [PATCH] Add empty parens to docs --- README.md | 10 +++--- docs/clients/transports.mdx | 2 +- docs/deployment/asgi.mdx | 2 +- docs/deployment/running-server.mdx | 4 +-- docs/getting-started/quickstart.mdx | 6 ++-- docs/getting-started/welcome.mdx | 2 +- docs/integrations/anthropic.mdx | 4 +-- docs/integrations/claude-desktop.mdx | 2 +- docs/integrations/gemini.mdx | 2 +- docs/integrations/openai.mdx | 4 +-- docs/patterns/cli.mdx | 2 +- docs/patterns/decorating-methods.mdx | 6 ++-- docs/patterns/http-requests.mdx | 4 +-- docs/patterns/testing.mdx | 2 +- docs/servers/auth/bearer.mdx | 2 +- docs/servers/composition.mdx | 6 ++-- docs/servers/context.mdx | 22 ++++++------ docs/servers/fastmcp.mdx | 10 +++--- docs/servers/prompts.mdx | 18 +++++----- docs/servers/proxy.mdx | 2 +- docs/servers/tools.mdx | 52 ++++++++++++++-------------- 21 files changed, 82 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index 082c4dc22..7374fa6b1 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ from fastmcp import FastMCP mcp = FastMCP("Demo 🚀") -@mcp.tool +@mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b @@ -144,7 +144,7 @@ Learn more in the [**FastMCP Server Documentation**](https://gofastmcp.com/serve Tools allow LLMs to perform actions by executing your Python functions (sync or async). Ideal for computations, API calls, or side effects (like `POST`/`PUT`). FastMCP handles schema generation from type hints and docstrings. Tools can return various types, including text, JSON-serializable objects, and even images using the [`fastmcp.Image`](https://gofastmcp.com/servers/tools#return-values) helper. ```python -@mcp.tool +@mcp.tool() def multiply(a: float, b: float) -> float: """Multiplies two numbers.""" return a * b @@ -176,7 +176,7 @@ Learn more in the [**Resources & Templates Documentation**](https://gofastmcp.co Prompts define reusable message templates to guide LLM interactions. Decorate functions with `@mcp.prompt`. Return strings or `Message` objects. ```python -@mcp.prompt +@mcp.prompt() def summarize_request(text: str) -> str: """Generate a prompt asking for a summary.""" return f"Please summarize the following text:\n\n{text}" @@ -201,7 +201,7 @@ from fastmcp import FastMCP, Context mcp = FastMCP("My MCP Server") -@mcp.tool +@mcp.tool() async def process_data(uri: str, ctx: Context): # Log a message to the client await ctx.info(f"Processing {uri}...") @@ -321,7 +321,7 @@ from fastmcp import FastMCP mcp = FastMCP("Demo 🚀") -@mcp.tool +@mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" diff --git a/docs/clients/transports.mdx b/docs/clients/transports.mdx index 94c94833c..6ed9fc489 100644 --- a/docs/clients/transports.mdx +++ b/docs/clients/transports.mdx @@ -359,7 +359,7 @@ import asyncio # 1. Create your FastMCP server instance server = FastMCP(name="InMemoryServer") -@server.tool +@server.tool() def ping(): return "pong" diff --git a/docs/deployment/asgi.mdx b/docs/deployment/asgi.mdx index 06da46374..ace7ee136 100644 --- a/docs/deployment/asgi.mdx +++ b/docs/deployment/asgi.mdx @@ -32,7 +32,7 @@ from fastmcp import FastMCP mcp = FastMCP("MyServer") -@mcp.tool +@mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" diff --git a/docs/deployment/running-server.mdx b/docs/deployment/running-server.mdx index 5b6a7eadd..5f5d758d2 100644 --- a/docs/deployment/running-server.mdx +++ b/docs/deployment/running-server.mdx @@ -22,7 +22,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="MyServer") -@mcp.tool +@mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" @@ -244,7 +244,7 @@ import asyncio mcp = FastMCP(name="MyServer") -@mcp.tool +@mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx index b3569d486..13a6bbae5 100644 --- a/docs/getting-started/quickstart.mdx +++ b/docs/getting-started/quickstart.mdx @@ -32,7 +32,7 @@ from fastmcp import FastMCP mcp = FastMCP("My MCP Server") -@mcp.tool +@mcp.tool() def greet(name: str) -> str: return f"Hello, {name}!" ``` @@ -49,7 +49,7 @@ from fastmcp import FastMCP, Client mcp = FastMCP("My MCP Server") -@mcp.tool +@mcp.tool() def greet(name: str) -> str: return f"Hello, {name}!" @@ -76,7 +76,7 @@ from fastmcp import FastMCP mcp = FastMCP("My MCP Server") -@mcp.tool +@mcp.tool() def greet(name: str) -> str: return f"Hello, {name}!" diff --git a/docs/getting-started/welcome.mdx b/docs/getting-started/welcome.mdx index d9d921a7a..f5574217c 100644 --- a/docs/getting-started/welcome.mdx +++ b/docs/getting-started/welcome.mdx @@ -14,7 +14,7 @@ from fastmcp import FastMCP mcp = FastMCP("Demo 🚀") -@mcp.tool +@mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b diff --git a/docs/integrations/anthropic.mdx b/docs/integrations/anthropic.mdx index bcea25769..0920afce2 100644 --- a/docs/integrations/anthropic.mdx +++ b/docs/integrations/anthropic.mdx @@ -27,7 +27,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="Dice Roller") -@mcp.tool +@mcp.tool() def roll_dice(n_dice: int) -> list[int]: """Roll `n_dice` 6-sided dice and return the results.""" return [random.randint(1, 6) for _ in range(n_dice)] @@ -170,7 +170,7 @@ auth = BearerAuthProvider( mcp = FastMCP(name="Dice Roller", auth=auth) -@mcp.tool +@mcp.tool() def roll_dice(n_dice: int) -> list[int]: """Roll `n_dice` 6-sided dice and return the results.""" return [random.randint(1, 6) for _ in range(n_dice)] diff --git a/docs/integrations/claude-desktop.mdx b/docs/integrations/claude-desktop.mdx index 9b8dc5404..7edafa68b 100644 --- a/docs/integrations/claude-desktop.mdx +++ b/docs/integrations/claude-desktop.mdx @@ -31,7 +31,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="Dice Roller") -@mcp.tool +@mcp.tool() def roll_dice(n_dice: int) -> list[int]: """Roll `n_dice` 6-sided dice and return the results.""" return [random.randint(1, 6) for _ in range(n_dice)] diff --git a/docs/integrations/gemini.mdx b/docs/integrations/gemini.mdx index 46ffd7a9d..d61d0feb0 100644 --- a/docs/integrations/gemini.mdx +++ b/docs/integrations/gemini.mdx @@ -31,7 +31,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="Dice Roller") -@mcp.tool +@mcp.tool() def roll_dice(n_dice: int) -> list[int]: """Roll `n_dice` 6-sided dice and return the results.""" return [random.randint(1, 6) for _ in range(n_dice)] diff --git a/docs/integrations/openai.mdx b/docs/integrations/openai.mdx index 52f3bb164..86f01e626 100644 --- a/docs/integrations/openai.mdx +++ b/docs/integrations/openai.mdx @@ -32,7 +32,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="Dice Roller") -@mcp.tool +@mcp.tool() def roll_dice(n_dice: int) -> list[int]: """Roll `n_dice` 6-sided dice and return the results.""" return [random.randint(1, 6) for _ in range(n_dice)] @@ -165,7 +165,7 @@ auth = BearerAuthProvider( mcp = FastMCP(name="Dice Roller", auth=auth) -@mcp.tool +@mcp.tool() def roll_dice(n_dice: int) -> list[int]: """Roll `n_dice` 6-sided dice and return the results.""" return [random.randint(1, 6) for _ in range(n_dice)] diff --git a/docs/patterns/cli.mdx b/docs/patterns/cli.mdx index 19e1ad1ab..b46d928d4 100644 --- a/docs/patterns/cli.mdx +++ b/docs/patterns/cli.mdx @@ -66,7 +66,7 @@ from fastmcp import FastMCP mcp = FastMCP("MyServer") -@mcp.tool +@mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" diff --git a/docs/patterns/decorating-methods.mdx b/docs/patterns/decorating-methods.mdx index b4ac48072..587e2dbb7 100644 --- a/docs/patterns/decorating-methods.mdx +++ b/docs/patterns/decorating-methods.mdx @@ -28,7 +28,7 @@ from fastmcp import FastMCP mcp = FastMCP() class MyClass: - @mcp.tool # This won't work correctly +@mcp.tool() # This won't work correctly def add(self, x, y): return x + y @@ -83,7 +83,7 @@ mcp = FastMCP() class MyClass: @classmethod - @mcp.tool # This won't work correctly +@mcp.tool() # This won't work correctly def from_string(cls, s): return cls(s) ``` @@ -122,7 +122,7 @@ mcp = FastMCP() class MyClass: @staticmethod - @mcp.tool # This works! +@mcp.tool() # This works! def utility(x, y): return x + y diff --git a/docs/patterns/http-requests.mdx b/docs/patterns/http-requests.mdx index c9b412c5d..ceb333e19 100644 --- a/docs/patterns/http-requests.mdx +++ b/docs/patterns/http-requests.mdx @@ -25,7 +25,7 @@ from starlette.requests import Request mcp = FastMCP(name="HTTP Request Demo") -@mcp.tool +@mcp.tool() async def user_agent_info() -> dict: """Return information about the user agent.""" # Get the HTTP request @@ -58,7 +58,7 @@ from fastmcp.server.dependencies import get_http_headers mcp = FastMCP(name="Headers Demo") -@mcp.tool +@mcp.tool() async def safe_header_info() -> dict: """Safely get header information without raising errors.""" # Get headers (returns empty dict if no request context) diff --git a/docs/patterns/testing.mdx b/docs/patterns/testing.mdx index adc3f516a..c8df2c759 100644 --- a/docs/patterns/testing.mdx +++ b/docs/patterns/testing.mdx @@ -22,7 +22,7 @@ from fastmcp import FastMCP, Client def mcp_server(): server = FastMCP("TestServer") - @server.tool +@server.tool() def greet(name: str) -> str: return f"Hello, {name}!" diff --git a/docs/servers/auth/bearer.mdx b/docs/servers/auth/bearer.mdx index 13053b5b2..c695c10e6 100644 --- a/docs/servers/auth/bearer.mdx +++ b/docs/servers/auth/bearer.mdx @@ -159,7 +159,7 @@ Once authenticated, your tools, resources, or prompts can access token informati from fastmcp import FastMCP, Context, ToolError from fastmcp.server.dependencies import get_access_token, AccessToken -@mcp.tool +@mcp.tool() async def get_my_data(ctx: Context) -> dict: access_token: AccessToken = get_access_token() diff --git a/docs/servers/composition.mdx b/docs/servers/composition.mdx index 04dc559d0..b1519b3f3 100644 --- a/docs/servers/composition.mdx +++ b/docs/servers/composition.mdx @@ -50,7 +50,7 @@ import asyncio # Define subservers weather_mcp = FastMCP(name="WeatherService") -@weather_mcp.tool +@weather_mcp.tool() def get_forecast(city: str) -> dict: """Get weather forecast.""" return {"city": city, "forecast": "Sunny"} @@ -102,7 +102,7 @@ from fastmcp import FastMCP, Client # Define subserver dynamic_mcp = FastMCP(name="DynamicService") -@dynamic_mcp.tool +@dynamic_mcp.tool() def initial_tool(): """Initial tool demonstration.""" return "Initial Tool Exists" @@ -112,7 +112,7 @@ main_mcp = FastMCP(name="MainAppLive") main_mcp.mount("dynamic", dynamic_mcp) # Add a tool AFTER mounting - it will be accessible through main_mcp -@dynamic_mcp.tool +@dynamic_mcp.tool() def added_later(): """Tool added after mounting.""" return "Tool Added Dynamically!" diff --git a/docs/servers/context.mdx b/docs/servers/context.mdx index 0f075d264..555a0c105 100644 --- a/docs/servers/context.mdx +++ b/docs/servers/context.mdx @@ -41,7 +41,7 @@ from fastmcp import FastMCP, Context mcp = FastMCP(name="ContextDemo") -@mcp.tool +@mcp.tool() async def process_file(file_uri: str, ctx: Context) -> str: """Processes a file, using context for logging and resource access.""" # Context is available as the ctx parameter @@ -71,7 +71,7 @@ async def get_user_profile(user_id: str, ctx: Context) -> dict: ```python -@mcp.prompt +@mcp.prompt() async def data_analysis_request(dataset: str, ctx: Context) -> str: """Generate a request to analyze data with contextual information.""" # Context is available as the ctx parameter @@ -99,7 +99,7 @@ async def process_data(data: list[float]) -> dict: ctx = get_context() await ctx.info(f"Processing {len(data)} data points") -@mcp.tool +@mcp.tool() async def analyze_dataset(dataset_name: str) -> dict: # Call utility function that uses context internally data = load_data(dataset_name) @@ -118,7 +118,7 @@ async def analyze_dataset(dataset_name: str) -> dict: Send log messages back to the MCP client. This is useful for debugging and providing visibility into function execution during a request. ```python -@mcp.tool +@mcp.tool() async def analyze_data(data: list[float], ctx: Context) -> dict: """Analyze numerical data with logging.""" await ctx.debug("Starting analysis of numerical data") @@ -149,7 +149,7 @@ async def analyze_data(data: list[float], ctx: Context) -> dict: For long-running operations, notify the client about the progress. This allows clients to display progress indicators and provide a better user experience. ```python -@mcp.tool +@mcp.tool() async def process_items(items: list[str], ctx: Context) -> dict: """Process a list of items with progress updates.""" total = len(items) @@ -182,7 +182,7 @@ Progress reporting requires the client to have sent a `progressToken` in the ini Read data from resources registered with your FastMCP server. This allows functions to access files, configuration, or dynamically generated content. ```python -@mcp.tool +@mcp.tool() async def summarize_document(document_uri: str, ctx: Context) -> str: """Summarize a document by its resource URI.""" # Read the document content @@ -222,7 +222,7 @@ The returned content is typically accessed via `content_list[0].content` and can Request the client's LLM to generate text based on provided messages. This is useful when your function needs to leverage the LLM's capabilities to process data or generate responses. ```python -@mcp.tool +@mcp.tool() async def analyze_sentiment(text: str, ctx: Context) -> dict: """Analyze the sentiment of a text using the client's LLM.""" # Create a sampling prompt asking for sentiment analysis @@ -258,7 +258,7 @@ async def analyze_sentiment(text: str, ctx: Context) -> dict: When providing a simple string, it's treated as a user message. For more complex scenarios, you can provide a list of messages with different roles. ```python -@mcp.tool +@mcp.tool() async def generate_example(concept: str, ctx: Context) -> str: """Generate a Python code example for a given concept.""" # Using a system prompt and a user message @@ -280,7 +280,7 @@ See [Client Sampling](/clients/client#llm-sampling) for more details on how clie Access metadata about the current request and client. ```python -@mcp.tool +@mcp.tool() async def request_info(ctx: Context) -> dict: """Return information about the current request.""" return { @@ -300,7 +300,7 @@ async def request_info(ctx: Context) -> dict: #### FastMCP Server and Sessions ```python -@mcp.tool +@mcp.tool() async def advanced_tool(ctx: Context) -> str: """Demonstrate advanced context access.""" # Access the FastMCP server instance @@ -326,7 +326,7 @@ See the [HTTP Requests pattern](/patterns/http-requests) for more details. For web applications, you can access the underlying HTTP request: ```python -@mcp.tool +@mcp.tool() async def handle_web_request(ctx: Context) -> dict: """Access HTTP request information from the Starlette request.""" request = ctx.get_http_request() diff --git a/docs/servers/fastmcp.mdx b/docs/servers/fastmcp.mdx index 13279525d..598d056b6 100644 --- a/docs/servers/fastmcp.mdx +++ b/docs/servers/fastmcp.mdx @@ -47,7 +47,7 @@ FastMCP servers expose several types of components to the client: Tools are functions that the client can call to perform actions or access external systems. ```python -@mcp.tool +@mcp.tool() def multiply(a: float, b: float) -> float: """Multiplies two numbers together.""" return a * b @@ -87,7 +87,7 @@ See [Resources & Templates](/servers/resources) for detailed documentation. Prompts are reusable message templates for guiding the LLM. ```python -@mcp.prompt +@mcp.prompt() def analyze_data(data_points: list[float]) -> str: """Creates a prompt asking for analysis of numerical data.""" formatted_data = ", ".join(str(point) for point in data_points) @@ -106,7 +106,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="MyServer") -@mcp.tool +@mcp.tool() def greet(name: str) -> str: """Greet a user by name.""" return f"Hello, {name}!" @@ -145,7 +145,7 @@ import asyncio main = FastMCP(name="Main") sub = FastMCP(name="Sub") -@sub.tool +@sub.tool() def hello(): return "hi" @@ -216,7 +216,7 @@ def yaml_serializer(data): # Create a server with the custom serializer mcp = FastMCP(name="MyServer", tool_serializer=yaml_serializer) -@mcp.tool +@mcp.tool() def get_config(): """Returns configuration in YAML format.""" return {"api_key": "abc123", "debug": True, "rate_limit": 100} diff --git a/docs/servers/prompts.mdx b/docs/servers/prompts.mdx index 47f19ff9e..6a8f0a62a 100644 --- a/docs/servers/prompts.mdx +++ b/docs/servers/prompts.mdx @@ -33,13 +33,13 @@ from fastmcp.prompts.prompt import Message, PromptMessage, TextContent mcp = FastMCP(name="PromptServer") # Basic prompt returning a string (converted to user message automatically) -@mcp.prompt +@mcp.prompt() def ask_about_topic(topic: str) -> str: """Generates a user message asking for an explanation of a topic.""" return f"Can you please explain the concept of '{topic}'?" # Prompt returning a specific message type -@mcp.prompt +@mcp.prompt() def generate_code_request(language: str, task_description: str) -> PromptMessage: """Generates a user message requesting code generation.""" content = f"Write a {language} function that performs the following task: {task_description}" @@ -69,7 +69,7 @@ FastMCP intelligently handles different return types from your prompt function: ```python from fastmcp.prompts.prompt import Message -@mcp.prompt +@mcp.prompt() def roleplay_scenario(character: str, situation: str) -> list[Message]: """Sets up a roleplaying scenario with initial messages.""" return [ @@ -89,7 +89,7 @@ Type annotations are important for prompts. They: from pydantic import Field from typing import Literal, Optional -@mcp.prompt +@mcp.prompt() def generate_content_request( topic: str = Field(description="The main subject to cover"), format: Literal["blog", "email", "social"] = "blog", @@ -111,7 +111,7 @@ def generate_content_request( Parameters in your function signature are considered **required** unless they have a default value. ```python -@mcp.prompt +@mcp.prompt() def data_analysis_prompt( data_uri: str, # Required - no default value analysis_type: str = "summary", # Optional - has default value @@ -154,13 +154,13 @@ FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`) ```python # Synchronous prompt -@mcp.prompt +@mcp.prompt() def simple_question(question: str) -> str: """Generates a simple question to ask the LLM.""" return f"Question: {question}" # Asynchronous prompt -@mcp.prompt +@mcp.prompt() async def data_based_prompt(data_id: str) -> str: """Generates a prompt based on data that needs to be fetched.""" # In a real scenario, you might fetch data from a database or API @@ -183,7 +183,7 @@ from fastmcp import FastMCP, Context mcp = FastMCP(name="PromptServer") -@mcp.prompt +@mcp.prompt() async def generate_report_request(report_type: str, ctx: Context) -> str: """Generates a request for a report.""" return f"Please create a {report_type} report. Request ID: {ctx.request_id}" @@ -207,7 +207,7 @@ mcp = FastMCP( on_duplicate_prompts="error" # Raise an error if a prompt name is duplicated ) -@mcp.prompt +@mcp.prompt() def greeting(): return "Hello, how can I help you today?" # This registration attempt will raise a ValueError because diff --git a/docs/servers/proxy.mdx b/docs/servers/proxy.mdx index 5a9bffccd..d78d6d694 100644 --- a/docs/servers/proxy.mdx +++ b/docs/servers/proxy.mdx @@ -90,7 +90,7 @@ from fastmcp import FastMCP # Original server original_server = FastMCP(name="Original") -@original_server.tool +@original_server.tool() def tool_a() -> str: return "A" diff --git a/docs/servers/tools.mdx b/docs/servers/tools.mdx index 00fa13252..6b1a54356 100644 --- a/docs/servers/tools.mdx +++ b/docs/servers/tools.mdx @@ -31,7 +31,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="CalculatorServer") -@mcp.tool +@mcp.tool() def add(a: int, b: int) -> int: """Adds two integer numbers together.""" return a + b @@ -61,7 +61,7 @@ Type annotations for parameters are essential for proper tool functionality. The Use standard Python type annotations for parameters: ```python -@mcp.tool +@mcp.tool() def analyze_text( text: str, max_tokens: int = 100, @@ -79,7 +79,7 @@ You can provide additional metadata about parameters using Pydantic's `Field` cl from typing import Annotated from pydantic import Field -@mcp.tool +@mcp.tool() def process_image( image_url: Annotated[str, Field(description="URL of the image to process")], resize: Annotated[bool, Field(description="Whether to resize the image")] = False, @@ -97,7 +97,7 @@ def process_image( You can also use the Field as a default value, though the Annotated approach is preferred: ```python -@mcp.tool +@mcp.tool() def search_database( query: str = Field(description="Search query string"), limit: int = Field(10, description="Maximum number of results", ge=1, le=100) @@ -137,7 +137,7 @@ For additional type annotations not listed here, see the [Parameter Types](#para FastMCP follows Python's standard function parameter conventions. Parameters without default values are required, while those with default values are optional. ```python -@mcp.tool +@mcp.tool() def search_products( query: str, # Required - no default value max_results: int = 10, # Optional - has default value @@ -197,14 +197,14 @@ FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`) ```python # Synchronous tool (suitable for CPU-bound or quick tasks) -@mcp.tool +@mcp.tool() def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float: """Calculate the distance between two coordinates.""" # Implementation... return 42.5 # Asynchronous tool (ideal for I/O-bound operations) -@mcp.tool +@mcp.tool() async def fetch_weather(city: str) -> dict: """Retrieve current weather conditions for a city.""" # Use 'async def' for operations involving network calls, file I/O, etc. @@ -244,7 +244,7 @@ except ImportError: mcp = FastMCP("Image Demo") -@mcp.tool +@mcp.tool() def generate_image(width: int, height: int, color: str) -> Image: """Generates a solid color image.""" # Create image using Pillow @@ -258,7 +258,7 @@ def generate_image(width: int, height: int, color: str) -> Image: # Return using FastMCP's Image helper return Image(data=img_bytes, format="png") -@mcp.tool +@mcp.tool() def do_nothing() -> None: """This tool performs an action but returns no data.""" print("Performing a side effect...") @@ -285,7 +285,7 @@ mcp = FastMCP(name="SecureServer", mask_error_details=True) from fastmcp import FastMCP from fastmcp.exceptions import ToolError -@mcp.tool +@mcp.tool() def divide(a: float, b: float) -> float: """Divide a by b.""" @@ -351,7 +351,7 @@ from fastmcp import FastMCP, Context mcp = FastMCP(name="ContextDemo") -@mcp.tool +@mcp.tool() async def process_data(data_uri: str, ctx: Context) -> dict: """Process data from a resource with progress reporting.""" await ctx.info(f"Processing data from {data_uri}") @@ -396,7 +396,7 @@ FastMCP supports **type coercion** when possible. This means that if a client se The most common parameter types are Python's built-in scalar types: ```python -@mcp.tool +@mcp.tool() def process_values( name: str, # Text data count: int, # Integer numbers @@ -416,7 +416,7 @@ FastMCP supports various date and time types from the `datetime` module: ```python from datetime import datetime, date, timedelta -@mcp.tool +@mcp.tool() def process_date_time( event_date: date, # ISO format date string or date object event_time: datetime, # ISO format datetime string or datetime object @@ -440,7 +440,7 @@ def process_date_time( FastMCP supports all standard Python collection types: ```python -@mcp.tool +@mcp.tool() def analyze_data( values: list[float], # List of numbers properties: dict[str, str], # Dictionary with string keys and values @@ -465,7 +465,7 @@ Collection types can be nested and combined to represent complex data structures For parameters that can accept multiple types or may be omitted: ```python -@mcp.tool +@mcp.tool() def flexible_search( query: str | int, # Can be either string or integer filters: dict[str, str] | None = None, # Optional dictionary @@ -488,7 +488,7 @@ Literals constrain parameters to a specific set of values: ```python from typing import Literal -@mcp.tool +@mcp.tool() def sort_data( data: list[float], order: Literal["ascending", "descending"] = "ascending", @@ -516,7 +516,7 @@ class Color(Enum): GREEN = "green" BLUE = "blue" -@mcp.tool +@mcp.tool() def process_image( image_path: str, color_filter: Color = Color.RED @@ -539,7 +539,7 @@ There are two approaches to handling binary data in tool parameters: #### Bytes ```python -@mcp.tool +@mcp.tool() def process_binary(data: bytes): """Process binary data directly. @@ -563,7 +563,7 @@ FastMCP does not automatically decode base64-encoded strings for bytes parameter from typing import Annotated from pydantic import Field -@mcp.tool +@mcp.tool() def process_image_data( image_data: Annotated[str, Field(description="Base64-encoded image data")] ): @@ -587,7 +587,7 @@ The `Path` type from the `pathlib` module can be used for file system paths: ```python from pathlib import Path -@mcp.tool +@mcp.tool() def process_file(path: Path) -> str: """Process a file at the given path.""" assert isinstance(path, Path) # Path is properly converted @@ -603,7 +603,7 @@ The `UUID` type from the `uuid` module can be used for unique identifiers: ```python import uuid -@mcp.tool +@mcp.tool() def process_item( item_id: uuid.UUID # String UUID or UUID object ) -> str: @@ -628,7 +628,7 @@ class User(BaseModel): age: int | None = None is_active: bool = True -@mcp.tool +@mcp.tool() def create_user(user: User): """Create a new user in the system.""" # The input is automatically validated against the User model @@ -657,7 +657,7 @@ Note that fields can be used *outside* Pydantic models to provide metadata and v from typing import Annotated from pydantic import Field -@mcp.tool +@mcp.tool() def analyze_metrics( # Numbers with range constraints count: Annotated[int, Field(ge=0, le=100)], # 0 <= count <= 100 @@ -682,7 +682,7 @@ def analyze_metrics( You can also use `Field` as a default value, though the `Annotated` approach is preferred: ```python -@mcp.tool +@mcp.tool() def validate_data( # Value constraints age: int = Field(ge=0, lt=120), # 0 <= age < 120 @@ -727,7 +727,7 @@ mcp = FastMCP( on_duplicate_tools="error" ) -@mcp.tool +@mcp.tool() def my_tool(): return "Version 1" # This will now raise a ValueError because 'my_tool' already exists @@ -754,7 +754,7 @@ from fastmcp import FastMCP mcp = FastMCP(name="DynamicToolServer") -@mcp.tool +@mcp.tool() def calculate_sum(a: int, b: int) -> int: """Add two numbers together.""" return a + b