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

# Developing Mirobody Tools

> Write a Python function or Service class and the engine serves it as an MCP tool, to the agent and to every MCP client.

export const OssSource = ({path, lang = "en"}) => {
  const href = "https://github.com/thetahealth/mirobody/blob/c1aae297b4f3fad5cb87c5fc5bffc5163f7758c9/" + path;
  return <p className="text-sm text-gray-500 dark:text-gray-400">
      {lang === "zh" ? "对应 mirobody " : "For mirobody "}
      <code>1.5.3</code>
      {lang === "zh" ? " · 源文件 " : " · source "}
      <a href={href}>
        <code>{path}</code>
      </a>
    </p>;
};

<OssSource path="mirobody/agent/tools/README.md" lang="en" />

Mirobody follows a **"Tools First"** philosophy. You write standard Python code, and the system automatically converts it into MCP (Model Context Protocol) tools for AI agents.

<h2 id="-tool-discovery">
  🔍 Tool Discovery
</h2>

Tool directories are configured by `MCP_TOOL_DIRS` in `config.{env}.yaml`. The defaults:

1. **Built-in tools**: `mirobody/agent/tools/` (this directory) — the whole shipped tool surface: terminology (② Translate), health records, genetics.

**Place your own tools in your own directory and add it to `MCP_TOOL_DIRS`** — the list is ordinary config, so a deployment can extend it without touching the package:

```yaml theme={null}
# config.{env}.yaml
MCP_TOOL_DIRS:
  - mirobody/agent/tools
  - my_tools          # yours, relative to the working directory
```

**Or ship them as a package.** A distribution that declares a `mirobody.tools`
entry point pointing at a module of tool classes is loaded at boot the moment
it is `pip install`ed — same registry, same schema generation, served over
`/mcp` and handed to the agent like the built-ins:

```toml theme={null}
[project.entry-points."mirobody.tools"]
labs = "my_plugin.tools"
```

`examples/mirobody_example_plugin/` is a complete example.

<h3 id="discovery-rules">
  Discovery Rules
</h3>

1. **File Location**: Must be a `.py` file inside a configured tool directory.
2. **Ignored Files**: Files starting with `_` (e.g., `_utils.py`) are ignored.
3. **Eligible Code**:
   * **Functions**: Top-level functions are automatically registered.
   * **Classes**: Must end with `Service` (e.g., `FinanceService`) to be registered.

<h3 id="conditional-registration-_enabled">
  Conditional Registration (`_enabled`)
</h3>

A Service may define a static `_enabled() -> bool`; returning `False` **skips the whole class** (none of its methods register). Use it to gate optional integrations on config (e.g. an API key).

<h2 id="-implementation-guide">
  📝 Implementation Guide
</h2>

Your Python code *is* the definition. No separate configuration or JSON schema is needed.

<h3 id="1-type-hints-required">
  1. Type Hints (Required)
</h3>

Mirobody uses Python type hints (`str`, `int`, `bool`, `float`) to generate the tool's input schema.

* **Fundamental Types**: `str`, `int`, `float`, `bool`
* **Complex Types**: `list[str]`, `dict` (parsed as generic object)

<h3 id="2-docstrings-required">
  2. Docstrings (Required)
</h3>

Docstrings are parsed to provide descriptions to the AI. We recommend the standard format:

```python theme={null}
def my_tool(arg1: str):
    """
    Brief description of what the tool does.

    Args:
        arg1: Description of the argument.
  
    Returns:
        Description of the return value.
    """
```

<h3 id="3-authentication--context">
  3. Authentication & Context
</h3>

If your tool needs user information (like a User ID from a JWT), add a `user_info` parameter.

* **Injection**: Mirobody automatically injects this value; the AI agent does *not* see or provide it.
* **Structure**: `{"user_id": "...", "success": True}`.

<h2 id="-examples">
  💡 Examples
</h2>

<h3 id="basic-function-tool">
  Basic Function Tool
</h3>

Save this as `my_tools/calculator.py`:

```python theme={null}
def add_numbers(a: float, b: float) -> dict:
    """
    Adds two numbers together.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        A dictionary containing the sum.
    """
    return {"result": a + b}
```

<h3 id="advanced-service-class">
  Advanced Service Class
</h3>

Save this as `my_tools/stocks.py`:

```python theme={null}
from typing import Dict, Any

class StockService:
    """
    Service for retrieving stock market data.
    """

    def get_stock_price(self, ticker: str, user_info: dict) -> Dict[str, Any]:
        """
        Gets the current price of a stock.

        Args:
            ticker: The stock ticker symbol (e.g., AAPL).
    
        Returns:
            The current stock price.
        """
        # user_info is automatically injected
        user_id = user_info.get("user_id")
        print(f"User {user_id} requested price for {ticker}")

        return {
            "ticker": ticker,
            "price": 150.00,
            "currency": "USD"
        }
```

<h2 id="-reference">
  🧩 Reference
</h2>

For the core implementation details of how tools are parsed, refer to:
[`mirobody/mcp/tool.py`](https://github.com/thetahealth/mirobody/blob/c1aae297b4f3fad5cb87c5fc5bffc5163f7758c9/mirobody/mcp/tool.py)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.