Files
mcp/internal/tools/search_symbols.go
T

49 lines
1.8 KiB
Go
Raw Normal View History

package tools
import (
"context"
"code.nochebuena.dev/einherjar/mcp/internal/index"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type searchSymbolsInput struct {
Query string `json:"query" jsonschema:"text to match against symbol name, doc comment, sub-package, or module"`
Limit int `json:"limit,omitempty" jsonschema:"max results (default 25)"`
Module string `json:"module,omitempty" jsonschema:"restrict to one module by name"`
Kind string `json:"kind,omitempty" jsonschema:"restrict to one kind: type, interface, func, method, const, var"`
}
type searchSymbolsOutput struct {
Results []index.Symbol `json:"results"`
Total int `json:"total"`
}
func registerSearchSymbols(s *mcp.Server, idx *index.Index) {
mcp.AddTool(s, &mcp.Tool{
Name: "search_symbols",
Description: "Search Einherjar's exported symbols (types, interfaces, funcs, methods, consts, vars) by name or doc text. Structs also match on a field name, field type, or struct tag (e.g. an env-var key); interfaces also match on a required method. Optionally filter by module or kind. Use when you need to find where a type, function, field, or tag lives.",
}, func(ctx context.Context, req *mcp.CallToolRequest, args searchSymbolsInput) (*mcp.CallToolResult, searchSymbolsOutput, error) {
all := idx.SearchSymbols(args.Query, args.Limit*4+25)
filtered := all[:0]
for _, sym := range all {
if args.Module != "" && sym.Module != args.Module {
continue
}
if args.Kind != "" && sym.Kind != args.Kind {
continue
}
filtered = append(filtered, sym)
}
limit := args.Limit
if limit <= 0 {
limit = 25
}
if len(filtered) > limit {
filtered = filtered[:limit]
}
out := searchSymbolsOutput{Results: filtered, Total: len(filtered)}
return jsonText(out), out, nil
})
}