list.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Package area provides MCP tools for area operations.
 6package area
 7
 8import (
 9	"context"
10	"fmt"
11	"strings"
12
13	"git.secluded.site/lune/internal/mcp/shared"
14	"github.com/modelcontextprotocol/go-sdk/mcp"
15)
16
17// ListToolName is the name of the list areas tool.
18const ListToolName = "list_areas"
19
20// ListToolDescription describes the list areas tool for LLMs.
21const ListToolDescription = `Lists configured areas. Fallback for lunatask://areas resource.
22
23Returns area metadata (id, name, key, workflow) from config.
24Use the lunatask://areas resource if your client supports MCP resources.`
25
26// ListInput is the input schema for listing areas.
27type ListInput struct{}
28
29// Summary represents an area in the list output.
30type Summary struct {
31	ID       string `json:"id"`
32	Name     string `json:"name"`
33	Key      string `json:"key"`
34	Workflow string `json:"workflow"`
35}
36
37// ListOutput is the output schema for listing areas.
38type ListOutput struct {
39	Areas []Summary `json:"areas"`
40	Count int       `json:"count"`
41}
42
43// Handler handles area tool requests.
44type Handler struct {
45	areas []shared.AreaProvider
46}
47
48// NewHandler creates a new area tool handler.
49func NewHandler(areas []shared.AreaProvider) *Handler {
50	return &Handler{areas: areas}
51}
52
53// HandleList lists configured areas.
54func (h *Handler) HandleList(
55	_ context.Context,
56	_ *mcp.CallToolRequest,
57	_ ListInput,
58) (*mcp.CallToolResult, ListOutput, error) {
59	summaries := make([]Summary, 0, len(h.areas))
60
61	for _, area := range h.areas {
62		summaries = append(summaries, Summary{
63			ID:       area.ID,
64			Name:     area.Name,
65			Key:      area.Key,
66			Workflow: string(area.Workflow),
67		})
68	}
69
70	output := ListOutput{
71		Areas: summaries,
72		Count: len(summaries),
73	}
74
75	text := formatListText(summaries)
76
77	return &mcp.CallToolResult{
78		Content: []mcp.Content{&mcp.TextContent{Text: text}},
79	}, output, nil
80}
81
82func formatListText(areas []Summary) string {
83	if len(areas) == 0 {
84		return "No areas configured"
85	}
86
87	var text strings.Builder
88
89	text.WriteString(fmt.Sprintf("Found %d area(s):\n", len(areas)))
90
91	for _, a := range areas {
92		text.WriteString(fmt.Sprintf("- %s: %s (%s, workflow: %s)\n", a.Key, a.Name, a.ID, a.Workflow))
93	}
94
95	return text.String()
96}