handler.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5// Package areas provides the MCP resource handler for Lunatask areas and goals.
  6package areas
  7
  8import (
  9	"context"
 10	"encoding/json"
 11	"fmt"
 12
 13	"git.secluded.site/lune/internal/mcp/shared"
 14	"github.com/modelcontextprotocol/go-sdk/mcp"
 15)
 16
 17// ResourceURI is the URI for the areas resource.
 18const ResourceURI = "lunatask://areas"
 19
 20// ResourceDescription describes the areas resource for LLMs.
 21const ResourceDescription = `Lists all configured Lunatask areas and their goals.
 22
 23Each area represents a life domain (e.g., Work, Personal, Health) and contains:
 24- id: UUID to use when creating tasks in this area
 25- name: Human-readable area name
 26- key: Short alias for CLI usage
 27- workflow: Task management style (determines which fields are relevant)
 28- workflow_description: Human-readable explanation of the workflow
 29- valid_statuses: Task statuses valid for this workflow
 30- uses_motivation: Whether motivation field (must/should/want) is relevant
 31- uses_eisenhower: Whether eisenhower matrix is relevant
 32- uses_scheduling: Whether date scheduling is relevant
 33- uses_priority: Whether priority field is relevant
 34- goals: List of goals within the area
 35
 36Use workflow information to determine which task fields to set for each area.`
 37
 38// Handler handles area resource requests.
 39type Handler struct {
 40	areas []shared.AreaProvider
 41}
 42
 43// NewHandler creates a new areas resource handler.
 44func NewHandler(areas []shared.AreaProvider) *Handler {
 45	return &Handler{areas: areas}
 46}
 47
 48// areaInfo represents an area in the resource response.
 49type areaInfo struct {
 50	ID                  string     `json:"id"`
 51	Name                string     `json:"name"`
 52	Key                 string     `json:"key"`
 53	Workflow            string     `json:"workflow"`
 54	WorkflowDescription string     `json:"workflow_description"`
 55	ValidStatuses       []string   `json:"valid_statuses"`
 56	UsesMotivation      bool       `json:"uses_motivation"`
 57	UsesEisenhower      bool       `json:"uses_eisenhower"`
 58	UsesScheduling      bool       `json:"uses_scheduling"`
 59	UsesPriority        bool       `json:"uses_priority"`
 60	Goals               []goalInfo `json:"goals"`
 61}
 62
 63// goalInfo represents a goal in the resource response.
 64type goalInfo struct {
 65	ID   string `json:"id"`
 66	Name string `json:"name"`
 67	Key  string `json:"key"`
 68}
 69
 70// HandleRead returns the configured areas and goals.
 71func (h *Handler) HandleRead(
 72	_ context.Context,
 73	_ *mcp.ReadResourceRequest,
 74) (*mcp.ReadResourceResult, error) {
 75	areasInfo := make([]areaInfo, 0, len(h.areas))
 76
 77	for _, area := range h.areas {
 78		goals := make([]goalInfo, 0, len(area.Goals))
 79		for _, g := range area.Goals {
 80			goals = append(goals, goalInfo{
 81				ID:   g.ID,
 82				Name: g.Name,
 83				Key:  g.Key,
 84			})
 85		}
 86
 87		validStatuses := make([]string, 0, len(area.Workflow.ValidStatuses()))
 88		for _, s := range area.Workflow.ValidStatuses() {
 89			validStatuses = append(validStatuses, string(s))
 90		}
 91
 92		areasInfo = append(areasInfo, areaInfo{
 93			ID:                  area.ID,
 94			Name:                area.Name,
 95			Key:                 area.Key,
 96			Workflow:            string(area.Workflow),
 97			WorkflowDescription: area.Workflow.Description(),
 98			ValidStatuses:       validStatuses,
 99			UsesMotivation:      area.Workflow.UsesMotivation(),
100			UsesEisenhower:      area.Workflow.UsesEisenhower(),
101			UsesScheduling:      area.Workflow.UsesScheduling(),
102			UsesPriority:        area.Workflow.UsesPriority(),
103			Goals:               goals,
104		})
105	}
106
107	data, err := json.MarshalIndent(areasInfo, "", "  ")
108	if err != nil {
109		return nil, fmt.Errorf("marshaling areas: %w", err)
110	}
111
112	return &mcp.ReadResourceResult{
113		Contents: []*mcp.ResourceContents{{
114			URI:      ResourceURI,
115			MIMEType: "application/json",
116			Text:     string(data),
117		}},
118	}, nil
119}