From 010a1ed2f1459d959e988668e5625aa27cc612dd Mon Sep 17 00:00:00 2001 From: Amolith Date: Sat, 31 Jan 2026 22:33:27 -0700 Subject: [PATCH] feat(mcp): add OpenWorldHint and Title to tools Add OpenWorldHint (true) and human-readable Title to all 7 MCP tools: - get_timestamp: Parse date - add_timeline_note: Add timeline note - track_habit: Track habit - create: Create entity - update: Update entity - delete: Delete entity - query: Query entities The OpenWorldHint indicates these tools interact with external APIs (Lunatask), and titles provide nicer UI labels for MCP clients. --- internal/mcp/tools/crud/create.go | 2 ++ internal/mcp/tools/crud/delete.go | 2 ++ internal/mcp/tools/crud/query.go | 4 +++- internal/mcp/tools/crud/update.go | 2 ++ internal/mcp/tools/habit/track.go | 4 ++++ internal/mcp/tools/timeline/handler.go | 2 ++ internal/mcp/tools/timestamp/handler.go | 6 +++++- 7 files changed, 20 insertions(+), 2 deletions(-) diff --git a/internal/mcp/tools/crud/create.go b/internal/mcp/tools/crud/create.go index 70c487c5119642acb9381411ad31e9880df07614..9cc31acdc03e348154fd9ae5424b8fec89e2ae3b 100644 --- a/internal/mcp/tools/crud/create.go +++ b/internal/mcp/tools/crud/create.go @@ -44,6 +44,8 @@ Returns the new entity's ID and deep link.` func CreateToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ DestructiveHint: ptr(false), + OpenWorldHint: ptr(true), + Title: "Create entity", } } diff --git a/internal/mcp/tools/crud/delete.go b/internal/mcp/tools/crud/delete.go index fa474875c69a27f64de3d04dabdc6a3fa4c8ed77..e08be8c40c7cfa8a7ae12c7e7a73d6c5d5ee64e8 100644 --- a/internal/mcp/tools/crud/delete.go +++ b/internal/mcp/tools/crud/delete.go @@ -24,6 +24,8 @@ This action cannot be undone. The entity and its associations are removed.` func DeleteToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ DestructiveHint: ptr(true), + OpenWorldHint: ptr(true), + Title: "Delete entity", } } diff --git a/internal/mcp/tools/crud/query.go b/internal/mcp/tools/crud/query.go index fcc50a47a3f1158a36fecab0ab581df23da7f73c..63200c4ec4d791990d2cfc763fd874c25f94532c 100644 --- a/internal/mcp/tools/crud/query.go +++ b/internal/mcp/tools/crud/query.go @@ -29,7 +29,9 @@ Prefer MCP resources (lunatask://tasks/today, lunatask://areas) when available.` // QueryToolAnnotations returns hints about tool behavior. func QueryToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ - ReadOnlyHint: true, + ReadOnlyHint: true, + OpenWorldHint: ptr(true), + Title: "Query entities", } } diff --git a/internal/mcp/tools/crud/update.go b/internal/mcp/tools/crud/update.go index 574725c8395a8b28d4b181206f8494ff58e97fd7..b9983eea343cc71cd5f103157ae76c669942926b 100644 --- a/internal/mcp/tools/crud/update.go +++ b/internal/mcp/tools/crud/update.go @@ -28,6 +28,8 @@ Task note/content replaces existing (not appended). Idempotent.` func UpdateToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ IdempotentHint: true, + OpenWorldHint: ptr(true), + Title: "Update entity", } } diff --git a/internal/mcp/tools/habit/track.go b/internal/mcp/tools/habit/track.go index 2a11c2a9d04a140ecd02b5fce5dcf254d105f64f..5e2ccd91d72e3d037abb7f6529d1cf17ed9d0d00 100644 --- a/internal/mcp/tools/habit/track.go +++ b/internal/mcp/tools/habit/track.go @@ -27,9 +27,13 @@ Tracks for today by default. Idempotent—re-tracking the same date has no effec func TrackToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ IdempotentHint: true, + OpenWorldHint: ptr(true), + Title: "Track habit", } } +func ptr[T any](v T) *T { return &v } + // TrackInput is the input schema for tracking a habit. type TrackInput struct { HabitID string `json:"habit_id" jsonschema:"Habit UUID, lunatask:// deep link, or config key"` diff --git a/internal/mcp/tools/timeline/handler.go b/internal/mcp/tools/timeline/handler.go index 6e93ae6c8c88bb60aeb1979299a4b870a2780569..e3b615a0c351bb1d1608fa21f32665188f517250 100644 --- a/internal/mcp/tools/timeline/handler.go +++ b/internal/mcp/tools/timeline/handler.go @@ -27,6 +27,8 @@ interactions, meetings, or memorable moments with someone.` func ToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ DestructiveHint: ptr(false), + OpenWorldHint: ptr(true), + Title: "Add timeline note", } } diff --git a/internal/mcp/tools/timestamp/handler.go b/internal/mcp/tools/timestamp/handler.go index 43c83fa95e652f200d696084768cc9edd6a38c51..933525f9f06b26e212158bb6f9c00d6c23596d42 100644 --- a/internal/mcp/tools/timestamp/handler.go +++ b/internal/mcp/tools/timestamp/handler.go @@ -27,10 +27,14 @@ Empty input returns today.` // ToolAnnotations returns hints about tool behavior. func ToolAnnotations() *mcp.ToolAnnotations { return &mcp.ToolAnnotations{ - ReadOnlyHint: true, + ReadOnlyHint: true, + OpenWorldHint: ptr(true), + Title: "Parse date", } } +func ptr[T any](v T) *T { return &v } + // Input is the input schema for the timestamp tool. type Input struct { Date string `json:"date" jsonschema:"Date/time expression to parse (empty = today)"`