handler.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5// Package habits provides MCP tools for habit tracking in Lunatask.
  6package habits
  7
  8import (
  9	"context"
 10	"fmt"
 11	"strings"
 12
 13	"git.secluded.site/go-lunatask"
 14	"github.com/mark3labs/mcp-go/mcp"
 15
 16	"git.sr.ht/~amolith/lunatask-mcp-server/tools/shared"
 17)
 18
 19// Handler handles habit-related MCP tool calls.
 20type Handler struct {
 21	accessToken string
 22	habits      []shared.HabitProvider
 23}
 24
 25// NewHandler creates a new habits Handler.
 26func NewHandler(accessToken string, habits []shared.HabitProvider) *Handler {
 27	return &Handler{
 28		accessToken: accessToken,
 29		habits:      habits,
 30	}
 31}
 32
 33// HandleList handles the list_habits_and_activities tool call.
 34func (h *Handler) HandleList(
 35	_ context.Context,
 36	_ mcp.CallToolRequest,
 37) (*mcp.CallToolResult, error) {
 38	var builder strings.Builder
 39
 40	for _, habit := range h.habits {
 41		fmt.Fprintf(&builder, "- %s: %s\n", habit.GetName(), habit.GetID())
 42	}
 43
 44	return &mcp.CallToolResult{
 45		Content: []mcp.Content{
 46			mcp.TextContent{
 47				Type: "text",
 48				Text: builder.String(),
 49			},
 50		},
 51	}, nil
 52}
 53
 54// HandleTrack handles the track_habit_activity tool call.
 55//
 56//nolint:wrapcheck // ReportError returns nil for error
 57func (h *Handler) HandleTrack(
 58	ctx context.Context,
 59	request mcp.CallToolRequest,
 60) (*mcp.CallToolResult, error) {
 61	habitID, ok := request.Params.Arguments["habit_id"].(string)
 62	if !ok || habitID == "" {
 63		return shared.ReportError("Missing or invalid required argument: habit_id")
 64	}
 65
 66	performedOnStr, ok := request.Params.Arguments["performed_on"].(string)
 67	if !ok || performedOnStr == "" {
 68		return shared.ReportError("Missing or invalid required argument: performed_on")
 69	}
 70
 71	performedOn, err := lunatask.ParseDate(performedOnStr)
 72	if err != nil {
 73		return shared.ReportError(fmt.Sprintf(
 74			"Invalid format for performed_on: '%s'. Must be YYYY-MM-DD.",
 75			performedOnStr,
 76		))
 77	}
 78
 79	client := lunatask.NewClient(h.accessToken)
 80	habitRequest := &lunatask.TrackHabitActivityRequest{
 81		PerformedOn: performedOn,
 82	}
 83
 84	resp, err := client.TrackHabitActivity(ctx, habitID, habitRequest)
 85	if err != nil {
 86		return shared.ReportError(fmt.Sprintf("Failed to track habit activity: %v", err))
 87	}
 88
 89	return &mcp.CallToolResult{
 90		Content: []mcp.Content{
 91			mcp.TextContent{
 92				Type: "text",
 93				Text: fmt.Sprintf(
 94					"Habit activity tracked successfully. Status: %s, Message: %s",
 95					resp.Status,
 96					resp.Message,
 97				),
 98			},
 99		},
100	}, nil
101}