Documentation
¶
Overview ¶
Package registry provides a thread-safe, ordered collection of LLM tools for use in agent dispatch loops.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds a named collection of model.Tool objects for an agent loop.
Storing model.Tool (the minimal interface) keeps the registry decoupled from the execution layer. Callers that need to execute a tool type-assert to handler.ExecutableTool at dispatch time:
tool, ok := reg.ByName(call.Name) exec, ok := tool.(handler.ExecutableTool) result, err := exec.Execute(ctx, call.Arguments)
Registry is safe for concurrent use: reads (All, ByName, Names) hold a read lock; writes (Add) hold a write lock.
Typical usage:
reg := registry.New(myTool) req.Tools = reg.All() tool, ok := reg.ByName(call.Name)
func New ¶
New creates a Registry pre-populated with the given tools.
Example ¶
package main
import (
"context"
"fmt"
"github.com/v8tix/mcp-toolkit/v2/handler"
"github.com/v8tix/mcp-toolkit/v2/registry"
)
type greetArgs struct {
Name string `json:"name" description:"Name to greet."`
}
func greetTool(name, desc string) handler.ExecutableTool {
return handler.NewTool(name, desc,
func(_ context.Context, in greetArgs) (string, error) {
return "hello, " + in.Name, nil
},
)
}
func main() {
reg := registry.New(
greetTool("greet", "Greet someone."),
greetTool("farewell", "Say goodbye."),
)
fmt.Println(reg.Names())
}
Output: [greet farewell]
func (*Registry) Add ¶
Add registers one or more tools and returns the Registry for method chaining. Panics if any tool's Definition().Name is empty — an empty name is always a programmer error: the LLM API rejects tools without a name, and a nameless tool cannot be dispatched by ByName.
Example ¶
package main
import (
"context"
"fmt"
"github.com/v8tix/mcp-toolkit/v2/handler"
"github.com/v8tix/mcp-toolkit/v2/registry"
)
type greetArgs struct {
Name string `json:"name" description:"Name to greet."`
}
func greetTool(name, desc string) handler.ExecutableTool {
return handler.NewTool(name, desc,
func(_ context.Context, in greetArgs) (string, error) {
return "hello, " + in.Name, nil
},
)
}
func main() {
reg := registry.New(greetTool("greet", "Greet someone."))
reg.Add(greetTool("farewell", "Say goodbye."))
fmt.Println(reg.Names())
}
Output: [greet farewell]
func (*Registry) All ¶
All returns the tool definitions of every registered tool in insertion order. Pass this slice directly to the tools field of an LLM chat-completion request. Returns a freshly allocated slice; mutations do not affect the registry.
func (*Registry) ByName ¶
ByName looks up a tool by its name and returns the model.Tool. Returns the tool and true if found, nil and false otherwise. Callers that need execution should type-assert to handler.ExecutableTool.
Example ¶
package main
import (
"context"
"fmt"
"github.com/v8tix/mcp-toolkit/v2/handler"
"github.com/v8tix/mcp-toolkit/v2/registry"
)
type greetArgs struct {
Name string `json:"name" description:"Name to greet."`
}
func greetTool(name, desc string) handler.ExecutableTool {
return handler.NewTool(name, desc,
func(_ context.Context, in greetArgs) (string, error) {
return "hello, " + in.Name, nil
},
)
}
func main() {
reg := registry.New(greetTool("greet", "Greet someone."))
t, ok := reg.ByName("greet")
fmt.Println(ok)
fmt.Println(t.Definition().Name)
}
Output: true greet
func (*Registry) Filter ¶
Filter returns a new Registry containing only the tools for which fn returns true. The original registry is not modified.
exec := reg.Filter(func(t model.Tool) bool {
_, ok := t.(handler.ExecutableTool)
return ok
})
Example ¶
package main
import (
"context"
"fmt"
"strings"
"github.com/v8tix/mcp-toolkit/v2/handler"
"github.com/v8tix/mcp-toolkit/v2/model"
"github.com/v8tix/mcp-toolkit/v2/registry"
)
type greetArgs struct {
Name string `json:"name" description:"Name to greet."`
}
func greetTool(name, desc string) handler.ExecutableTool {
return handler.NewTool(name, desc,
func(_ context.Context, in greetArgs) (string, error) {
return "hello, " + in.Name, nil
},
)
}
func main() {
reg := registry.New(
greetTool("public_greet", "Public."),
greetTool("internal_sync", "Internal."),
greetTool("public_farewell", "Public."),
)
public := reg.Filter(func(t model.Tool) bool {
return !strings.HasPrefix(t.Definition().Name, "internal_")
})
fmt.Println(public.Names())
fmt.Println(reg.Names()) // original unchanged
}
Output: [public_greet public_farewell] [public_greet internal_sync public_farewell]
func (*Registry) Remove ¶
Remove removes the tool with the given name from the registry. Returns true if a tool was removed, false if no tool had that name.
Example ¶
package main
import (
"context"
"fmt"
"github.com/v8tix/mcp-toolkit/v2/handler"
"github.com/v8tix/mcp-toolkit/v2/registry"
)
type greetArgs struct {
Name string `json:"name" description:"Name to greet."`
}
func greetTool(name, desc string) handler.ExecutableTool {
return handler.NewTool(name, desc,
func(_ context.Context, in greetArgs) (string, error) {
return "hello, " + in.Name, nil
},
)
}
func main() {
reg := registry.New(
greetTool("greet", "Greet someone."),
greetTool("farewell", "Say goodbye."),
)
removed := reg.Remove("greet")
fmt.Println(removed)
fmt.Println(reg.Names())
}
Output: true [farewell]