● Zion Boggan zionboggan.com ↗

Add mark_delete MCP tool

The MCP server could start, check, and list marks but had no way to
remove one. Agents cleaning up after a finished task had to leave
stale marks in state with no MCP-native cleanup path.

Wire service.DeleteMark into the MCP handler as the mark_delete tool
and add a test for the missing-mark error path.
eebd939   Zion Boggan committed on Jul 9, 2026 (1 month ago)
README.md +1 -0
@@ -82,6 +82,7 @@ JSON responses include a `confidence` value. For v0.1, persisted elapsed calcula
- `mark_start`
- `mark_elapsed`
- `mark_list`
+- `mark_delete`
- `stale_check`
- `ledger_event`
- `ledger_report`
internal/ledger/ledger_test.go +7 -0
@@ -79,6 +79,13 @@ func TestMissingMarkError(t *testing.T) {
}
}
+func TestDeleteMissingMarkError(t *testing.T) {
+ service := testService(t, time.Date(2026, 6, 19, 6, 30, 0, 0, time.UTC))
+ if err := service.DeleteMark("missing"); err == nil {
+ t.Fatal("expected missing mark error")
+ }
+}
+
func TestSessionStatusNoActiveSession(t *testing.T) {
service := testService(t, time.Date(2026, 6, 19, 6, 30, 0, 0, time.UTC))
status, err := service.SessionStatus()
internal/mcp/mcp.go +7 -0
@@ -160,6 +160,10 @@ func handleToolCall(raw json.RawMessage, service *ledger.Service) (callResult, e
result, err = staleCheck(args, service)
case "mark_list":
result, err = service.ListMarks()
+ case "mark_delete":
+ name := requiredString(args, "name")
+ err = service.DeleteMark(name)
+ result = map[string]any{"ok": err == nil, "name": name, "confidence": clock.ConfidenceWallFallback}
case "ledger_event":
note, _ := args["note"].(string)
err = service.LedgerEvent(note)
@@ -214,6 +218,9 @@ func tools() []map[string]any {
"name": stringSchema("Mark name"),
}, "name"),
tool("mark_list", "Return all open marks with elapsed time.", map[string]any{}),
+ tool("mark_delete", "Delete a named mark.", map[string]any{
+ "name": stringSchema("Mark name"),
+ }, "name"),
tool("stale_check", "Check whether a timestamp or mark is stale for a TTL.", map[string]any{
"timestamp": stringSchema("RFC3339 timestamp"),
"mark": stringSchema("Existing mark name"),