# How to Create and Integrate Custom Tools with ToolGroup in Embabel Agents

> Learn to create custom tools for Embabel agents. Define tool groups, annotate classes and methods, and register as Spring components for seamless integration.

- Repository: [Embabel/embabel-agent](https://github.com/embabel/embabel-agent)
- Tags: how-to-guide
- Published: 2026-08-08

---

**Create custom tools in Embabel by defining a group enum, annotating your tool class with `@ToolGroup`, marking callable methods with `@Action`, and registering the class as a Spring component for automatic discovery by the `ToolGroupResolver`.**

Embabel agents organize capabilities into logical tool groups that planners use to select specific function sets such as Web, File-System, or MCP. To extend an agent's functionality, you must create custom tools and assign them to groups using the framework's annotation-based registration system. This guide walks through the exact implementation pattern used in the `embabel/embabel-agent` repository.

## Understanding ToolGroup Architecture

Embabel uses the **ToolGroup** abstraction to categorize related capabilities. A tool group is defined by the `@ToolGroup` annotation and resolved at runtime by the `ToolGroupResolver` class. According to the source code in [`embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/config/spring/ToolGroupsConfiguration.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/config/spring/ToolGroupsConfiguration.kt), the resolver scans all Spring beans carrying the `@ToolGroup` annotation and builds a mapping from role strings to lists of executable tools.

The annotation definitions reside in [`embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/annotations.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/annotations.kt) (lines 43-45), where `@ToolGroup` accepts a `role` parameter that serves as the group's unique identifier. This role string links your custom implementation to agent actions that request specific tool sets.

## Step-by-Step Implementation Guide

Follow this exact sequence to register a custom tool with a new group in Embabel.

### 1. Define the Tool Group Enum

Create a Kotlin enum that holds logical group names. These values reference the `role` attribute in subsequent annotations.

```kotlin
package com.example.agent.tools

/** Logical groups referenced by @ToolGroup and @Action annotations */
enum class MyToolGroups(val role: String) {
    DATABASE("db"),
    CLOUD("cloud"),
    ANALYTICS("analytics")
}

```

### 2. Annotate the Tool Class with @ToolGroup

Apply `@ToolGroup` to the class implementation, specifying the role string that identifies the group. The class must also carry Spring's `@Component` annotation (or `@EmbabelComponent`) to enable classpath scanning.

```kotlin
package com.example.agent.tools

import com.embabel.agent.api.annotation.ToolGroup
import com.embabel.agent.api.annotation.Action
import org.springframework.stereotype.Component

@ToolGroup(role = MyToolGroups.CLOUD.role)
@Component
class CloudTool {
    // Tool methods will be defined here
}

```

### 3. Expose Callable Methods with @Action

Each public function that the LLM can invoke requires the `@Action` annotation. You can optionally reinforce group membership using the `toolGroups` attribute, or override the class-level group for specific methods.

```kotlin
@Action(
    description = "Starts a VM in the cloud",
    toolGroups = [MyToolGroups.CLOUD.role]
)
fun startVm(instanceId: String): String {
    // Implementation logic
    return "VM $instanceId started"
}

@Action(
    description = "Stops a VM in the cloud"
)
fun stopVm(instanceId: String): String {
    return "VM $instanceId stopped"
}

```

### 4. Register with Spring Context

Ensure your class is discoverable by Spring's component scan. The framework automatically detects beans annotated with both `@Component` and `@ToolGroup`, as implemented in [`ToolGroupsConfiguration.kt`](https://github.com/embabel/embabel-agent/blob/main/ToolGroupsConfiguration.kt).

### 5. Reference the Group in Agent Definitions

Actions or agents request tool groups via the `toolGroups` attribute. When the planner generates execution plans, it filters available tools to include only those belonging to the specified groups.

```kotlin
package com.example.agent

import com.embabel.agent.api.annotation.Agent
import com.embabel.agent.api.annotation.Action
import com.example.agent.tools.MyToolGroups

@Agent(
    name = "cloud-agent",
    description = "Agent that manages cloud resources",
    version = "1.0.0"
)
class CloudAgent {

    @Action(
        description = "Provision a new VM",
        toolGroups = [MyToolGroups.CLOUD.role]
    )
    fun provisionVm(size: String): String {
        // Planner will select tools from the CLOUD group
        return "VM provisioned with size $size"
    }
}

```

## Testing Custom Tool Group Integration

Verify that your custom group resolves correctly by writing unit tests against the `ToolGroupResolver`. The test suite in [`embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/config/spring/ToolGroupsConfigurationTest.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/config/spring/ToolGroupsConfigurationTest.kt) demonstrates the validation pattern for built-in groups.

```kotlin
package com.example.agent.tests

import com.embabel.agent.spi.ToolGroupResolver
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import kotlin.test.assertTrue

class CloudToolGroupTest @Autowired constructor(
    private val resolver: ToolGroupResolver
) {

    @Test
    fun `cloud group contains CloudTool methods`() {
        val tools = resolver.resolveTools("cloud")
        assertTrue(tools.any { it.name == "startVm" })
        assertTrue(tools.any { it.name == "stopVm" })
    }
}

```

## Summary

- **Tool groups** organize related capabilities using the `@ToolGroup(role = "group-name")` annotation defined in [`annotations.kt`](https://github.com/embabel/embabel-agent/blob/main/annotations.kt) (lines 43-45).
- **Custom tools** must be Spring components (`@Component` or `@EmbabelComponent`) to enable automatic discovery by `ToolGroupsConfiguration`.
- **Method exposure** requires `@Action` annotations on public functions, with optional `toolGroups` attributes to specify membership.
- **Runtime resolution** is handled by `ToolGroupResolver`, which maps role strings to executable tool instances.
- **Testing** should verify group registration using the resolver interface, following patterns in [`ToolGroupsConfigurationTest.kt`](https://github.com/embabel/embabel-agent/blob/main/ToolGroupsConfigurationTest.kt).

## Frequently Asked Questions

### What is the difference between @ToolGroup and the toolGroups attribute in @Action?

`@ToolGroup` is a class-level annotation that assigns an entire tool class to a specific group, as defined in [`embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/annotations.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/annotations.kt). The `toolGroups` attribute within `@Action` allows method-level override or reinforcement of group membership. Use the class-level annotation for cohesion, and the method attribute when specific actions need to declare or restrict group access.

### Can a single tool class belong to multiple tool groups?

No, a class can only carry one `@ToolGroup` annotation with a single role. To expose the same functionality across multiple groups, create separate wrapper classes for each group, each annotated with their respective `@ToolGroup` role, or use the `toolGroups` attribute in individual `@Action` methods to override the default group assignment.

### How does the ToolGroupResolver discover custom tools at runtime?

The resolver scans the Spring application context for beans annotated with `@ToolGroup`, as configured in [`embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/config/spring/ToolGroupsConfiguration.kt`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/config/spring/ToolGroupsConfiguration.kt). It extracts the role string from each bean's annotation and populates a map that the planner queries when resolving tool requests for specific groups.

### Where are built-in tool groups like WEB or FILE_SYSTEM defined?

Built-in groups are typically defined in enums such as `CoreToolGroups`, referenced in the README.md examples showing usage like `@Action(toolGroups = {CoreToolGroups.WEB})`. These constants map to role strings that the `ToolGroupResolver` recognizes, allowing consistent group references across the `embabel/embabel-agent` codebase.