Detailed changes
@@ -54,7 +54,6 @@ type CreateInput struct {
// CreateOutput is the output schema for creating a task.
type CreateOutput struct {
- ID string `json:"id"`
DeepLink string `json:"deep_link"`
}
@@ -108,10 +107,11 @@ func (h *Handler) HandleCreate(
deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, task.ID)
- return nil, CreateOutput{
- ID: task.ID,
- DeepLink: deepLink,
- }, nil
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: "Task created: " + deepLink,
+ }},
+ }, CreateOutput{DeepLink: deepLink}, nil
}
//nolint:cyclop,funlen
@@ -30,8 +30,8 @@ type DeleteInput struct {
// DeleteOutput is the output schema for deleting a task.
type DeleteOutput struct {
- Success bool `json:"success"`
- ID string `json:"id"`
+ Success bool `json:"success"`
+ DeepLink string `json:"deep_link"`
}
// HandleDelete deletes a task.
@@ -45,12 +45,15 @@ func (h *Handler) HandleDelete(
return shared.ErrorResult("invalid ID: expected UUID or lunatask:// deep link"), DeleteOutput{}, nil
}
+ deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, id)
+
if _, err := h.client.DeleteTask(ctx, id); err != nil {
return shared.ErrorResult(err.Error()), DeleteOutput{}, nil
}
- return nil, DeleteOutput{
- Success: true,
- ID: id,
- }, nil
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: "Task deleted: " + deepLink,
+ }},
+ }, DeleteOutput{Success: true, DeepLink: deepLink}, nil
}
@@ -6,6 +6,8 @@ package task
import (
"context"
+ "fmt"
+ "strings"
"time"
"git.secluded.site/go-lunatask"
@@ -44,7 +46,6 @@ type ListOutput struct {
// Summary represents a task in list output.
type Summary struct {
- ID string `json:"id"`
DeepLink string `json:"deep_link"`
Status *string `json:"status,omitempty"`
Priority *int `json:"priority,omitempty"`
@@ -90,11 +91,14 @@ func (h *Handler) HandleList(
filtered := lunatask.FilterTasks(tasks, opts)
summaries := buildSummaries(filtered)
-
- return nil, ListOutput{
- Tasks: summaries,
- Count: len(summaries),
- }, nil
+ text := formatListText(summaries)
+
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{Text: text}},
+ }, ListOutput{
+ Tasks: summaries,
+ Count: len(summaries),
+ }, nil
}
func buildSummaries(tasks []lunatask.Task) []Summary {
@@ -102,7 +106,6 @@ func buildSummaries(tasks []lunatask.Task) []Summary {
for _, task := range tasks {
summary := Summary{
- ID: task.ID,
CreatedAt: task.CreatedAt.Format(time.RFC3339),
AreaID: task.AreaID,
GoalID: task.GoalID,
@@ -130,3 +133,26 @@ func buildSummaries(tasks []lunatask.Task) []Summary {
return summaries
}
+
+func formatListText(summaries []Summary) string {
+ if len(summaries) == 0 {
+ return "No tasks found."
+ }
+
+ var builder strings.Builder
+
+ builder.WriteString(fmt.Sprintf("Found %d task(s):\n", len(summaries)))
+
+ for _, summary := range summaries {
+ status := "unknown"
+ if summary.Status != nil {
+ status = *summary.Status
+ }
+
+ builder.WriteString(fmt.Sprintf("- %s (%s)\n", summary.DeepLink, status))
+ }
+
+ builder.WriteString("\nUse show_task for full details.")
+
+ return builder.String()
+}
@@ -6,6 +6,8 @@ package task
import (
"context"
+ "fmt"
+ "strings"
"time"
"git.secluded.site/go-lunatask"
@@ -32,7 +34,6 @@ type ShowInput struct {
// ShowOutput is the output schema for showing a task.
type ShowOutput struct {
- ID string `json:"id"`
DeepLink string `json:"deep_link"`
Status *string `json:"status,omitempty"`
Priority *int `json:"priority,omitempty"`
@@ -64,7 +65,6 @@ func (h *Handler) HandleShow(
}
output := ShowOutput{
- ID: task.ID,
CreatedAt: task.CreatedAt.Format(time.RFC3339),
UpdatedAt: task.UpdatedAt.Format(time.RFC3339),
AreaID: task.AreaID,
@@ -104,5 +104,59 @@ func (h *Handler) HandleShow(
output.Urgent = &urgent
}
- return nil, output, nil
+ text := formatShowText(output)
+
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{Text: text}},
+ }, output, nil
+}
+
+func formatShowText(output ShowOutput) string {
+ var builder strings.Builder
+
+ builder.WriteString(fmt.Sprintf("Task: %s\n", output.DeepLink))
+ writeOptionalField(&builder, "Status", output.Status)
+ writeOptionalIntField(&builder, "Priority", output.Priority)
+ writeOptionalField(&builder, "Scheduled", output.ScheduledOn)
+ writeOptionalMinutesField(&builder, "Estimate", output.Estimate)
+ writeEisenhowerField(&builder, output.Important, output.Urgent)
+ builder.WriteString(fmt.Sprintf("Created: %s\n", output.CreatedAt))
+ builder.WriteString("Updated: " + output.UpdatedAt)
+ writeOptionalField(&builder, "\nCompleted", output.CompletedAt)
+
+ return builder.String()
+}
+
+func writeOptionalField(builder *strings.Builder, label string, value *string) {
+ if value != nil {
+ fmt.Fprintf(builder, "%s: %s\n", label, *value)
+ }
+}
+
+func writeOptionalIntField(builder *strings.Builder, label string, value *int) {
+ if value != nil {
+ fmt.Fprintf(builder, "%s: %d\n", label, *value)
+ }
+}
+
+func writeOptionalMinutesField(builder *strings.Builder, label string, value *int) {
+ if value != nil {
+ fmt.Fprintf(builder, "%s: %d min\n", label, *value)
+ }
+}
+
+func writeEisenhowerField(builder *strings.Builder, important, urgent *bool) {
+ var parts []string
+
+ if important != nil && *important {
+ parts = append(parts, "important")
+ }
+
+ if urgent != nil && *urgent {
+ parts = append(parts, "urgent")
+ }
+
+ if len(parts) > 0 {
+ fmt.Fprintf(builder, "Eisenhower: %s\n", strings.Join(parts, ", "))
+ }
}
@@ -55,7 +55,6 @@ type UpdateInput struct {
// UpdateOutput is the output schema for updating a task.
type UpdateOutput struct {
- ID string `json:"id"`
DeepLink string `json:"deep_link"`
}
@@ -96,10 +95,11 @@ func (h *Handler) HandleUpdate(
deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, task.ID)
- return nil, UpdateOutput{
- ID: task.ID,
- DeepLink: deepLink,
- }, nil
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: "Task updated: " + deepLink,
+ }},
+ }, UpdateOutput{DeepLink: deepLink}, nil
}
//nolint:cyclop,funlen
@@ -7,6 +7,7 @@ package timestamp
import (
"context"
+ "fmt"
"time"
"git.secluded.site/lune/internal/dateutil"
@@ -72,9 +73,19 @@ func (h *Handler) Handle(
}
t := parsed.In(h.timezone)
-
- return nil, Output{
+ output := Output{
Timestamp: t.Format(time.RFC3339),
Date: t.Format("2006-01-02"),
- }, nil
+ }
+
+ inputDisplay := input.Date
+ if inputDisplay == "" {
+ inputDisplay = "(empty)"
+ }
+
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: fmt.Sprintf("Parsed %q → %s", inputDisplay, output.Timestamp),
+ }},
+ }, output, nil
}