Skip to content

client.fetchTodos is not a function — tsdav 2.3.0 doesn't export fetchTodos #41

Description

@zelentsov-dev

Bug: client.fetchTodos is not a function — tsdav 2.3.0 doesn't export fetchTodos

Environment

  • dav-mcp version: 3.0.7 (latest on npm)
  • tsdav version (bundled): 2.3.0 (git-pinned to PhilflowIO/tsdav#master)
  • Node: 24.15.0
  • macOS 26.4.1 (arm64)
  • iCloud Reminders via CalDAV

Symptom

Every call to list_todos or todo_query tools fails with:

client.fetchTodos is not a function

Verified by grep "exports.fetchTodos" tsdav.cjs → 0 matches in the bundled tsdav build (tsdav v2.3.0 from PhilflowIO/tsdav#master).

Root cause

Source code calls a method that the bundled tsdav doesn't expose:

  • src/tools/todos/list-todos.js:24const todos = await client.fetchTodos({ calendar });
  • src/tools/todos/todo-query.js:60const calendarTodos = await client.fetchTodos({ calendar });

The bundled tsdav only exports fetchCalendars, fetchCalendarObjects, calendarQuery, calendarMultiGet. There is no fetchTodos.

Notably, todo-query.js already contains a comment acknowledging tsdav doesn't support server-side VTODO filtering:

// Client-side filtering (tsdav doesn't support server-side VTODO filtering yet)

— so the author appears to have known about the limitation but still relied on a non-existent fetchTodos shortcut.

Reproduction

npm install -g dav-mcp@3.0.7
# Configure with any iCloud / CalDAV account
# Through any MCP client (Claude Desktop, OpenClaw, etc.):
#   call tool list_todos { calendar_url: "..." }
# → throws "client.fetchTodos is not a function"

Proposed fix

Replace client.fetchTodos({ calendar }) with client.fetchCalendarObjects({ calendar }) + a client-side VTODO filter — this is the same pattern todo-query.js already uses for status/summary/time filtering.

src/tools/todos/list-todos.js:

-    const calendar = { url: validated.calendar_url };
-    const todos = await client.fetchTodos({ calendar });
+    const calendar = { url: validated.calendar_url };
+    const allObjects = await client.fetchCalendarObjects({ calendar });
+    const todos = allObjects.filter(obj => obj.data && obj.data.includes('BEGIN:VTODO'));

src/tools/todos/todo-query.js:

-      const calendarTodos = await client.fetchTodos({ calendar });
+      const allObjects = await client.fetchCalendarObjects({ calendar });
+      const calendarTodos = allObjects.filter(obj => obj.data && obj.data.includes('BEGIN:VTODO'));

Tested locally

Applied the patch on Mac mini; node --check passes; iCloud Reminders MCP calls now return VTODO objects correctly. Happy to submit a PR if welcome.

Trade-offs of this fix

  • fetchCalendarObjects returns all calendar objects (VEVENT + VTODO + VJOURNAL). For small calendars overhead is negligible. For very large calendars this is slower than a hypothetical native VTODO query — but tsdav doesn't expose that yet anyway.
  • Filter obj.data.includes('BEGIN:VTODO') is precise: VEVENT/VJOURNAL have different component names, no false positives.

Alternative

If tsdav later adds proper VTODO support (e.g., client.calendarQuery({ calendar, comp: 'VTODO' })), the fix can be tightened to a server-side query.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions