Tools & MCP
Wrap any Go function as a tool with auto-generated JSON Schema. Discover and consume MCP servers. Expose your tools as MCP services. Parallel DAG execution for independent tools.
Overview
The Beluga AI tool system provides a unified abstraction for integrating external capabilities into agents.
At its core, the FuncTool wrapper lets you turn any Go function into an agent-callable tool
with automatically generated JSON Schema for parameter validation. The system supports both local tools
and remote tools accessed via the Model Context Protocol (MCP).
MCP integration is bidirectional: your agents can consume tools from any MCP-compatible server, and you can expose your own Go tools as MCP services for other systems to use. The Streamable HTTP transport provides efficient communication with session management and OAuth support.
For performance-critical workloads, the parallel DAG executor automatically identifies independent tool calls and runs them concurrently. Combined with the registry pattern for runtime tool discovery and middleware for cross-cutting concerns like auth and rate limiting, the tool system provides a complete foundation for building capable AI agents.
Capabilities
FuncTool
Wrap any Go function as an agent-callable tool with automatic JSON Schema generation from struct tags. The framework introspects function signatures to produce the parameter schema that LLMs use to invoke tools correctly.
searchTool := tool.NewFuncTool("search", searchFunc) MCP Client
Discover and consume tools, resources, and prompts from any MCP-compatible server. The client uses Streamable HTTP transport with automatic session management, reconnection logic, and OAuth authentication for secured endpoints.
MCP Server
Expose your Go tools, resources, and prompts as a standards-compliant MCP server. Any MCP client -- including Claude Desktop, Cursor, and other AI editors -- can connect and use your tools directly.
MCP Registry
Search and discover MCP servers from public registries. Browse available tools by category, filter by capability, and connect to servers on demand. Enables dynamic tool discovery at runtime.
Tool Registry
The standard Beluga registry pattern for tools: Add, Get, List,
and Remove at runtime. Agents can dynamically add or remove tools based on context,
user permissions, or task requirements.
Parallel DAG Execution
When an agent requests multiple tool calls, the executor builds a dependency graph and runs independent tools in parallel using goroutines. Dependent tools wait for their prerequisites. This dramatically reduces latency for multi-tool operations.
Built-in Tools
Common tools included out of the box: Calculator for math expressions, HTTP client for API calls,
Shell executor for system commands (sandboxed), and Code sandbox for safe code execution.
All follow the same Tool interface and can be extended or replaced.
Middleware and Hooks
Apply cross-cutting concerns to any tool via middleware: authentication, rate limiting, timeout enforcement,
and logging. Hooks provide fine-grained lifecycle control with BeforeExecute,
AfterExecute, and OnError callbacks.
Architecture
Full Example
Create tools from Go functions, connect to an MCP server, and wire everything into an agent:
package main
import (
"context"
"fmt"
"log"
"github.com/lookatitude/beluga-ai/agent"
"github.com/lookatitude/beluga-ai/llm"
"github.com/lookatitude/beluga-ai/tool"
"github.com/lookatitude/beluga-ai/tool/mcp"
)
// Define a search function
func searchWeb(ctx context.Context, params struct {
Query string `json:"query" description:"Search query"`
Limit int `json:"limit" description:"Max results" default:"5"`
}) ([]SearchResult, error) {
// ... implementation
return results, nil
}
func main() {
ctx := context.Background()
// Wrap Go function as a tool with auto JSON Schema
searchTool := tool.NewFuncTool("search_web", searchWeb,
tool.WithDescription("Search the web for information"),
)
// Connect to an MCP server for additional tools
mcpClient, err := mcp.NewClient(ctx, "https://tools.example.com/mcp",
mcp.WithOAuth("client-id", "client-secret"),
mcp.WithSessionManagement(true),
)
if err != nil {
log.Fatal(err)
}
defer mcpClient.Close()
// Discover tools from MCP server
mcpTools, _ := mcpClient.ListTools(ctx)
// Create tool registry and add all tools
registry := tool.NewRegistry()
registry.Add(searchTool)
for _, t := range mcpTools {
registry.Add(t)
}
// Create LLM and agent with tools
model, _ := llm.New("openai", llm.WithModel("gpt-4o"))
myAgent, _ := agent.New("research-agent",
agent.WithModel(model),
agent.WithTools(registry.List()...),
agent.WithToolHooks(tool.Hooks{
BeforeExecute: func(ctx context.Context, name string, input any) error {
fmt.Printf("Calling tool: %s\n", name)
return nil
},
AfterExecute: func(ctx context.Context, name string, result any, err error) {
fmt.Printf("Tool %s completed\n", name)
},
}),
)
// Run the agent - parallel tool calls execute concurrently
result, err := myAgent.Run(ctx, "Research the latest AI frameworks and compare them")
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}