- Implement maintenance tool for adding, logging, and retrieving tasks - Create meals tool for managing recipes, meal plans, and shopping lists - Introduce reparse metadata tool for updating thought metadata - Add household knowledge, home maintenance, family calendar, meal planning, and professional CRM database migrations - Grant necessary permissions for new database tables
213 lines
7.3 KiB
Go
213 lines
7.3 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
|
|
"git.warky.dev/wdevs/amcs/internal/store"
|
|
ext "git.warky.dev/wdevs/amcs/internal/types"
|
|
)
|
|
|
|
type CalendarTool struct {
|
|
store *store.DB
|
|
}
|
|
|
|
func NewCalendarTool(db *store.DB) *CalendarTool {
|
|
return &CalendarTool{store: db}
|
|
}
|
|
|
|
// add_family_member
|
|
|
|
type AddFamilyMemberInput struct {
|
|
Name string `json:"name" jsonschema:"person's name"`
|
|
Relationship string `json:"relationship,omitempty" jsonschema:"e.g. self, spouse, child, parent"`
|
|
BirthDate *time.Time `json:"birth_date,omitempty"`
|
|
Notes string `json:"notes,omitempty"`
|
|
}
|
|
|
|
type AddFamilyMemberOutput struct {
|
|
Member ext.FamilyMember `json:"member"`
|
|
}
|
|
|
|
func (t *CalendarTool) AddMember(ctx context.Context, _ *mcp.CallToolRequest, in AddFamilyMemberInput) (*mcp.CallToolResult, AddFamilyMemberOutput, error) {
|
|
if strings.TrimSpace(in.Name) == "" {
|
|
return nil, AddFamilyMemberOutput{}, errInvalidInput("name is required")
|
|
}
|
|
member, err := t.store.AddFamilyMember(ctx, ext.FamilyMember{
|
|
Name: strings.TrimSpace(in.Name),
|
|
Relationship: strings.TrimSpace(in.Relationship),
|
|
BirthDate: in.BirthDate,
|
|
Notes: strings.TrimSpace(in.Notes),
|
|
})
|
|
if err != nil {
|
|
return nil, AddFamilyMemberOutput{}, err
|
|
}
|
|
return nil, AddFamilyMemberOutput{Member: member}, nil
|
|
}
|
|
|
|
// list_family_members
|
|
|
|
type ListFamilyMembersInput struct{}
|
|
|
|
type ListFamilyMembersOutput struct {
|
|
Members []ext.FamilyMember `json:"members"`
|
|
}
|
|
|
|
func (t *CalendarTool) ListMembers(ctx context.Context, _ *mcp.CallToolRequest, _ ListFamilyMembersInput) (*mcp.CallToolResult, ListFamilyMembersOutput, error) {
|
|
members, err := t.store.ListFamilyMembers(ctx)
|
|
if err != nil {
|
|
return nil, ListFamilyMembersOutput{}, err
|
|
}
|
|
if members == nil {
|
|
members = []ext.FamilyMember{}
|
|
}
|
|
return nil, ListFamilyMembersOutput{Members: members}, nil
|
|
}
|
|
|
|
// add_activity
|
|
|
|
type AddActivityInput struct {
|
|
Title string `json:"title" jsonschema:"activity title"`
|
|
ActivityType string `json:"activity_type,omitempty" jsonschema:"e.g. sports, medical, school, social"`
|
|
FamilyMemberID *uuid.UUID `json:"family_member_id,omitempty" jsonschema:"leave empty for whole-family activities"`
|
|
DayOfWeek string `json:"day_of_week,omitempty" jsonschema:"for recurring: monday, tuesday, etc."`
|
|
StartTime string `json:"start_time,omitempty" jsonschema:"HH:MM format"`
|
|
EndTime string `json:"end_time,omitempty" jsonschema:"HH:MM format"`
|
|
StartDate *time.Time `json:"start_date,omitempty"`
|
|
EndDate *time.Time `json:"end_date,omitempty" jsonschema:"for recurring activities, when they end"`
|
|
Location string `json:"location,omitempty"`
|
|
Notes string `json:"notes,omitempty"`
|
|
}
|
|
|
|
type AddActivityOutput struct {
|
|
Activity ext.Activity `json:"activity"`
|
|
}
|
|
|
|
func (t *CalendarTool) AddActivity(ctx context.Context, _ *mcp.CallToolRequest, in AddActivityInput) (*mcp.CallToolResult, AddActivityOutput, error) {
|
|
if strings.TrimSpace(in.Title) == "" {
|
|
return nil, AddActivityOutput{}, errInvalidInput("title is required")
|
|
}
|
|
activity, err := t.store.AddActivity(ctx, ext.Activity{
|
|
FamilyMemberID: in.FamilyMemberID,
|
|
Title: strings.TrimSpace(in.Title),
|
|
ActivityType: strings.TrimSpace(in.ActivityType),
|
|
DayOfWeek: strings.ToLower(strings.TrimSpace(in.DayOfWeek)),
|
|
StartTime: strings.TrimSpace(in.StartTime),
|
|
EndTime: strings.TrimSpace(in.EndTime),
|
|
StartDate: in.StartDate,
|
|
EndDate: in.EndDate,
|
|
Location: strings.TrimSpace(in.Location),
|
|
Notes: strings.TrimSpace(in.Notes),
|
|
})
|
|
if err != nil {
|
|
return nil, AddActivityOutput{}, err
|
|
}
|
|
return nil, AddActivityOutput{Activity: activity}, nil
|
|
}
|
|
|
|
// get_week_schedule
|
|
|
|
type GetWeekScheduleInput struct {
|
|
WeekStart time.Time `json:"week_start" jsonschema:"start of the week (Monday) to retrieve"`
|
|
}
|
|
|
|
type GetWeekScheduleOutput struct {
|
|
Activities []ext.Activity `json:"activities"`
|
|
}
|
|
|
|
func (t *CalendarTool) GetWeekSchedule(ctx context.Context, _ *mcp.CallToolRequest, in GetWeekScheduleInput) (*mcp.CallToolResult, GetWeekScheduleOutput, error) {
|
|
activities, err := t.store.GetWeekSchedule(ctx, in.WeekStart)
|
|
if err != nil {
|
|
return nil, GetWeekScheduleOutput{}, err
|
|
}
|
|
if activities == nil {
|
|
activities = []ext.Activity{}
|
|
}
|
|
return nil, GetWeekScheduleOutput{Activities: activities}, nil
|
|
}
|
|
|
|
// search_activities
|
|
|
|
type SearchActivitiesInput struct {
|
|
Query string `json:"query,omitempty" jsonschema:"search text matching title or notes"`
|
|
ActivityType string `json:"activity_type,omitempty" jsonschema:"filter by type"`
|
|
FamilyMemberID *uuid.UUID `json:"family_member_id,omitempty" jsonschema:"filter by family member"`
|
|
}
|
|
|
|
type SearchActivitiesOutput struct {
|
|
Activities []ext.Activity `json:"activities"`
|
|
}
|
|
|
|
func (t *CalendarTool) SearchActivities(ctx context.Context, _ *mcp.CallToolRequest, in SearchActivitiesInput) (*mcp.CallToolResult, SearchActivitiesOutput, error) {
|
|
activities, err := t.store.SearchActivities(ctx, in.Query, in.ActivityType, in.FamilyMemberID)
|
|
if err != nil {
|
|
return nil, SearchActivitiesOutput{}, err
|
|
}
|
|
if activities == nil {
|
|
activities = []ext.Activity{}
|
|
}
|
|
return nil, SearchActivitiesOutput{Activities: activities}, nil
|
|
}
|
|
|
|
// add_important_date
|
|
|
|
type AddImportantDateInput struct {
|
|
Title string `json:"title" jsonschema:"description of the date"`
|
|
DateValue time.Time `json:"date_value" jsonschema:"the date"`
|
|
FamilyMemberID *uuid.UUID `json:"family_member_id,omitempty"`
|
|
RecurringYearly bool `json:"recurring_yearly,omitempty" jsonschema:"if true, reminds every year"`
|
|
ReminderDaysBefore int `json:"reminder_days_before,omitempty" jsonschema:"how many days before to remind (default: 7)"`
|
|
Notes string `json:"notes,omitempty"`
|
|
}
|
|
|
|
type AddImportantDateOutput struct {
|
|
Date ext.ImportantDate `json:"date"`
|
|
}
|
|
|
|
func (t *CalendarTool) AddImportantDate(ctx context.Context, _ *mcp.CallToolRequest, in AddImportantDateInput) (*mcp.CallToolResult, AddImportantDateOutput, error) {
|
|
if strings.TrimSpace(in.Title) == "" {
|
|
return nil, AddImportantDateOutput{}, errInvalidInput("title is required")
|
|
}
|
|
reminder := in.ReminderDaysBefore
|
|
if reminder <= 0 {
|
|
reminder = 7
|
|
}
|
|
d, err := t.store.AddImportantDate(ctx, ext.ImportantDate{
|
|
FamilyMemberID: in.FamilyMemberID,
|
|
Title: strings.TrimSpace(in.Title),
|
|
DateValue: in.DateValue,
|
|
RecurringYearly: in.RecurringYearly,
|
|
ReminderDaysBefore: reminder,
|
|
Notes: strings.TrimSpace(in.Notes),
|
|
})
|
|
if err != nil {
|
|
return nil, AddImportantDateOutput{}, err
|
|
}
|
|
return nil, AddImportantDateOutput{Date: d}, nil
|
|
}
|
|
|
|
// get_upcoming_dates
|
|
|
|
type GetUpcomingDatesInput struct {
|
|
DaysAhead int `json:"days_ahead,omitempty" jsonschema:"how many days to look ahead (default: 30)"`
|
|
}
|
|
|
|
type GetUpcomingDatesOutput struct {
|
|
Dates []ext.ImportantDate `json:"dates"`
|
|
}
|
|
|
|
func (t *CalendarTool) GetUpcomingDates(ctx context.Context, _ *mcp.CallToolRequest, in GetUpcomingDatesInput) (*mcp.CallToolResult, GetUpcomingDatesOutput, error) {
|
|
dates, err := t.store.GetUpcomingDates(ctx, in.DaysAhead)
|
|
if err != nil {
|
|
return nil, GetUpcomingDatesOutput{}, err
|
|
}
|
|
if dates == nil {
|
|
dates = []ext.ImportantDate{}
|
|
}
|
|
return nil, GetUpcomingDatesOutput{Dates: dates}, nil
|
|
}
|