@doist/todoist-ai 4.15.1 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/dist/filter-helpers.d.ts +1 -1
  2. package/dist/index.d.ts +175 -175
  3. package/dist/index.js +61 -81
  4. package/dist/main.js +15 -23
  5. package/dist/mcp-helpers.d.ts +4 -4
  6. package/dist/mcp-server-6tm7Rhyz.js +2840 -0
  7. package/dist/todoist-tool.d.ts +2 -2
  8. package/dist/tool-helpers.d.ts +1 -1
  9. package/dist/tools/add-comments.d.ts +1 -1
  10. package/dist/tools/add-comments.d.ts.map +1 -1
  11. package/dist/tools/add-projects.d.ts +4 -4
  12. package/dist/tools/add-projects.d.ts.map +1 -1
  13. package/dist/tools/add-sections.d.ts +1 -1
  14. package/dist/tools/add-sections.d.ts.map +1 -1
  15. package/dist/tools/add-tasks.d.ts +4 -4
  16. package/dist/tools/add-tasks.d.ts.map +1 -1
  17. package/dist/tools/complete-tasks.d.ts +1 -1
  18. package/dist/tools/complete-tasks.d.ts.map +1 -1
  19. package/dist/tools/delete-object.d.ts +3 -3
  20. package/dist/tools/delete-object.d.ts.map +1 -1
  21. package/dist/tools/fetch.d.ts +1 -1
  22. package/dist/tools/find-activity.d.ts +5 -5
  23. package/dist/tools/find-activity.d.ts.map +1 -1
  24. package/dist/tools/find-comments.d.ts +2 -2
  25. package/dist/tools/find-comments.d.ts.map +1 -1
  26. package/dist/tools/find-completed-tasks.d.ts +3 -3
  27. package/dist/tools/find-completed-tasks.d.ts.map +1 -1
  28. package/dist/tools/find-project-collaborators.d.ts +2 -2
  29. package/dist/tools/find-projects.d.ts +1 -1
  30. package/dist/tools/find-projects.d.ts.map +1 -1
  31. package/dist/tools/find-sections.d.ts +1 -1
  32. package/dist/tools/find-sections.d.ts.map +1 -1
  33. package/dist/tools/find-tasks-by-date.d.ts +1 -1
  34. package/dist/tools/find-tasks-by-date.d.ts.map +1 -1
  35. package/dist/tools/find-tasks.d.ts +3 -3
  36. package/dist/tools/find-tasks.d.ts.map +1 -1
  37. package/dist/tools/get-overview.d.ts +1 -1
  38. package/dist/tools/manage-assignments.d.ts +1 -1
  39. package/dist/tools/search.d.ts +1 -1
  40. package/dist/tools/update-comments.d.ts +4 -4
  41. package/dist/tools/update-comments.d.ts.map +1 -1
  42. package/dist/tools/update-projects.d.ts +1 -1
  43. package/dist/tools/update-projects.d.ts.map +1 -1
  44. package/dist/tools/update-sections.d.ts +4 -4
  45. package/dist/tools/update-sections.d.ts.map +1 -1
  46. package/dist/tools/update-tasks.d.ts +7 -7
  47. package/dist/tools/update-tasks.d.ts.map +1 -1
  48. package/dist/tools/user-info.d.ts +1 -1
  49. package/dist/utils/assignment-validator.d.ts +2 -2
  50. package/dist/utils/response-builders.d.ts +1 -3
  51. package/dist/utils/response-builders.d.ts.map +1 -1
  52. package/dist/utils/test-helpers.d.ts +1 -1
  53. package/dist/utils/user-resolver.d.ts +1 -1
  54. package/package.json +11 -9
  55. package/dist/filter-helpers.js +0 -79
  56. package/dist/mcp-helpers.js +0 -71
  57. package/dist/mcp-server.js +0 -142
  58. package/dist/todoist-tool.js +0 -1
  59. package/dist/tool-helpers.js +0 -125
  60. package/dist/tool-helpers.test.d.ts +0 -2
  61. package/dist/tool-helpers.test.d.ts.map +0 -1
  62. package/dist/tool-helpers.test.js +0 -223
  63. package/dist/tools/__tests__/add-comments.test.d.ts +0 -2
  64. package/dist/tools/__tests__/add-comments.test.d.ts.map +0 -1
  65. package/dist/tools/__tests__/add-comments.test.js +0 -241
  66. package/dist/tools/__tests__/add-projects.test.d.ts +0 -2
  67. package/dist/tools/__tests__/add-projects.test.d.ts.map +0 -1
  68. package/dist/tools/__tests__/add-projects.test.js +0 -174
  69. package/dist/tools/__tests__/add-sections.test.d.ts +0 -2
  70. package/dist/tools/__tests__/add-sections.test.d.ts.map +0 -1
  71. package/dist/tools/__tests__/add-sections.test.js +0 -185
  72. package/dist/tools/__tests__/add-tasks.test.d.ts +0 -2
  73. package/dist/tools/__tests__/add-tasks.test.d.ts.map +0 -1
  74. package/dist/tools/__tests__/add-tasks.test.js +0 -533
  75. package/dist/tools/__tests__/assignment-integration.test.d.ts +0 -2
  76. package/dist/tools/__tests__/assignment-integration.test.d.ts.map +0 -1
  77. package/dist/tools/__tests__/assignment-integration.test.js +0 -428
  78. package/dist/tools/__tests__/complete-tasks.test.d.ts +0 -2
  79. package/dist/tools/__tests__/complete-tasks.test.d.ts.map +0 -1
  80. package/dist/tools/__tests__/complete-tasks.test.js +0 -206
  81. package/dist/tools/__tests__/delete-object.test.d.ts +0 -2
  82. package/dist/tools/__tests__/delete-object.test.d.ts.map +0 -1
  83. package/dist/tools/__tests__/delete-object.test.js +0 -110
  84. package/dist/tools/__tests__/fetch.test.d.ts +0 -2
  85. package/dist/tools/__tests__/fetch.test.d.ts.map +0 -1
  86. package/dist/tools/__tests__/fetch.test.js +0 -279
  87. package/dist/tools/__tests__/find-activity.test.d.ts +0 -2
  88. package/dist/tools/__tests__/find-activity.test.d.ts.map +0 -1
  89. package/dist/tools/__tests__/find-activity.test.js +0 -229
  90. package/dist/tools/__tests__/find-comments.test.d.ts +0 -2
  91. package/dist/tools/__tests__/find-comments.test.d.ts.map +0 -1
  92. package/dist/tools/__tests__/find-comments.test.js +0 -236
  93. package/dist/tools/__tests__/find-completed-tasks.test.d.ts +0 -2
  94. package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +0 -1
  95. package/dist/tools/__tests__/find-completed-tasks.test.js +0 -324
  96. package/dist/tools/__tests__/find-projects.test.d.ts +0 -2
  97. package/dist/tools/__tests__/find-projects.test.d.ts.map +0 -1
  98. package/dist/tools/__tests__/find-projects.test.js +0 -154
  99. package/dist/tools/__tests__/find-sections.test.d.ts +0 -2
  100. package/dist/tools/__tests__/find-sections.test.d.ts.map +0 -1
  101. package/dist/tools/__tests__/find-sections.test.js +0 -245
  102. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +0 -2
  103. package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +0 -1
  104. package/dist/tools/__tests__/find-tasks-by-date.test.js +0 -528
  105. package/dist/tools/__tests__/find-tasks.test.d.ts +0 -2
  106. package/dist/tools/__tests__/find-tasks.test.d.ts.map +0 -1
  107. package/dist/tools/__tests__/find-tasks.test.js +0 -771
  108. package/dist/tools/__tests__/get-overview.test.d.ts +0 -2
  109. package/dist/tools/__tests__/get-overview.test.d.ts.map +0 -1
  110. package/dist/tools/__tests__/get-overview.test.js +0 -225
  111. package/dist/tools/__tests__/search.test.d.ts +0 -2
  112. package/dist/tools/__tests__/search.test.d.ts.map +0 -1
  113. package/dist/tools/__tests__/search.test.js +0 -206
  114. package/dist/tools/__tests__/update-comments.test.d.ts +0 -2
  115. package/dist/tools/__tests__/update-comments.test.d.ts.map +0 -1
  116. package/dist/tools/__tests__/update-comments.test.js +0 -294
  117. package/dist/tools/__tests__/update-projects.test.d.ts +0 -2
  118. package/dist/tools/__tests__/update-projects.test.d.ts.map +0 -1
  119. package/dist/tools/__tests__/update-projects.test.js +0 -217
  120. package/dist/tools/__tests__/update-sections.test.d.ts +0 -2
  121. package/dist/tools/__tests__/update-sections.test.d.ts.map +0 -1
  122. package/dist/tools/__tests__/update-sections.test.js +0 -169
  123. package/dist/tools/__tests__/update-tasks.test.d.ts +0 -2
  124. package/dist/tools/__tests__/update-tasks.test.d.ts.map +0 -1
  125. package/dist/tools/__tests__/update-tasks.test.js +0 -788
  126. package/dist/tools/__tests__/user-info.test.d.ts +0 -2
  127. package/dist/tools/__tests__/user-info.test.d.ts.map +0 -1
  128. package/dist/tools/__tests__/user-info.test.js +0 -139
  129. package/dist/tools/add-comments.js +0 -79
  130. package/dist/tools/add-projects.js +0 -63
  131. package/dist/tools/add-sections.js +0 -61
  132. package/dist/tools/add-tasks.js +0 -160
  133. package/dist/tools/complete-tasks.js +0 -68
  134. package/dist/tools/delete-object.js +0 -79
  135. package/dist/tools/fetch.js +0 -102
  136. package/dist/tools/find-activity.js +0 -221
  137. package/dist/tools/find-comments.js +0 -143
  138. package/dist/tools/find-completed-tasks.js +0 -161
  139. package/dist/tools/find-project-collaborators.js +0 -151
  140. package/dist/tools/find-projects.js +0 -101
  141. package/dist/tools/find-sections.js +0 -96
  142. package/dist/tools/find-tasks-by-date.js +0 -198
  143. package/dist/tools/find-tasks.js +0 -329
  144. package/dist/tools/get-overview.js +0 -249
  145. package/dist/tools/manage-assignments.js +0 -337
  146. package/dist/tools/search.js +0 -65
  147. package/dist/tools/update-comments.js +0 -82
  148. package/dist/tools/update-projects.js +0 -84
  149. package/dist/tools/update-sections.js +0 -70
  150. package/dist/tools/update-tasks.js +0 -170
  151. package/dist/tools/user-info.js +0 -142
  152. package/dist/utils/assignment-validator.js +0 -253
  153. package/dist/utils/constants.js +0 -45
  154. package/dist/utils/duration-parser.js +0 -96
  155. package/dist/utils/duration-parser.test.d.ts +0 -2
  156. package/dist/utils/duration-parser.test.d.ts.map +0 -1
  157. package/dist/utils/duration-parser.test.js +0 -147
  158. package/dist/utils/labels.js +0 -18
  159. package/dist/utils/priorities.js +0 -20
  160. package/dist/utils/response-builders.js +0 -210
  161. package/dist/utils/sanitize-data.js +0 -37
  162. package/dist/utils/sanitize-data.test.d.ts +0 -2
  163. package/dist/utils/sanitize-data.test.d.ts.map +0 -1
  164. package/dist/utils/sanitize-data.test.js +0 -93
  165. package/dist/utils/test-helpers.js +0 -237
  166. package/dist/utils/tool-names.js +0 -40
  167. package/dist/utils/user-resolver.js +0 -179
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doist/todoist-ai",
3
- "version": "4.15.1",
3
+ "version": "4.16.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -27,11 +27,13 @@
27
27
  "tools"
28
28
  ],
29
29
  "scripts": {
30
- "test": "jest",
31
- "build": "rimraf dist && npx tsc --project tsconfig.json",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "test:coverage": "vitest run --coverage",
33
+ "build": "vite build",
32
34
  "postbuild": "chmod +x dist/main.js",
33
35
  "start": "npm run build && npx @modelcontextprotocol/inspector node dist/main.js",
34
- "dev": "concurrently \"npx tsc --watch\" \"npx @modelcontextprotocol/inspector npx nodemon --quiet --watch dist --ext js --exec node dist/main.js\"",
36
+ "dev": "concurrently \"vite build --watch\" \"npx @modelcontextprotocol/inspector npx nodemon --quiet --watch dist --ext js --exec node dist/main.js\"",
35
37
  "setup": "cp .env.example .env && npm install && npm run build",
36
38
  "test:executable": "npm run build && node scripts/test-executable.cjs",
37
39
  "type-check": "npx tsc --noEmit",
@@ -46,28 +48,28 @@
46
48
  "prepare": "husky"
47
49
  },
48
50
  "dependencies": {
51
+ "@doist/todoist-api-typescript": "6.0.0",
49
52
  "@modelcontextprotocol/sdk": "^1.11.1",
50
53
  "date-fns": "^4.1.0",
51
- "@doist/todoist-api-typescript": "5.9.0",
52
54
  "dotenv": "^17.0.0",
53
55
  "zod": "^3.25.7"
54
56
  },
55
57
  "devDependencies": {
56
58
  "@biomejs/biome": "2.3.2",
57
59
  "@types/express": "^5.0.2",
58
- "@types/jest": "30.0.0",
59
60
  "@types/morgan": "^1.9.9",
60
61
  "@types/node": "^22.15.17",
61
62
  "concurrently": "^9.0.0",
62
63
  "express": "^5.0.0",
63
64
  "husky": "^9.1.7",
64
- "jest": "30.2.0",
65
65
  "lint-staged": "^16.0.0",
66
66
  "morgan": "^1.10.0",
67
67
  "nodemon": "^3.1.10",
68
68
  "rimraf": "^6.0.1",
69
- "ts-jest": "29.4.5",
70
- "typescript": "^5.8.3"
69
+ "typescript": "^5.8.3",
70
+ "vite": "7.1.10",
71
+ "vite-plugin-dts": "4.5.4",
72
+ "vitest": "3.2.4"
71
73
  },
72
74
  "lint-staged": {
73
75
  "*": [
@@ -1,79 +0,0 @@
1
- import { resolveUserNameToId } from './utils/user-resolver.js';
2
- export const RESPONSIBLE_USER_FILTERING = ['assigned', 'unassignedOrMe', 'all'];
3
- /**
4
- * Resolves a responsible user name/email to user ID and email.
5
- * @param client - Todoist API client
6
- * @param responsibleUser - User identifier (can be user ID, name, or email)
7
- * @returns Object with userId and email, or undefined if not provided
8
- * @throws Error if user cannot be found
9
- */
10
- export async function resolveResponsibleUser(client, responsibleUser) {
11
- if (!responsibleUser) {
12
- return undefined;
13
- }
14
- const resolved = await resolveUserNameToId(client, responsibleUser);
15
- if (!resolved) {
16
- throw new Error(`Could not find user: "${responsibleUser}". Make sure the user is a collaborator on a shared project.`);
17
- }
18
- return { userId: resolved.userId, email: resolved.email };
19
- }
20
- /**
21
- * Appends a filter component to a query string with proper ' & ' separator.
22
- * @param query - The existing query string
23
- * @param filterComponent - The filter component to append
24
- * @returns The updated query string
25
- */
26
- export function appendToQuery(query, filterComponent) {
27
- if (filterComponent.length === 0) {
28
- return query;
29
- }
30
- if (query.length === 0) {
31
- return filterComponent;
32
- }
33
- return `${query} & ${filterComponent}`;
34
- }
35
- /**
36
- * Builds a query filter string for responsible user filtering that can be appended to a Todoist filter query.
37
- * @param resolvedAssigneeId - The resolved assignee ID (if provided)
38
- * @param assigneeEmail - The assignee email (if provided)
39
- * @param responsibleUserFiltering - The filtering mode ('assigned', 'unassignedOrMe', 'all')
40
- * @returns Query filter string (e.g., "assigned to: email@example.com" or "!assigned to: others")
41
- */
42
- export function buildResponsibleUserQueryFilter({ resolvedAssigneeId, assigneeEmail, responsibleUserFiltering = 'unassignedOrMe', }) {
43
- if (resolvedAssigneeId && assigneeEmail) {
44
- // If specific user is provided, filter by that user
45
- return `assigned to: ${assigneeEmail}`;
46
- }
47
- // Otherwise use the filtering mode
48
- if (responsibleUserFiltering === 'unassignedOrMe') {
49
- // Exclude tasks assigned to others (keeps unassigned + assigned to me)
50
- return '!assigned to: others';
51
- }
52
- if (responsibleUserFiltering === 'assigned') {
53
- // Only tasks assigned to others
54
- return 'assigned to: others';
55
- }
56
- // For 'all', don't add any assignment filter
57
- return '';
58
- }
59
- /**
60
- * Filters tasks based on responsible user logic:
61
- * - If resolvedAssigneeId is provided: returns only tasks assigned to that user
62
- * - If no resolvedAssigneeId: returns only unassigned tasks or tasks assigned to current user
63
- * @param tasks - Array of tasks to filter (must have responsibleUid property)
64
- * @param resolvedAssigneeId - The resolved assignee ID to filter by (optional)
65
- * @param currentUserId - The current authenticated user's ID
66
- * @returns Filtered array of tasks
67
- */
68
- export function filterTasksByResponsibleUser({ tasks, resolvedAssigneeId, currentUserId, responsibleUserFiltering = 'unassignedOrMe', }) {
69
- if (resolvedAssigneeId) {
70
- // If responsibleUser provided, only return tasks assigned to that user
71
- return tasks.filter((task) => task.responsibleUid === resolvedAssigneeId);
72
- }
73
- else {
74
- // If no responsibleUser, only return unassigned tasks or tasks assigned to current user
75
- return responsibleUserFiltering === 'unassignedOrMe'
76
- ? tasks.filter((task) => !task.responsibleUid || task.responsibleUid === currentUserId)
77
- : tasks;
78
- }
79
- }
@@ -1,71 +0,0 @@
1
- import { removeNullFields } from './utils/sanitize-data.js';
2
- /**
3
- * Wether to return the structured content directly, vs. in the `content` part of the output.
4
- *
5
- * The `structuredContent` part of the output is relatively new in the spec, and it's not yet
6
- * supported by all clients. This flag controls wether we return the structured content using this
7
- * new feature of the MCP protocol or not.
8
- *
9
- * If `false`, the `structuredContent` will be returned as stringified JSON in one of the `content`
10
- * parts.
11
- *
12
- * Eventually we should be able to remove this, and change the code to always work with the
13
- * structured content returned directly, once most or all MCP clients support it.
14
- */
15
- const USE_STRUCTURED_CONTENT = process.env.USE_STRUCTURED_CONTENT === 'true' || process.env.NODE_ENV === 'test';
16
- /**
17
- * Get the output payload for a tool, in the correct format expected by MCP client apps.
18
- *
19
- * @param textContent - The text content to return.
20
- * @param structuredContent - The structured content to return.
21
- * @returns The output payload.
22
- * @see USE_STRUCTURED_CONTENT - Wether to use the structured content feature of the MCP protocol.
23
- */
24
- function getToolOutput({ textContent, structuredContent, }) {
25
- // Remove null fields from structured content before returning
26
- const sanitizedContent = removeNullFields(structuredContent);
27
- if (USE_STRUCTURED_CONTENT) {
28
- return {
29
- content: [{ type: 'text', text: textContent }],
30
- structuredContent: sanitizedContent,
31
- };
32
- }
33
- const json = JSON.stringify(sanitizedContent);
34
- return {
35
- content: [
36
- { type: 'text', text: textContent },
37
- { type: 'text', mimeType: 'application/json', text: json },
38
- ],
39
- };
40
- }
41
- function getErrorOutput(error) {
42
- return {
43
- content: [{ type: 'text', text: error }],
44
- isError: true,
45
- };
46
- }
47
- /**
48
- * Register a Todoist tool in an MCP server.
49
- * @param tool - The tool to register.
50
- * @param server - The server to register the tool on.
51
- * @param client - The Todoist API client to use to execute the tool.
52
- */
53
- function registerTool(tool, server, client) {
54
- // @ts-expect-error I give up
55
- const cb = async (args, _context) => {
56
- try {
57
- const result = await tool.execute(args, client);
58
- return result;
59
- }
60
- catch (error) {
61
- console.error(`Error executing tool ${tool.name}:`, {
62
- args,
63
- error,
64
- });
65
- const message = error instanceof Error ? error.message : 'An unknown error occurred';
66
- return getErrorOutput(message);
67
- }
68
- };
69
- server.tool(tool.name, tool.description, tool.parameters, cb);
70
- }
71
- export { registerTool, getErrorOutput, getToolOutput };
@@ -1,142 +0,0 @@
1
- import { TodoistApi } from '@doist/todoist-api-typescript';
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { registerTool } from './mcp-helpers.js';
4
- import { addComments } from './tools/add-comments.js';
5
- import { addProjects } from './tools/add-projects.js';
6
- import { addSections } from './tools/add-sections.js';
7
- import { addTasks } from './tools/add-tasks.js';
8
- import { completeTasks } from './tools/complete-tasks.js';
9
- import { deleteObject } from './tools/delete-object.js';
10
- import { fetch } from './tools/fetch.js';
11
- import { findActivity } from './tools/find-activity.js';
12
- import { findComments } from './tools/find-comments.js';
13
- import { findCompletedTasks } from './tools/find-completed-tasks.js';
14
- import { findProjectCollaborators } from './tools/find-project-collaborators.js';
15
- import { findProjects } from './tools/find-projects.js';
16
- import { findSections } from './tools/find-sections.js';
17
- import { findTasks } from './tools/find-tasks.js';
18
- import { findTasksByDate } from './tools/find-tasks-by-date.js';
19
- import { getOverview } from './tools/get-overview.js';
20
- import { manageAssignments } from './tools/manage-assignments.js';
21
- import { search } from './tools/search.js';
22
- import { updateComments } from './tools/update-comments.js';
23
- import { updateProjects } from './tools/update-projects.js';
24
- import { updateSections } from './tools/update-sections.js';
25
- import { updateTasks } from './tools/update-tasks.js';
26
- import { userInfo } from './tools/user-info.js';
27
- const instructions = `
28
- ## Todoist Task and Project Management Tools
29
-
30
- You have access to comprehensive Todoist management tools for personal productivity and team collaboration. Use these tools to help users manage tasks, projects, sections, comments, and assignments effectively.
31
-
32
- ### Core Capabilities:
33
- - Create, update, complete, and search tasks with rich metadata (priorities, due dates, durations, assignments)
34
- - Manage projects and sections with flexible organization
35
- - Handle comments and collaboration features
36
- - Bulk assignment operations for team workflows
37
- - Get overviews and insights about workload and progress
38
-
39
- ### Tool Usage Guidelines:
40
-
41
- **Task Management:**
42
- - **add-tasks**: Create tasks with content, description, priority (p1=highest, p2=high, p3=medium, p4=lowest/default), dueString (natural language like "tomorrow", "next Friday", "2024-12-25"), deadlineDate (ISO 8601 format like "2025-12-31" for immovable constraints), duration (formats like "2h", "90m", "2h30m"), and assignments to project collaborators
43
- - **update-tasks**: Modify existing tasks - get task IDs from search results first, only include fields that need changes. Supports deadlineDate (ISO 8601 format like "2025-12-31") updates and removals (use "remove" to clear)
44
- - **complete-tasks**: Mark tasks as done using task IDs
45
- - **find-tasks**: Search by text, project/section/parent container, responsible user, or labels. Requires at least one search parameter
46
- - **find-tasks-by-date**: Get tasks by date range (startDate: YYYY-MM-DD or 'today' which includes overdue tasks) or specific day counts
47
- - **find-completed-tasks**: View completed tasks by completion date or original due date (returns all collaborators unless filtered)
48
-
49
- **Project & Organization:**
50
- - **add-projects/update-projects/find-projects**: Manage project lifecycle with names, favorites, and view styles (list/board/calendar)
51
- - **add-sections/update-sections/find-sections**: Organize tasks within projects using sections
52
- - **get-overview**: Get comprehensive Markdown overview of entire account or specific project with task hierarchies
53
-
54
- **Collaboration & Comments:**
55
- - **add-comments/update-comments/find-comments**: Manage task and project discussions
56
- - **find-project-collaborators**: Find team members by name or email for assignments
57
- - **manage-assignments**: Bulk assign/unassign/reassign up to 50 tasks with atomic operations and dry-run validation
58
-
59
- **Activity & Audit:**
60
- - **find-activity**: Retrieve recent activity logs to monitor and audit changes. Shows events from all users by default; use initiatorId to filter by specific user. Filter by object type (task/project/comment), event type (added/updated/deleted/completed/uncompleted/archived/unarchived/shared/left), and specific objects (objectId, projectId, taskId). Useful for tracking who did what and when. Note: Date-based filtering is not supported.
61
-
62
- **General Operations:**
63
- - **delete-object**: Remove projects, sections, tasks, or comments by type and ID
64
- - **user-info**: Get user details including timezone, goals, and plan information
65
-
66
- ### Best Practices:
67
-
68
- 1. **Task Creation**: Write clear, actionable task titles. Use natural language for due dates ("tomorrow", "next Monday"). Set appropriate priorities and include detailed descriptions when needed.
69
-
70
- 2. **Search Strategy**: Use specific search queries combining multiple filters for precise results. When searching for tasks, start with broader queries and narrow down as needed.
71
-
72
- 3. **Assignments**: Always validate project collaborators exist before assigning tasks. Use find-project-collaborators to verify user access.
73
-
74
- 4. **Bulk Operations**: When working with multiple items, prefer bulk tools (complete-tasks, manage-assignments) over individual operations for better performance.
75
-
76
- 5. **Date Handling**: All dates respect user timezone settings. Use 'today' keyword for dynamic date filtering (includes overdue tasks).
77
-
78
- 6. **Labels**: Use label filtering with AND/OR operators for advanced task organization. Most search tools support labels parameter.
79
-
80
- 7. **Pagination**: Large result sets use cursor-based pagination. Use limit parameter to control result size (default varies by tool).
81
-
82
- 8. **Error Handling**: All tools provide detailed error messages and next-step suggestions. Pay attention to validation feedback for corrective actions.
83
-
84
- ### Common Workflows:
85
-
86
- - **Daily Planning**: Use find-tasks-by-date with 'today' and get-overview for project status
87
- - **Team Assignment**: find-project-collaborators → add-tasks with responsibleUser → manage-assignments for bulk changes
88
- - **Task Search**: find-tasks with multiple filters → update-tasks or complete-tasks based on results
89
- - **Project Organization**: add-projects → add-sections → add-tasks with projectId and sectionId
90
- - **Progress Reviews**: find-completed-tasks with date ranges → get-overview for project summaries
91
- - **Activity Auditing**: find-activity with event/object filters to track changes, monitor team activity, or investigate specific actions
92
-
93
- Always provide clear, actionable task titles and descriptions. Use the overview tools to give users context about their workload and project status.
94
- `;
95
- /**
96
- * Create the MCP server.
97
- * @param todoistApiKey - The API key for the todoist account.
98
- * @param baseUrl - The base URL for the todoist API.
99
- * @returns the MCP server.
100
- */
101
- function getMcpServer({ todoistApiKey, baseUrl }) {
102
- const server = new McpServer({ name: 'todoist-mcp-server', version: '0.1.0' }, {
103
- capabilities: {
104
- tools: { listChanged: true },
105
- },
106
- instructions,
107
- });
108
- const todoist = new TodoistApi(todoistApiKey, baseUrl);
109
- // Task management tools
110
- registerTool(addTasks, server, todoist);
111
- registerTool(completeTasks, server, todoist);
112
- registerTool(updateTasks, server, todoist);
113
- registerTool(findTasks, server, todoist);
114
- registerTool(findTasksByDate, server, todoist);
115
- registerTool(findCompletedTasks, server, todoist);
116
- // Project management tools
117
- registerTool(addProjects, server, todoist);
118
- registerTool(updateProjects, server, todoist);
119
- registerTool(findProjects, server, todoist);
120
- // Section management tools
121
- registerTool(addSections, server, todoist);
122
- registerTool(updateSections, server, todoist);
123
- registerTool(findSections, server, todoist);
124
- // Comment management tools
125
- registerTool(addComments, server, todoist);
126
- registerTool(findComments, server, todoist);
127
- registerTool(updateComments, server, todoist);
128
- // Activity and audit tools
129
- registerTool(findActivity, server, todoist);
130
- // General tools
131
- registerTool(getOverview, server, todoist);
132
- registerTool(deleteObject, server, todoist);
133
- registerTool(userInfo, server, todoist);
134
- // Assignment and collaboration tools
135
- registerTool(findProjectCollaborators, server, todoist);
136
- registerTool(manageAssignments, server, todoist);
137
- // OpenAI MCP tools
138
- registerTool(search, server, todoist);
139
- registerTool(fetch, server, todoist);
140
- return server;
141
- }
142
- export { getMcpServer };
@@ -1 +0,0 @@
1
- export {};
@@ -1,125 +0,0 @@
1
- import z from 'zod';
2
- import { formatDuration } from './utils/duration-parser.js';
3
- // Re-export filter helpers for backward compatibility
4
- export { appendToQuery, buildResponsibleUserQueryFilter, filterTasksByResponsibleUser, RESPONSIBLE_USER_FILTERING, resolveResponsibleUser, } from './filter-helpers.js';
5
- export function isPersonalProject(project) {
6
- return 'inboxProject' in project;
7
- }
8
- export function isWorkspaceProject(project) {
9
- return 'accessLevel' in project;
10
- }
11
- /**
12
- * Creates a MoveTaskArgs object from move parameters, validating that exactly one is provided.
13
- * @param taskId - The task ID (used for error messages)
14
- * @param projectId - Optional project ID to move to
15
- * @param sectionId - Optional section ID to move to
16
- * @param parentId - Optional parent ID to move to
17
- * @returns MoveTaskArgs object with exactly one destination
18
- * @throws Error if multiple move parameters are provided or none are provided
19
- */
20
- export function createMoveTaskArgs(taskId, projectId, sectionId, parentId) {
21
- // Validate that only one move parameter is provided (RequireExactlyOne constraint)
22
- const moveParams = [projectId, sectionId, parentId].filter(Boolean);
23
- if (moveParams.length > 1) {
24
- throw new Error(`Task ${taskId}: Only one of projectId, sectionId, or parentId can be specified at a time. The Todoist API requires exactly one destination for move operations.`);
25
- }
26
- if (moveParams.length === 0) {
27
- throw new Error(`Task ${taskId}: At least one of projectId, sectionId, or parentId must be provided for move operations.`);
28
- }
29
- // Build moveArgs with the single defined value
30
- if (projectId)
31
- return { projectId };
32
- if (sectionId)
33
- return { sectionId };
34
- if (parentId)
35
- return { parentId };
36
- // This should never be reached due to the validation above
37
- throw new Error('Unexpected error: No valid move parameter found');
38
- }
39
- /**
40
- * Map a single Todoist task to a more structured format, for LLM consumption.
41
- * @param task - The task to map.
42
- * @returns The mapped task.
43
- */
44
- function mapTask(task) {
45
- return {
46
- id: task.id,
47
- content: task.content,
48
- description: task.description,
49
- dueDate: task.due?.date,
50
- recurring: task.due?.isRecurring && task.due.string ? task.due.string : false,
51
- deadlineDate: task.deadline?.date,
52
- priority: task.priority,
53
- projectId: task.projectId,
54
- sectionId: task.sectionId,
55
- parentId: task.parentId,
56
- labels: task.labels,
57
- duration: task.duration ? formatDuration(task.duration.amount) : null,
58
- responsibleUid: task.responsibleUid,
59
- assignedByUid: task.assignedByUid,
60
- checked: task.checked,
61
- completedAt: task.completedAt,
62
- };
63
- }
64
- /**
65
- * Map a single Todoist project to a more structured format, for LLM consumption.
66
- * @param project - The project to map.
67
- * @returns The mapped project.
68
- */
69
- function mapProject(project) {
70
- return {
71
- id: project.id,
72
- name: project.name,
73
- color: project.color,
74
- isFavorite: project.isFavorite,
75
- isShared: project.isShared,
76
- parentId: isPersonalProject(project) ? (project.parentId ?? null) : null,
77
- inboxProject: isPersonalProject(project) ? (project.inboxProject ?? false) : false,
78
- viewStyle: project.viewStyle,
79
- };
80
- }
81
- /**
82
- * Map a single Todoist activity event to a more structured format, for LLM consumption.
83
- * @param event - The activity event to map.
84
- * @returns The mapped activity event.
85
- */
86
- function mapActivityEvent(event) {
87
- return {
88
- id: event.id,
89
- objectType: event.objectType,
90
- objectId: event.objectId,
91
- eventType: event.eventType,
92
- eventDate: event.eventDate,
93
- parentProjectId: event.parentProjectId,
94
- parentItemId: event.parentItemId,
95
- initiatorId: event.initiatorId,
96
- extraData: event.extraData,
97
- };
98
- }
99
- const ErrorSchema = z.object({
100
- httpStatusCode: z.number(),
101
- responseData: z.object({
102
- error: z.string(),
103
- errorCode: z.number(),
104
- errorTag: z.string(),
105
- }),
106
- });
107
- async function getTasksByFilter({ client, query, limit, cursor, }) {
108
- try {
109
- const { results, nextCursor } = await client.getTasksByFilter({ query, cursor, limit });
110
- const tasks = results.map(mapTask);
111
- return { tasks, nextCursor };
112
- }
113
- catch (error) {
114
- const parsedError = ErrorSchema.safeParse(error);
115
- if (!parsedError.success) {
116
- throw error;
117
- }
118
- const { responseData } = parsedError.data;
119
- if (responseData.errorTag === 'INVALID_SEARCH_QUERY') {
120
- throw new Error(`Invalid filter query: ${query}`);
121
- }
122
- throw new Error(`${responseData.error} (tag: ${responseData.errorTag}, code: ${responseData.errorCode})`);
123
- }
124
- }
125
- export { getTasksByFilter, mapActivityEvent, mapProject, mapTask };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=tool-helpers.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-helpers.test.d.ts","sourceRoot":"","sources":["../src/tool-helpers.test.ts"],"names":[],"mappings":""}