handler.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Package timestamp provides an MCP tool for parsing natural language dates.
 6package timestamp
 7
 8import (
 9	"context"
10	"time"
11
12	"git.secluded.site/lune/internal/dateutil"
13	"github.com/modelcontextprotocol/go-sdk/mcp"
14)
15
16// ToolName is the name of this tool.
17const ToolName = "get_timestamp"
18
19// ToolDescription describes the tool for LLMs.
20const ToolDescription = `Parses natural language date/time expressions into RFC3339 timestamps.
21
22Accepts expressions like:
23- "today", "tomorrow", "yesterday"
24- "next Monday", "last Friday"
25- "2 days ago", "in 3 weeks"
26- "March 5", "2024-01-15"
27- "" (empty string returns today)
28
29Returns the timestamp in RFC3339 format (e.g., "2024-01-15T00:00:00Z").
30Use this tool to convert human-readable dates before passing them to task/habit tools.`
31
32// Input is the input schema for the timestamp tool.
33type Input struct {
34	Date string `json:"date"`
35}
36
37// Output is the output schema for the timestamp tool.
38type Output struct {
39	Timestamp string `json:"timestamp"`
40	Date      string `json:"date"`
41}
42
43// Handler handles timestamp tool requests.
44type Handler struct {
45	timezone *time.Location
46}
47
48// NewHandler creates a new timestamp handler with the given timezone.
49func NewHandler(tz string) *Handler {
50	loc, err := time.LoadLocation(tz)
51	if err != nil {
52		loc = time.UTC
53	}
54
55	return &Handler{timezone: loc}
56}
57
58// Handle parses a natural language date and returns an RFC3339 timestamp.
59func (h *Handler) Handle(
60	_ context.Context,
61	_ *mcp.CallToolRequest,
62	input Input,
63) (*mcp.CallToolResult, Output, error) {
64	parsed, err := dateutil.Parse(input.Date)
65	if err != nil {
66		return &mcp.CallToolResult{
67			IsError: true,
68			Content: []mcp.Content{
69				&mcp.TextContent{Text: err.Error()},
70			},
71		}, Output{}, nil
72	}
73
74	t := parsed.In(h.timezone)
75
76	return nil, Output{
77		Timestamp: t.Format(time.RFC3339),
78		Date:      t.Format("2006-01-02"),
79	}, nil
80}