package mcp import ( "context" "encoding/json" "fmt" "github.com/mathiasbq/hyperguild/ingestion/internal/search" ) // tools returns the tool descriptors. Handler bodies for each tool are filled // in subsequent tasks; this file currently only provides the descriptors. func (s *Server) tools() []map[string]any { str := func(desc string) map[string]any { return map[string]any{"type": "string", "description": desc} } int_ := func(desc string) map[string]any { return map[string]any{"type": "integer", "description": desc} } schema := func(required []string, props map[string]any) json.RawMessage { b, _ := json.Marshal(map[string]any{ "type": "object", "required": required, "properties": props, }) return b } return []map[string]any{ { "name": "brain_query", "description": "BM25 full-text search across brain/knowledge/ and brain/wiki/ markdown files.", "inputSchema": schema([]string{"query"}, map[string]any{ "query": str("search terms"), "limit": int_("max results, default 5"), }), }, { "name": "brain_write", "description": "Write a raw knowledge note to brain/knowledge/.", "inputSchema": schema([]string{"content"}, map[string]any{ "content": str("markdown content"), "filename": str("optional filename"), "type": str("optional frontmatter type"), "domain": str("optional frontmatter domain"), }), }, { "name": "brain_ingest_raw", "description": "Ingest pre-structured pages into the brain wiki, bypassing the LLM extraction step.", "inputSchema": schema([]string{"source", "pages"}, map[string]any{ "source": str("source name"), "pages": map[string]any{"type": "array"}, "dry_run": map[string]any{"type": "boolean"}, }), }, { "name": "brain_ingest", "description": "Ingest content into the brain wiki via the LLM extraction pipeline.", "inputSchema": schema([]string{}, map[string]any{ "content": str("raw content; required when path is empty"), "source": str("source name; required when path is empty"), "path": str("file path; mutually exclusive with content+source"), "dry_run": map[string]any{"type": "boolean"}, }), }, { "name": "session_log", "description": "Append a structured entry to brain/sessions/.jsonl.", "inputSchema": schema([]string{"session_id"}, map[string]any{ "session_id": str("session identifier"), "skill": str("skill name"), "phase": str("phase within the skill"), "project_root": str("absolute project root"), "final_status": str("ok | error | skipped"), "file_path": str("optional file produced"), "model_used": str("optional model identifier"), "duration_ms": int_("optional duration in ms"), "message": str("optional free-text"), }), }, } } type brainQueryArgs struct { Query string `json:"query"` Limit int `json:"limit,omitempty"` } func (s *Server) brainQuery(ctx context.Context, args json.RawMessage) (json.RawMessage, error) { var a brainQueryArgs if err := json.Unmarshal(args, &a); err != nil { return nil, fmt.Errorf("parse args: %w", err) } if a.Query == "" { return nil, fmt.Errorf("query is required") } if a.Limit == 0 { a.Limit = 5 } results, err := search.Query(s.brainDir, a.Query, a.Limit) if err != nil { return nil, fmt.Errorf("search: %w", err) } return json.Marshal(map[string]any{"results": results}) }