1. Installation
go get github.com/jonwraymond/toolcompose@latest
import (
"fmt"
"log"
"github.com/jonwraymond/toolcompose/set"
"github.com/jonwraymond/toolfoundation/adapter"
)
tools := []*adapter.CanonicalTool{
{Namespace: "github", Name: "create_issue", Tags: []string{"issues"}, InputSchema: &adapter.JSONSchema{Type: "object"}},
{Namespace: "github", Name: "add_labels", Tags: []string{"issues"}, InputSchema: &adapter.JSONSchema{Type: "object"}},
{Namespace: "slack", Name: "post_message", Tags: []string{"chat"}, InputSchema: &adapter.JSONSchema{Type: "object"}},
}
ts, err := set.NewBuilder("issue-workflow").
FromTools(tools).
WithNamespace("github").
WithTags([]string{"issues"}).
WithPolicy(set.DenyTags("danger")).
Build()
if err != nil {
log.Fatal(err)
}
fmt.Println("Toolset IDs:", ts.IDs())
filtered := ts.Filter(set.TagsAny("issues"))
fmt.Println(filtered.IDs())
import (
"log"
"github.com/jonwraymond/toolfoundation/adapter/mcp"
)
exposure := set.NewExposure(ts, mcp.NewAdapter())
tools, warnings, errs := exposure.ExportWithWarnings()
if len(errs) > 0 {
log.Printf("conversion errors: %v", errs)
}
_ = warnings
_ = tools
5. Define a Skill
import "github.com/jonwraymond/toolcompose/skill"
sk := skill.Skill{
Name: "triage-issue",
Steps: []skill.Step{
{ID: "create", ToolID: "github:create_issue", Inputs: map[string]any{"title": "Bug"}},
{ID: "label", ToolID: "github:add_labels", Inputs: map[string]any{"labels": []string{"bug"}}},
},
}
6. Plan + Guard
planner := skill.NewPlanner()
plan, err := planner.Plan(sk)
if err != nil {
log.Fatal(err)
}
guard := skill.MaxStepsGuard(5)
if err := guard.Validate(sk); err != nil {
log.Fatal(err)
}
import (
"context"
"github.com/jonwraymond/toolcompose/skill"
"github.com/jonwraymond/toolexec/run"
)
type runAdapter struct{ exec run.Runner }
func (r runAdapter) Run(ctx context.Context, step skill.Step) (any, error) {
res, err := r.exec.Run(ctx, step.ToolID, step.Inputs)
if err != nil {
return nil, err
}
return res.Output, nil
}
runner := run.NewRunner()
results, err := skill.Execute(context.Background(), plan, runAdapter{exec: runner})
if err != nil {
log.Fatal(err)
}
_ = results
Next Steps
- Combine with
toolcompose/set to scope which tools a skill can access. - Use
toolcompose/set exposures to export protocol-specific tool lists.