package tools import ( "context" "strings" "github.com/modelcontextprotocol/go-sdk/mcp" "git.warky.dev/wdevs/amcs/internal/ai" "git.warky.dev/wdevs/amcs/internal/config" "git.warky.dev/wdevs/amcs/internal/session" "git.warky.dev/wdevs/amcs/internal/store" thoughttypes "git.warky.dev/wdevs/amcs/internal/types" ) type SearchTool struct { store *store.DB provider ai.Provider search config.SearchConfig sessions *session.ActiveProjects } type SearchInput struct { Query string `json:"query" jsonschema:"the semantic query to search for"` Limit int `json:"limit,omitempty" jsonschema:"maximum number of results to return"` Threshold float64 `json:"threshold,omitempty" jsonschema:"minimum similarity threshold between 0 and 1"` Project string `json:"project,omitempty" jsonschema:"optional project name or id to scope the search"` } type SearchOutput struct { Results []thoughttypes.SearchResult `json:"results"` } func NewSearchTool(db *store.DB, provider ai.Provider, search config.SearchConfig, sessions *session.ActiveProjects) *SearchTool { return &SearchTool{store: db, provider: provider, search: search, sessions: sessions} } func (t *SearchTool) Handle(ctx context.Context, req *mcp.CallToolRequest, in SearchInput) (*mcp.CallToolResult, SearchOutput, error) { query := strings.TrimSpace(in.Query) if query == "" { return nil, SearchOutput{}, errInvalidInput("query is required") } limit := normalizeLimit(in.Limit, t.search) threshold := normalizeThreshold(in.Threshold, t.search.DefaultThreshold) embedding, err := t.provider.Embed(ctx, query) if err != nil { return nil, SearchOutput{}, err } project, err := resolveProject(ctx, t.store, t.sessions, req, in.Project, false) if err != nil { return nil, SearchOutput{}, err } var results []thoughttypes.SearchResult if project != nil { results, err = t.store.SearchSimilarThoughts(ctx, embedding, threshold, limit, &project.ID, nil) _ = t.store.TouchProject(ctx, project.ID) } else { results, err = t.store.SearchThoughts(ctx, embedding, threshold, limit, map[string]any{}) } if err != nil { return nil, SearchOutput{}, err } return nil, SearchOutput{Results: results}, nil }