create.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Package person provides MCP tools for Lunatask person/relationship operations.
 6package person
 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 person tool.
17const CreateToolName = "create_person"
18
19// CreateToolDescription describes the create person tool for LLMs.
20const CreateToolDescription = `Creates a new person in Lunatask's relationship tracker.
21
22Required:
23- first_name: First name
24
25Optional:
26- last_name: Last name
27- relationship: Relationship strength (family, intimate-friends, close-friends,
28  casual-friends, acquaintances, business-contacts, almost-strangers)
29  Default: casual-friends
30- source: Origin identifier for integrations
31- source_id: Source-specific ID (requires source)
32
33Returns the deep link to the created person.`
34
35// CreateInput is the input schema for creating a person.
36type CreateInput struct {
37	FirstName    string  `json:"first_name"             jsonschema:"required"`
38	LastName     *string `json:"last_name,omitempty"`
39	Relationship *string `json:"relationship,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 person.
45type CreateOutput struct {
46	DeepLink string `json:"deep_link"`
47}
48
49// Handler handles person-related MCP tool requests.
50type Handler struct {
51	client *lunatask.Client
52}
53
54// NewHandler creates a new person handler.
55func NewHandler(accessToken string) *Handler {
56	return &Handler{
57		client: lunatask.NewClient(accessToken, lunatask.UserAgent("lune-mcp/1.0")),
58	}
59}
60
61// HandleCreate creates a new person.
62func (h *Handler) HandleCreate(
63	ctx context.Context,
64	_ *mcp.CallToolRequest,
65	input CreateInput,
66) (*mcp.CallToolResult, CreateOutput, error) {
67	lastName := ""
68	if input.LastName != nil {
69		lastName = *input.LastName
70	}
71
72	builder := h.client.NewPerson(input.FirstName, lastName)
73
74	if input.Relationship != nil {
75		rel, err := lunatask.ParseRelationshipStrength(*input.Relationship)
76		if err != nil {
77			return shared.ErrorResult(err.Error()), CreateOutput{}, nil
78		}
79
80		builder.WithRelationshipStrength(rel)
81	}
82
83	if input.Source != nil && input.SourceID != nil {
84		builder.FromSource(*input.Source, *input.SourceID)
85	}
86
87	person, err := builder.Create(ctx)
88	if err != nil {
89		return shared.ErrorResult(err.Error()), CreateOutput{}, nil
90	}
91
92	deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourcePerson, person.ID)
93
94	return &mcp.CallToolResult{
95		Content: []mcp.Content{&mcp.TextContent{
96			Text: "Person created: " + deepLink,
97		}},
98	}, CreateOutput{DeepLink: deepLink}, nil
99}