list.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Package notebook provides MCP tools for notebook operations.
 6package notebook
 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 notebooks tool.
18const ListToolName = "list_notebooks"
19
20// ListToolDescription describes the list notebooks tool for LLMs.
21const ListToolDescription = `Lists configured notebooks. Fallback for lunatask://notebooks resource.
22
23Returns notebook metadata (IDs, names, keys).
24Use notebook IDs when creating or updating notes.`
25
26// ListInput is the input schema for listing notebooks.
27type ListInput struct{}
28
29// Summary represents a notebook in the list output.
30type Summary struct {
31	ID   string `json:"id"`
32	Name string `json:"name"`
33	Key  string `json:"key"`
34}
35
36// ListOutput is the output schema for listing notebooks.
37type ListOutput struct {
38	Notebooks []Summary `json:"notebooks"`
39	Count     int       `json:"count"`
40}
41
42// Handler handles notebook tool requests.
43type Handler struct {
44	notebooks []shared.NotebookProvider
45}
46
47// NewHandler creates a new notebook tool handler.
48func NewHandler(notebooks []shared.NotebookProvider) *Handler {
49	return &Handler{notebooks: notebooks}
50}
51
52// HandleList lists configured notebooks.
53func (h *Handler) HandleList(
54	_ context.Context,
55	_ *mcp.CallToolRequest,
56	_ ListInput,
57) (*mcp.CallToolResult, ListOutput, error) {
58	summaries := make([]Summary, 0, len(h.notebooks))
59
60	for _, nb := range h.notebooks {
61		summaries = append(summaries, Summary{
62			ID:   nb.ID,
63			Name: nb.Name,
64			Key:  nb.Key,
65		})
66	}
67
68	output := ListOutput{
69		Notebooks: summaries,
70		Count:     len(summaries),
71	}
72
73	text := formatListText(summaries)
74
75	return &mcp.CallToolResult{
76		Content: []mcp.Content{&mcp.TextContent{Text: text}},
77	}, output, nil
78}
79
80func formatListText(notebooks []Summary) string {
81	if len(notebooks) == 0 {
82		return "No notebooks configured"
83	}
84
85	var text strings.Builder
86
87	text.WriteString(fmt.Sprintf("Found %d notebook(s):\n", len(notebooks)))
88
89	for _, nb := range notebooks {
90		text.WriteString(fmt.Sprintf("- %s (key: %s, id: %s)\n", nb.Name, nb.Key, nb.ID))
91	}
92
93	return text.String()
94}