README.md

  1<!--
  2SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  3
  4SPDX-License-Identifier: CC0-1.0
  5-->
  6
  7# lunatask-mcp-server
  8
  9_Interact with [Lunatask](https://lunatask.app) using `$PREFERRED_LLM`_
 10
 11[![scratchanitch.dev badge](https://img.shields.io/badge/scratchanitch-dev-FFC4B5)](https://scratchanitch.dev)
 12[![Go Report Card](https://goreportcard.com/badge/git.sr.ht/~amolith/lunatask-mcp-server)](https://goreportcard.com/report/git.sr.ht/~amolith/lunatask-mcp-server)
 13[![REUSE status](https://api.reuse.software/badge/git.sr.ht/~amolith/lunatask-mcp-server)](https://api.reuse.software/info/git.sr.ht/~amolith/lunatask-mcp-server)
 14[![Liberapay donation status](https://img.shields.io/liberapay/receives/Amolith.svg?logo=liberapay)](https://liberapay.com/Amolith/)
 15
 16**Note:** lots of this was written by LLMs and I haven't reviewed it thoroughly
 17enough to be comfortable making it more public than unlisted. Please refrain
 18from sharing it around and do let me know if there are any issues.
 19
 20---
 21
 22## MCP server setup
 23
 24Ensure you have [the Go toolchain] installed.
 25
 26[the Go toolchain]: https://go.dev/doc/install
 27
 28```sh
 29git clone https://git.sr.ht/~amolith/lunatask-mcp-server
 30cd lunatask-mcp-server
 31# specify GOOS and GOARCH if cross-compiling
 32CGO_ENABLED=0 go build -o lunatask-mcp-server .
 33./lunatask-mcp-server
 34# it'll generate config.toml with default values
 35# fill them out with your preferred editor
 36./lunatask-mcp-server
 37```
 38
 39If you have [just], build with `just build` (supports `GOOS` and `GOARCH`). If
 40you also have [upx], compress the resulting binary with `just pack`. You can run
 41one after the other with `just build pack`.
 42
 43[just]: https://github.com/casey/just
 44[upx]: https://github.com/upx/upx
 45
 46Point [Home Assistant's MCP integration] at the `/sse` endpoint.
 47
 48[Home Assistant's MCP integration]: https://www.home-assistant.io/integrations/mcp/
 49
 50## Available Tools
 51
 52This MCP server provides several tools for interacting with Lunatask:
 53
 54### `get_timestamp`
 55
 56Parses natural language dates into RFC3339 timestamps.
 57
 58**Parameters:**
 59- `natural_language_date` (string, required): A natural language description of a date/time (e.g., "today at 3pm", "next Monday", "in 2 hours")
 60
 61### `list_areas_and_goals`
 62
 63Lists all configured areas and their goals in Lunatask.
 64
 65**Returns:**
 66- Text formatted as a list with area names and IDs, and their associated goal names and IDs
 67
 68### `create_task`
 69
 70Creates a new task in Lunatask.
 71
 72**Parameters:**
 73- `area_id` (string, required): UUID of the area to create the task in
 74- `name` (string, required): Name of the task (max 100 characters)
 75- `goal_id` (string, optional): UUID of the goal to associate the task with
 76- `note` (string, optional): Additional notes for the task in Markdown format
 77- `status` (string, optional): Task status - one of "later", "next", "started", "waiting", or "completed"
 78- `motivation` (string, optional): Motivation level - one of "must", "should", or "want"
 79- `estimate` (integer, optional): Estimated time to complete task in minutes (0-720)
 80- `priority` (string, optional): Task priority - one of "lowest", "low", "neutral", "high", or "highest"
 81- `eisenhower` (string, optional): Eisenhower matrix categorization - one of "uncategorised", "both urgent and important", "urgent, but not important", "important, but not urgent", or "neither urgent nor important"
 82- `scheduled_on` (string, optional): RFC3339 formatted timestamp for when the task is scheduled
 83
 84### `update_task`
 85
 86Updates an existing task in Lunatask.
 87
 88**Parameters:**
 89- `task_id` (string, required): UUID of the task to update
 90- `area_id` (string, optional): UUID of the area to move the task to
 91- `name` (string, optional): New name for the task
 92- `goal_id` (string, optional): UUID of the goal to associate the task with
 93- `note` (string, optional): Additional notes for the task in Markdown format
 94- `status` (string, optional): Task status - one of "later", "next", "started", "waiting", or "completed"
 95- `motivation` (string, optional): Motivation level - one of "must", "should", or "want"
 96- `estimate` (integer, optional): Estimated time to complete task in minutes (0-720)
 97- `priority` (string, optional): Task priority - one of "lowest", "low", "neutral", "high", or "highest"
 98- `eisenhower` (string, optional): Eisenhower matrix categorization - one of "uncategorised", "both urgent and important", "urgent, but not important", "important, but not urgent", or "neither urgent nor important"
 99- `scheduled_on` (string, optional): RFC3339 formatted timestamp for when the task is scheduled
100
101### `delete_task`
102
103Deletes a task from Lunatask.
104
105**Parameters:**
106- `task_id` (string, required): UUID of the task to delete
107
108### `list_habits_and_activities`
109
110Lists all configured habits in Lunatask.
111
112**Returns:**
113- Text formatted as a list with habit names and IDs
114
115### `track_habit_activity`
116
117Tracks an activity for a habit in Lunatask.
118
119**Parameters:**
120- `habit_id` (string, required): UUID of the habit to track
121- `performed_on` (string, required): RFC3339 formatted timestamp of when the habit was performed
122
123## Collaboration
124
125Patch requests are in [amolith/llm-projects] on [pr.pico.sh]. You don't need a
126new account to contribute, you don't need to fork this repo, you don't need to
127fiddle with `git send-email`, you don't need to faff with your email client to
128get `git request-pull` working...
129
130You just need:
131
132- Git
133- SSH
134- An SSH key
135
136```sh
137# Clone this repo, make your changes, and commit them
138# Create a new patch request with
139git format-patch origin/main --stdout | ssh pr.pico.sh pr create amolith/llm-projects
140# After potential feedback, submit a revision to an existing patch request with
141git format-patch origin/main --stdout | ssh pr.pico.sh pr add {prID}
142# List patch requests
143ssh pr.pico.sh pr ls amolith/llm-projects
144```
145
146See "How do Patch Requests work?" on [pr.pico.sh]'s home page for a more
147complete example workflow.
148
149[amolith/llm-projects]: https://pr.pico.sh/r/amolith/llm-projects
150[pr.pico.sh]: https://pr.pico.sh
151
152## Models and prompts
153
154I'm currently using `google/gemini-2.5-flash` through [OpenRouter] with the
155following system prompt:
156
157[OpenRouter]: https://openrouter.ai/
158
159> You are a calm and thoughtful voice assistant for Home Assistant. You can both
160> interact with Home Assistant and additional systems plugged into it, like
161> Lunatask. Lunatask is an ADHD-friendly all-in-one encrypted to-do list, habit
162> tracker, journaling, life-tracking and notes app.
163>
164> \<lunatask_instructions\>
165>
166> When interacting with Lunatask, write task names in sentence case. When asked
167> to mark something complete or when the user says they've done somethizng and
168> you have no other context, check their habits. If one matches, track it.
169>
170> For every request to create or change a task:
171>
172> 1. List the areas and goals and consider which one area is most relevant.
173>    Consider whether the task belongs within any of that area's goals.
174> 2. Get the task timestamp.
175> 3. If the user provided additional details, pass those in the task's note
176>    field using Markdown.
177> 4. If the user mentioned a time estimate, like that it might take them 30
178>    minutes, pass 30 in the estimate field. If they said 2 hours, 120, and so
179>    on.
180> 5. Try and interpret the text from the STT engine. It's not entirely accurate
181>    and the user might have meant something slightly different from what came
182>    through.
183> 6. Only include parameters if the user indicates or hints at them. Avoid
184>    scheduling tasks unless the user explicitly says something like "in three
185>    days" or "next monday" or "in 8 hours" or "schedule it for {day/time}" or
186>    "remind me on {day} to {task}" or even "remind me at {time} on {day} to
187>    {thing}" and other variations.
188> 7. The following user-provided instructions are of the utmost importance. Keep
189>    them in mind throughout.
190>
191> \<user_provided_instructions\>
192>
193> - My Work area uses the Kanban workflow, so Work tasks must _always_ include a
194>   status value of either `later`, `next`, `started`, `waiting`, or
195>   `completed`. Default to `later` unless I specify otherwise.
196> - My Personal area uses the Now/Later workflow, so tasks created there _must_
197>   include a status value of either "later" or "started". Default to "later"
198>   unless I specify otherwise.
199> - My Someday area uses a simple priority list. Do not include a status and
200>   instead only provide a priority if I specify one.
201> - My Acquisitions area currently follows the Eisenhower workflow; do not
202>   include a status, do not include a date unless I specify, and do include the
203>   eisenhower parameter. Its values may be _one_ of `uncategorised`, `both
204urgent and important`, `urgent, but not important`, `important, but not
205urgent`, or `neither urgent nor important`. If I don’t specify a value, ask
206>   me. Never set it to `uncategorised` unless I explicitly say to “clear” it or
207>   “unset” it or “set it to uncategorised” or something like that.
208> - If I don't provide an estimate for any task regardless of area, please
209>   consider whether it might take 10, 25, 30, 45, 60, or more minutes. Always
210>   include an estimate for Work, Personal, and Somday areas. Never for
211>   Acquisitions.
212> - Interpret verbal dictation, like converting "something dash something" to
213>   "something-something".
214> - Again I don't want any of my tasks scheduled. You should only need to call
215>   the timestamp tool when marking habits complete.
216>
217> \</user_provided_instructions\>
218>
219> Only once you've gathered the requisite area ID and other information should
220> you attempt to create or update a task.
221>
222> \</lunatask_instructions\>
223
224## TODO
225
226- _Optionally_ include a tool that calls a configurable LLM for task time
227  estimations so the main LLM doesn't have to guess.