Skip to content

tooldiscovery

Discovery layer providing tool registry, search strategies, and progressive documentation for the ApertureStack tool framework.

Packages

Package Purpose
discovery Unified facade combining index, search, semantic, and tooldoc
index Global registry, tool lookup, and search interface
search BM25-based full-text search strategy
semantic Embedding-based semantic search (optional)
tooldoc Progressive documentation with detail levels
registry MCP server helper with local + backend execution

Installation

go get github.com/jonwraymond/tooldiscovery@latest

Quick Start

import (
  "context"
  "github.com/jonwraymond/tooldiscovery/discovery"
)

disc, _ := discovery.New(discovery.Options{})

// Register tools through the facade
_ = disc.RegisterTool(tool, backend)

// Search (hybrid-ready)
results, _ := disc.Search(context.Background(), "create issue", 5)
for _, r := range results {
  fmt.Printf("[%s] %s\n", r.ScoreType, r.Summary.ID)
}

Build an MCP Server (registry)

import (
  "context"
  "github.com/jonwraymond/tooldiscovery/registry"
)

reg := registry.New(registry.Config{
  ServerInfo: registry.ServerInfo{Name: "my-mcp", Version: "1.0.0"},
})

_ = reg.RegisterLocalFunc(
  "echo",
  "Echo input",
  map[string]any{"type": "object"},
  func(ctx context.Context, args map[string]any) (any, error) { return args, nil },
)

_ = reg.Start(context.Background())
defer reg.Stop()

Register and Search Tools

import (
  "github.com/jonwraymond/tooldiscovery/index"
  "github.com/jonwraymond/toolfoundation/model"
)

// Create an index
idx := index.NewInMemoryIndex()

// Register a tool
err := idx.RegisterTool(tool, backend)
if err != nil {
  log.Fatal(err)
}

// Search for tools
summaries, err := idx.Search("create issue", 5)
for _, s := range summaries {
  fmt.Printf("%s: %s\n", s.ID, s.Summary)
}
import (
  "github.com/jonwraymond/tooldiscovery/index"
  "github.com/jonwraymond/tooldiscovery/search"
)

// Create BM25 searcher
searcher, err := search.NewBM25Searcher(search.DefaultConfig())
if err != nil {
  log.Fatal(err)
}
defer searcher.Close()

// Create index with BM25
idx := index.NewInMemoryIndex(index.WithSearchStrategy(searcher))

Search Strategy Guidance

  • Lexical (default): simple substring matching; best for small registries.
  • BM25 (search): higher quality ranking for larger registries.
  • Semantic (semantic): intent-based matching when embeddings are available.
  • Hybrid (discovery): combines BM25 + semantic with weighted scoring.

Progressive Documentation

import "github.com/jonwraymond/tooldiscovery/tooldoc"

store := tooldoc.NewInMemoryStore(tooldoc.StoreOptions{Index: idx})

// Get summary only (token-cheap)
doc, _ := store.GetDoc(toolID, tooldoc.DetailSummary)

// Get full schema (on-demand)
doc, _ = store.GetDoc(toolID, tooldoc.DetailSchema)

Semantic Search (Optional)

import "github.com/jonwraymond/tooldiscovery/semantic"

// Provide an Embedder + VectorStore implementation
searcher := semantic.NewSemanticSearcher(embedder, vectorStore)
idx := index.NewInMemoryIndex(index.WithSearchStrategy(searcher))

Key Features

  • Token-efficient: Summaries exclude schemas to reduce context usage
  • Pluggable search: Swap between lexical, BM25, or semantic search
  • Progressive disclosure: Request only the detail level needed
  • Namespace support: List and filter tools by namespace