feat(tools): implement CRUD operations for thoughts and projects

* Add tools for creating, retrieving, updating, and deleting thoughts.
* Implement project management tools for creating and listing projects.
* Introduce linking functionality between thoughts.
* Add search and recall capabilities for thoughts based on semantic queries.
* Implement statistics and summarization tools for thought analysis.
* Create database migrations for thoughts, projects, and links.
* Add helper functions for UUID parsing and project resolution.
This commit is contained in:
Hein
2026-03-24 15:38:59 +02:00
parent 64024193e9
commit 66370a7f0e
68 changed files with 4422 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
package tools
import (
"context"
"strings"
"github.com/modelcontextprotocol/go-sdk/mcp"
"git.warky.dev/wdevs/amcs/internal/session"
"git.warky.dev/wdevs/amcs/internal/store"
thoughttypes "git.warky.dev/wdevs/amcs/internal/types"
)
type ProjectsTool struct {
store *store.DB
sessions *session.ActiveProjects
}
type CreateProjectInput struct {
Name string `json:"name" jsonschema:"the unique project name"`
Description string `json:"description,omitempty" jsonschema:"optional project description"`
}
type CreateProjectOutput struct {
Project thoughttypes.Project `json:"project"`
}
type ListProjectsInput struct{}
type ListProjectsOutput struct {
Projects []thoughttypes.ProjectSummary `json:"projects"`
}
type SetActiveProjectInput struct {
Project string `json:"project" jsonschema:"project name or id"`
}
type SetActiveProjectOutput struct {
Project thoughttypes.Project `json:"project"`
}
type GetActiveProjectInput struct{}
type GetActiveProjectOutput struct {
Project *thoughttypes.Project `json:"project,omitempty"`
}
func NewProjectsTool(db *store.DB, sessions *session.ActiveProjects) *ProjectsTool {
return &ProjectsTool{store: db, sessions: sessions}
}
func (t *ProjectsTool) Create(ctx context.Context, _ *mcp.CallToolRequest, in CreateProjectInput) (*mcp.CallToolResult, CreateProjectOutput, error) {
name := strings.TrimSpace(in.Name)
if name == "" {
return nil, CreateProjectOutput{}, errInvalidInput("name is required")
}
project, err := t.store.CreateProject(ctx, name, strings.TrimSpace(in.Description))
if err != nil {
return nil, CreateProjectOutput{}, err
}
return nil, CreateProjectOutput{Project: project}, nil
}
func (t *ProjectsTool) List(ctx context.Context, _ *mcp.CallToolRequest, _ ListProjectsInput) (*mcp.CallToolResult, ListProjectsOutput, error) {
projects, err := t.store.ListProjects(ctx)
if err != nil {
return nil, ListProjectsOutput{}, err
}
return nil, ListProjectsOutput{Projects: projects}, nil
}
func (t *ProjectsTool) SetActive(ctx context.Context, req *mcp.CallToolRequest, in SetActiveProjectInput) (*mcp.CallToolResult, SetActiveProjectOutput, error) {
sid, err := sessionID(req)
if err != nil {
return nil, SetActiveProjectOutput{}, err
}
project, err := resolveProject(ctx, t.store, t.sessions, req, in.Project, true)
if err != nil {
return nil, SetActiveProjectOutput{}, err
}
t.sessions.Set(sid, project.ID)
_ = t.store.TouchProject(ctx, project.ID)
return nil, SetActiveProjectOutput{Project: *project}, nil
}
func (t *ProjectsTool) GetActive(ctx context.Context, req *mcp.CallToolRequest, _ GetActiveProjectInput) (*mcp.CallToolResult, GetActiveProjectOutput, error) {
project, err := resolveProject(ctx, t.store, t.sessions, req, "", false)
if err != nil {
return nil, GetActiveProjectOutput{}, err
}
return nil, GetActiveProjectOutput{Project: project}, nil
}