create.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5// Package note provides MCP tools for Lunatask note operations.
  6package note
  7
  8import (
  9	"context"
 10
 11	"git.secluded.site/go-lunatask"
 12	"git.secluded.site/lune/internal/mcp/shared"
 13	"github.com/modelcontextprotocol/go-sdk/mcp"
 14)
 15
 16// CreateToolName is the name of the create note tool.
 17const CreateToolName = "create_note"
 18
 19// CreateToolDescription describes the create note tool for LLMs.
 20const CreateToolDescription = `Creates a new note in Lunatask.
 21
 22Optional:
 23- name: Note title
 24- notebook_id: Notebook UUID (get from lunatask://notebooks resource)
 25- content: Markdown content
 26- source: Origin identifier for integrations
 27- source_id: Source-specific ID (requires source)
 28
 29All fields are optional — can create an empty note.
 30Returns the deep link to the created note.
 31
 32Note: If a note with the same source/source_id already exists,
 33the API returns a duplicate warning instead of creating a new note.`
 34
 35// CreateInput is the input schema for creating a note.
 36type CreateInput struct {
 37	Name       *string `json:"name,omitempty"`
 38	NotebookID *string `json:"notebook_id,omitempty"`
 39	Content    *string `json:"content,omitempty"`
 40	Source     *string `json:"source,omitempty"`
 41	SourceID   *string `json:"source_id,omitempty"`
 42}
 43
 44// CreateOutput is the output schema for creating a note.
 45type CreateOutput struct {
 46	DeepLink string `json:"deep_link"`
 47}
 48
 49// Handler handles note-related MCP tool requests.
 50type Handler struct {
 51	client    *lunatask.Client
 52	notebooks []shared.NotebookProvider
 53}
 54
 55// NewHandler creates a new note handler.
 56func NewHandler(accessToken string, notebooks []shared.NotebookProvider) *Handler {
 57	return &Handler{
 58		client:    lunatask.NewClient(accessToken, lunatask.UserAgent("lune-mcp/1.0")),
 59		notebooks: notebooks,
 60	}
 61}
 62
 63// HandleCreate creates a new note.
 64func (h *Handler) HandleCreate(
 65	ctx context.Context,
 66	_ *mcp.CallToolRequest,
 67	input CreateInput,
 68) (*mcp.CallToolResult, CreateOutput, error) {
 69	if input.NotebookID != nil {
 70		if err := lunatask.ValidateUUID(*input.NotebookID); err != nil {
 71			return shared.ErrorResult("invalid notebook_id: expected UUID"), CreateOutput{}, nil
 72		}
 73	}
 74
 75	builder := h.client.NewNote()
 76
 77	if input.Name != nil {
 78		builder.WithName(*input.Name)
 79	}
 80
 81	if input.NotebookID != nil {
 82		builder.InNotebook(*input.NotebookID)
 83	}
 84
 85	if input.Content != nil {
 86		builder.WithContent(*input.Content)
 87	}
 88
 89	if input.Source != nil && input.SourceID != nil {
 90		builder.FromSource(*input.Source, *input.SourceID)
 91	}
 92
 93	note, err := builder.Create(ctx)
 94	if err != nil {
 95		return shared.ErrorResult(err.Error()), CreateOutput{}, nil
 96	}
 97
 98	if note == nil {
 99		return &mcp.CallToolResult{
100			Content: []mcp.Content{&mcp.TextContent{
101				Text: "Note already exists (duplicate source)",
102			}},
103		}, CreateOutput{}, nil
104	}
105
106	deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceNote, note.ID)
107
108	return &mcp.CallToolResult{
109		Content: []mcp.Content{&mcp.TextContent{
110			Text: "Note created: " + deepLink,
111		}},
112	}, CreateOutput{DeepLink: deepLink}, nil
113}