Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 5

Crafting Effective Tool Descriptions for LLMs

Recommended resources

Introduction

Welcome back! In our last lesson, you successfully verified that your get_order_details tool is correctly exposed via the /mcp endpoint using the MCP Inspector. You saw how fastapi_mcp automatically translates your operation_id, function signature, and Pydantic response_model into a machine-readable tool definition.

Today, we'll focus on the most crucial element for making that tool truly usable by an AI: writing a high-quality description. This is where you move from just exposing a technical interface to actively guiding the Large Language Model (LLM). A good description is the primary piece of information the model uses to understand what your tool does, when to use it, and why it's the right choice for a given task. This is, in essence, the prompt engineering of tool building.


1. The Critical Role of a Tool's Description

Think of the components we've used so far:

  • operation_id: This is the tool's unique name.
  • Function parameters: This is the tool's input schema.
  • response_model: This is the tool's output schema.

These are the technical specifications. The description is the natural language "docstring" for the AI. Without a clear description, the LLM has to guess the tool's purpose based only on its name, which is unreliable and leads to poor performance.

The article we are following makes this point very clearly.

How To Build a MCP Server with FastAPI (FastAPI-MCP)

Let's revisit our main project guide, 'How To Build a MCP Server with FastAPI (FastAPI-MCP)', to see its explicit guidance on the importance of the description parameter.

Please read the first paragraph of 'Step 3: Add and Expose Tools'. It directly states that the quality of the description is the main factor the LLM uses to select the right tool.

This is the bridge between the user's intent ("What's the status of my order?") and your API's capability (get_order_details).


2. Principles of Effective Tool Descriptions

Writing for an LLM is like writing documentation for a new team member: you must be clear, explicit, and avoid ambiguity. A poorly described tool will be ignored or used incorrectly.

For a deeper dive into best practices, the official MCP documentation offers excellent principles.

Writing Effective Tools for Agents

The article 'Writing Effective Tools for Agents' provides expert guidance on how to craft descriptions that maximize tool performance.

Please read the sections 'Prompt-Engineering Your Tool Descriptions' and 'Practical Guidance'. Focus on the advice to think like you're explaining the tool to a new hire, the need to make implicit context explicit, and the pitfalls to avoid, such as 'Neglecting tool description quality'.

Based on these principles, here are the key characteristics of a high-quality tool description:

  • Be Action-Oriented: Start with a strong verb that describes the primary action (e.g., "Fetches," "Retrieves," "Calculates," "Updates").
  • Be Specific: Clearly state what the tool does and what entity it operates on. Instead of "Gets order data," use "Fetches detailed information for a specific order."
  • Clarify Inputs: Mention what key inputs are required. For example, "...by its unique ID" or "...using the customer's email address."
  • Hint at the Output: Briefly describe what kind of information is returned. For example, "...returning the order status, total amount, and currency."
  • Be Concise: While clarity is key, descriptions contribute to the token count of the prompt sent to the LLM. Unnecessarily long descriptions can increase costs and push other information out of the model's limited context window.

This short video explains how the name, arguments, and description are all packaged together and sent to the LLM, highlighting why each part is essential.

How LLM Tool Calling Works

The video 'How LLM Tool Calling Works' provides a concise overview of the components that define a tool for an LLM.

Watch from 03:28 to 04:10 to see the four key pieces of information given to an LLM about a tool: name, arguments, response shape, and description. Then, watch from 08:25 to 11:17, where the presenter shows how this is formalized in an API call, reinforcing the structure we are building in FastAPI.


3. Hands-On: Adding a Description to Your Tool

Now, let's apply these principles to your code. You will add the description parameter to the @app.get decorator for your get_order_details endpoint.

Open your main.py file and update the get_order_details endpoint as follows:




# main.py

@app.get(
    "/orders/{order_id}",
    operation_id="get_order_details",
    description="Fetches detailed information for a specific order by its ID, returning status, amount, and currency.", # Add this line
    tags=["orders"],
    response_model=Order,
)
async def get_order_details(order_id: str) -> Dict[str, Any]:



    # ... function body remains the same

Notice how this description follows our principles:

  • Action-oriented: "Fetches..."
  • Specific: "...detailed information for a specific order..."
  • Clarifies Input: "...by its ID..."
  • Hints at Output: "...returning status, amount, and currency."

After saving the file, you can restart your server and use the MCP Inspector again. When you connect and view the get_order_details tool, you will now see your new description prominently displayed. This confirms the LLM will receive this crucial context.


4. Going Deeper: Describing Tool Parameters

To give the LLM even more clarity, you can also add descriptions to the individual parameters of your tool. This is especially useful for clarifying formats, constraints, or the purpose of a specific input. In FastAPI, you achieve this using the Annotated type hint.

The following video demonstrates this technique effectively.

Python + MCP: Building MCP servers with FastMCP

In 'Python + MCP: Building MCP servers with FastMCP', the presenter shows how to add detailed descriptions to individual function arguments, which provides the LLM with fine-grained context.

Watch from 23:36 to 26:37. Pay close attention to how annotated is used to add a description to each argument, such as explaining the expected format for a date. This is the exact technique we'll apply.

Let's apply this to our order_id parameter. Update your imports and the function signature in main.py:




# main.py
import os
from typing import Optional, Dict, Any, Annotated # Add Annotated
from fastapi import FastAPI, Depends, HTTPException, Request, Path # Add Path



# ... other imports




# ... app setup and Pydantic models




# --- Tool Endpoints ---
@app.get(
    "/orders/{order_id}",
    operation_id="get_order_details",
    description="Fetches detailed information for a specific order by its ID, returning status, amount, and currency.",
    tags=["orders"],
    response_model=Order,
)
async def get_order_details(
    order_id: Annotated[str, Path(description="The unique identifier of the order, typically starting with 'ORD'. For example: 'ORD12345'.")]
) -> Dict[str, Any]:
    """
    Example endpoint to simulate fetching order data.
    In a real application, this would query a database.
    """



    # Placeholder data
    if order_id == "ORD12345":
        return {
            "order_id": order_id,
            "customer_id": 101,
            "status": "shipped",
            "total_amount": 199.99,
            "currency": "USD",
        }
    raise HTTPException(status_code=404, detail="Order not found")




# ... rest of the file

Here, we've used Annotated with fastapi.Path to attach a description directly to the order_id path parameter. This tells the LLM not just that an order_id is a string, but also gives it a hint about the expected format and an example. This significantly reduces the chance of the model attempting to call the tool with an invalid input.


Conclusion

In this lesson, you've moved beyond the technical setup and into the art of guiding an AI. You've learned that the description field is not just metadata but a critical instruction that dictates how and when your tool will be used.

Key Takeaways:

  • A tool's description is the most important factor for an LLM to decide which tool to use.
  • Effective descriptions are action-oriented, specific, clarify inputs, and are concise.
  • You can, and should, add descriptions to individual tool parameters using Annotated for even greater precision and reliability.

In our next lesson, we will continue building on this foundation. You'll add a second tool, get_customer_profile, and learn how to use the include_operations list in FastApiMCP to explicitly manage which of your API endpoints are exposed as tools. This will be our first step toward building a curated, scalable toolset.