> ## Documentation Index
> Fetch the complete documentation index at: https://docs.golf.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Component specification

> Learn how to define GolfMCP components (tools, resources, prompts).

### 1. Description

The primary source for a component's description is its **module-level docstring**.

```python theme={null}
# tools/my_tool.py
"""This is the description for 'my_tool'.
It can span multiple lines and will be used to generate tool description.
"""

# ... rest of the tool code
```

* This docstring is **mandatory**. If missing, the build will fail.
* The function docstring of the exported function is generally ignored if a module docstring is present. It might be used as a fallback if the module docstring is missing, but relying on this is not recommended.

### 2. Entry function (`export`)

GolfMCP needs to know which function within your Python file is the main entry point for the component. This is primarily done by assigning the function to a module-level variable named `export`.

```python theme={null}
# tools/calculator.py
"""A simple calculator tool."""

async def add_numbers(a: int, b: int) -> int:
    return a + b

async def subtract_numbers(a: int, b: int) -> int:
    return a - b

# 'add_numbers' is the designated tool function
export = add_numbers
```

If an `export` variable is not found, GolfMCP build will fail.

### 3. Function signature requirements

The signature of your exported function must adhere to certain rules:

* **Tools:**
  * Parameters **must** have type hints (e.g., `param: str`, `count: int`).
  * The return value **must** have a type hint (e.g., `-> str`, `-> Dict[str, Any]`).
  * Can be `async def` or `def`.
* **Resources:**
  * If defined as a function, it follows similar rules to tools.
  * Resource functions typically do not take arguments unless they are part of a resource template (where arguments come from URI path parameters).
  * The URI for the resource is defined by a module-level variable `resource_uri: str`.
  * Example: `resource_uri = "data://config"`
  * Can also be a simple module-level constant (JSON-serializable).
* **Prompts:**
  * The function should return either a `str` (which becomes a single user message) or a `List[Dict]`.
  * Parameters should have type hints.

**Pydantic for Input/Output Schemas (Tools):**

For tools, Pydantic `BaseModel` is highly recommended for defining complex input argument structures and output shapes, enabling clear schemas and validation.

* **Input Parameters & Schema:**
  Tool inputs are **always** defined by the parameters of your exported tool function. These parameters **must** have type hints and descriptions.

  * **Direct Function Parameters:** You define inputs directly in the tool function's signature.
    ```python theme={null}
    # tools/hello.py
    """Hello World tool example."""
    from typing import Annotated
    from pydantic import BaseModel, Field

    class Output(BaseModel):
        message: str

    async def hello(
        name: Annotated[str, Field(description="The name of the person to greet")] = "World",
        greeting: Annotated[str, Field(description="The greeting phrase to use")] = "Hello"
    ) -> Output:
        # 'name' and 'greeting' are direct input parameters.
        # Golf's parser creates an inputSchema in the manifest based on these.
        return Output(message=f"{greeting}, {name}!")
    export = hello
    ```

* **Output Structure & Schema:**
  The structure of your tool's output should be defined by its return type hint. It is strongly recommended to use a Pydantic `BaseModel` for this return type to ensure a clear and validated output schema.

  ```python theme={null}
  # tools/user_profile_tool.py
  """Tool to fetch user profile information."""
  from pydantic import BaseModel
  from typing import Optional

  class Output(BaseModel): # Explicit Pydantic model for the output
      user_id: int
      username: str
      email: Optional[str]
      is_active: bool

  async def fetch_user_profile(user_id: int) -> Output:
      # We use the 'Output' return type hint for its
      # runtime behavior and schema exposure to clients.
      return Output(
          user_id=user_id, 
          username="example_user", 
          email="user@example.com", 
          is_active=True
      )

  export = fetch_user_profile
  ```

### 4. Parameter annotations (recommended)

While simple type hints are sufficient, using `Annotated` with Pydantic `Field` provides rich descriptions and validation that significantly improves how AI agents understand and use your tools.

#### Basic parameter annotations

```python theme={null}
from typing import Annotated
from pydantic import BaseModel, Field

async def hello(
    name: Annotated[str, Field(description="The name of the person to greet")] = "World",
    greeting: Annotated[str, Field(description="The greeting phrase to use")] = "Hello"
) -> Output:
    """Say hello to the given name."""
    return Output(message=f"{greeting}, {name}!")
```

#### Parameter validation

Field annotations support various validation constraints:

```python theme={null}
from typing import Annotated, Optional
from pydantic import BaseModel, Field

class ChargeOutput(BaseModel):
    success: bool
    charge_id: str
    message: str

async def charge_payment(
    # Numeric constraints
    amount: Annotated[float, Field(
        description="Amount to charge in USD",
        gt=0,        # Must be greater than 0
        le=10000     # Maximum charge limit
    )],
    
    # Pattern validation
    card_token: Annotated[str, Field(
        description="Tokenized payment card identifier",
        pattern=r"^tok_[a-zA-Z0-9]+$"  # Regex validation
    )],
    
    # String length constraints
    description: Annotated[str, Field(
        description="Optional payment description",
        max_length=200,
        min_length=0
    )] = "",
    
    # Optional parameters with constraints
    customer_email: Annotated[Optional[str], Field(
        description="Customer's email address",
        pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$",
        default=None
    )] = None
) -> ChargeOutput:
    """Process a payment charge with validation."""
    # Implementation here
    pass
```

### 5. Tool annotations (MCP behavioral hints)

Tool annotations provide behavioral hints about your tools to MCP clients, following the official MCP specification. These hints help clients understand how to interact with your tools safely and efficiently.

#### Overview

Add an `annotations` dictionary at the module level to specify behavioral hints:

```python theme={null}
"""Delete file tool."""

from typing import Annotated
from pydantic import BaseModel, Field

# Tool annotations - MCP behavioral hints
annotations = {
    "readOnlyHint": False,      # Tool modifies state
    "destructiveHint": True,     # Tool may delete/mutate data irreversibly  
    "idempotentHint": False,     # Repeated calls have side effects
    "openWorldHint": False       # Tool operates on local state only
}

class Output(BaseModel):
    success: bool
    message: str

async def delete_file(
    path: Annotated[str, Field(description="Path to file to delete")]
) -> Output:
    """Delete a file from the filesystem."""
    return Output(success=True, message="File deleted")

export = delete_file
```

#### Supported annotation types

<ResponseField name="readOnlyHint" type="boolean">
  `true` → tool cannot change state (pure "GET-style" call)

  **Note**: When `true`, other hints are ignored by MCP clients.
</ResponseField>

<ResponseField name="destructiveHint" type="boolean">
  `true` → tool may delete or irreversibly mutate data

  Only meaningful when `readOnlyHint` is `false`.
</ResponseField>

<ResponseField name="idempotentHint" type="boolean">
  `true` → repeated calls with identical arguments are safe and side-effect-free

  Helps MCP clients add caching and deduplication.
</ResponseField>

<ResponseField name="openWorldHint" type="boolean">
  `true` → behavior depends on external mutable state (e.g., live web, clock)

  Signals lower reproducibility to MCP clients.
</ResponseField>

#### Common patterns

**Read-only tool:**

```python theme={null}
# Tool that only reads data
annotations = {
    "readOnlyHint": True  # Other hints ignored when this is true
}
```

**Web search tool:**

```python theme={null}
# Tool that searches the internet
annotations = {
    "readOnlyHint": True,        # Doesn't modify local state
    "openWorldHint": True        # Depends on external web services
}
```

**Idempotent tool:**

```python theme={null}
# Tool safe to retry
annotations = {
    "readOnlyHint": False,
    "destructiveHint": False,
    "idempotentHint": True,      # Safe to call multiple times
    "openWorldHint": False
}
```

**File operations tool:**

```python theme={null}
# Tool that modifies files
annotations = {
    "readOnlyHint": False,
    "destructiveHint": True,     # May delete files
    "idempotentHint": False,     # Multiple calls may have different effects
    "openWorldHint": False       # Works on local filesystem
}
```
