@kydycode/todoist-mcp-server-ext 0.2.0 → 0.3.0

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 (3) hide show
  1. package/README.md +110 -100
  2. package/dist/index.js +142 -8
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -3,68 +3,84 @@
3
3
 
4
4
  > **Extended Version** - Forked and enhanced by [kydycode](https://github.com/kydycode) from the original [@abhiz123/todoist-mcp-server](https://github.com/abhiz123/todoist-mcp-server)
5
5
 
6
- A comprehensive MCP (Model Context Protocol) server implementation that provides full integration between Claude and Todoist. This **extended version** includes additional features, improved compatibility, and enhanced functionality using the complete Todoist API with the latest MCP SDK.
6
+ A comprehensive MCP (Model Context Protocol) server implementation that provides full integration between Claude and Todoist. This **extended version** includes additional features, improved compatibility, and enhanced functionality using the complete Todoist API with the latest MCP SDK (`@doist/todoist-api-typescript@4.0.4`).
7
7
 
8
8
  ## 🆕 Extended Version Features
9
9
 
10
10
  ### 🔧 **Technical Improvements**
11
- * **Updated MCP SDK Compatibility**: Compatible with MCP SDK 0.5.0 and latest versions
12
- * **Enhanced Error Handling**: Comprehensive error handling with detailed error messages
13
- * **Improved TypeScript Support**: Better type safety and compatibility
14
- * **Optimized API Usage**: Efficient use of Todoist API with proper parameter handling
15
- * **Better Response Formatting**: Enhanced task and project formatting for better readability
16
-
17
- ### ✨ **Enhanced Task Management**
18
- * **Direct ID-based Operations**: Efficient task operations using task IDs instead of search
19
- * **Comprehensive Task Creation**: Support for subtasks, labels, projects, sections, priorities
20
- * **Quick Add Integration**: Natural language task creation using Todoist's Quick Add
21
- * **Advanced Task Search**: Content-based search with project scoping
22
- * **Task Movement Capabilities**: Move tasks between projects, sections, or make them subtasks
23
- * **Task State Management**: Complete, reopen, and manage task lifecycle
24
- * **Smart Filtering**: Enhanced filtering with better parameter handling
25
-
26
- ### 🗂️ **Complete Project Management**
27
- * **Full Project CRUD**: Create, read, update, delete projects with all properties
28
- * **Sub-project Support**: Create hierarchical project structures
29
- * **Project Customization**: Set colors, favorites, view styles (list/board)
30
- * **Enhanced Project Listing**: Improved project retrieval and formatting
31
-
32
- ### 📋 **Section Management**
33
- * **Complete Section Operations**: Create, read, update, delete sections
34
- * **Project-specific Sections**: Filter and manage sections within projects
35
- * **Section Organization**: Proper ordering and structure management
36
-
37
- ## 🛠️ Available Tools
11
+ * **Updated Todoist SDK**: Now using `@doist/todoist-api-typescript@4.0.4`.
12
+ * **Updated MCP SDK Compatibility**: Compatible with MCP SDK 0.5.0.
13
+ * **Enhanced Error Handling**: Comprehensive error handling with detailed error messages.
14
+ * **Improved TypeScript Support**: Better type safety and compatibility.
15
+ * **Optimized API Usage**: Efficient use of Todoist API, including `getTasksByFilter` for robust search and `moveTasks` for semantic task movement.
16
+ * **Better Response Formatting**: Enhanced task, project, and label formatting for better readability, including project names in search results.
17
+
18
+ ### **Enhanced Task Management (10 Tools)**
19
+ * **Direct ID-based Operations**: Efficient task operations using task IDs.
20
+ * **Comprehensive Task Creation**: Support for subtasks, labels, projects, sections, priorities.
21
+ * **Quick Add Integration**: Natural language task creation using Todoist's Quick Add.
22
+ * **Advanced Task Search**: Robust keyword search using Todoist's filter engine (`search: your query`).
23
+ * **Task Movement Capabilities**: Move tasks between projects, sections, or make them subtasks.
24
+ * **Task State Management**: Complete, reopen, and manage task lifecycle.
25
+ * **Detailed Task Output**: Search and get-task operations return more task details.
26
+
27
+ ### 🗂️ **Complete Project Management (5 Tools)**
28
+ * **Full Project CRUD**: Create, read, update, delete projects with all properties.
29
+ * **Sub-project Support**: Create hierarchical project structures.
30
+ * **Project Customization**: Set colors, favorites, view styles (list/board).
31
+ * **Enhanced Project Listing**: Improved project retrieval with pagination and detailed formatting.
32
+
33
+ ### 📋 **Section Management (4 Tools)**
34
+ * **Complete Section Operations**: Create, read, update, delete sections.
35
+ * **Project-specific Sections**: Filter and manage sections within projects.
36
+ * **Section Organization**: Proper ordering and structure management.
37
+
38
+ ### 🏷️ **Label Management (5 Tools)**
39
+ * **Full Label CRUD**: Create, read, update, delete labels.
40
+ * **Label Customization**: Set names, colors, favorites, order.
41
+ * **Paginated Label Listing**: Efficiently retrieve all labels.
42
+
43
+ ## 🛠️ Available Tools (Total 24)
38
44
 
39
45
  ### Task Operations (10 tools)
40
- | Tool | Description | Enhanced Features |
41
- |------|-------------|------------------|
42
- | `todoist_create_task` | Create tasks with full options | ✅ Subtasks, labels, projects, sections, priorities |
43
- | `todoist_quick_add_task` | Natural language task creation | Todoist Quick Add syntax support |
44
- | `todoist_get_tasks` | Retrieve tasks with filtering | ✅ Project, section, parent, label filtering |
45
- | `todoist_get_task` | Get specific task by ID | Direct ID-based retrieval |
46
- | `todoist_update_task` | Update task properties | ✅ Content, description, due date, priority, labels |
47
- | `todoist_delete_task` | Delete task by ID | ✅ Direct deletion with confirmation |
48
- | `todoist_complete_task` | Mark task complete | ✅ Instant completion |
49
- | `todoist_reopen_task` | Reopen completed task | ✅ Task restoration |
50
- | `todoist_search_tasks` | Search tasks by content | Project-scoped content search |
46
+ | Tool | Description |
47
+ |---------------------------|-------------------------------------------------------------------------------------|
48
+ | `todoist_create_task` | Create tasks with full options (subtasks, labels, projects, sections, priorities). |
49
+ | `todoist_quick_add_task` | Natural language task creation using Todoist's Quick Add syntax. |
50
+ | `todoist_get_tasks` | Retrieve tasks with filtering (project, section, parent, label, IDs) and pagination. |
51
+ | `todoist_get_task` | Get a specific task by its ID, with detailed information. |
52
+ | `todoist_update_task` | Update task properties (content, description, due date, priority, labels). |
53
+ | `todoist_delete_task` | Delete task by ID. |
54
+ | `todoist_complete_task` | Mark task complete. |
55
+ | `todoist_reopen_task` | Reopen completed task. |
56
+ | `todoist_search_tasks` | Search tasks using Todoist's filter engine (e.g., `search: keyword`). |
57
+ | `todoist_move_task` | Move a task to a different project, section, or make it a subtask. |
51
58
 
52
59
  ### Project Operations (5 tools)
53
- | Tool | Description | Enhanced Features |
54
- |------|-------------|------------------|
55
- | `todoist_get_projects` | List all active projects | Clean formatting, proper error handling |
56
- | `todoist_get_project` | Get specific project by ID | ✅ Direct project retrieval |
57
- | `todoist_create_project` | Create new project | ✅ Name, color, favorite, view style, sub-projects |
58
- | `todoist_update_project` | Update project properties | ✅ All project attributes |
59
- | `todoist_delete_project` | Delete project by ID | ✅ Safe deletion with confirmation |
60
+ | Tool | Description |
61
+ |----------------------------|-------------------------------------------------------------------------------|
62
+ | `todoist_get_projects` | List all active projects with pagination support. |
63
+ | `todoist_get_project` | Get a specific project by its ID. |
64
+ | `todoist_create_project` | Create new project (name, color, favorite, view style, sub-projects). |
65
+ | `todoist_update_project` | Update project properties. |
66
+ | `todoist_delete_project` | Delete project by ID. |
60
67
 
61
68
  ### Section Operations (4 tools)
62
- | Tool | Description | Enhanced Features |
63
- |------|-------------|------------------|
64
- | `todoist_get_sections` | List sections | ✅ All sections or project-specific |
65
- | `todoist_create_section` | Create section in project | ✅ Name, project, ordering |
66
- | `todoist_update_section` | Update section name | ✅ Direct section modification |
67
- | `todoist_delete_section` | Delete section by ID | ✅ Clean section removal |
69
+ | Tool | Description |
70
+ |----------------------------|-----------------------------------------------------------------|
71
+ | `todoist_get_sections` | List sections (all sections or project-specific). |
72
+ | `todoist_create_section` | Create section in project (name, project, ordering). |
73
+ | `todoist_update_section` | Update section name. |
74
+ | `todoist_delete_section` | Delete section by ID. |
75
+
76
+ ### Label Operations (5 tools)
77
+ | Tool | Description |
78
+ |--------------------------|--------------------------------------------------------------------|
79
+ | `todoist_create_label` | Create a new label (name, color, favorite, order). |
80
+ | `todoist_get_label` | Get a specific label by its ID. |
81
+ | `todoist_get_labels` | List all labels with pagination support. |
82
+ | `todoist_update_label` | Update an existing label by its ID (name, color, favorite, order). |
83
+ | `todoist_delete_label` | Delete a label by its ID. |
68
84
 
69
85
  ## 🚀 Installation & Setup
70
86
 
@@ -97,7 +113,7 @@ Add to your `claude_desktop_config.json`:
97
113
  "mcpServers": {
98
114
  "todoist-mcp-server": {
99
115
  "command": "node",
100
- "args": ["/path/to/todoist-mcp-server-ext/dist/index.js"],
116
+ "args": ["/path/to/your/todoist-mcp-server-ext/dist/index.js"],
101
117
  "env": {
102
118
  "TODOIST_API_TOKEN": "your_api_token_here"
103
119
  }
@@ -106,13 +122,13 @@ Add to your `claude_desktop_config.json`:
106
122
  }
107
123
  ```
108
124
 
109
- #### Option 2: Run via npm (if installed globally)
125
+ #### Option 2: Run via npm/npx (recommended for published version)
110
126
  ```json
111
127
  {
112
128
  "mcpServers": {
113
129
  "todoist-mcp-server": {
114
130
  "command": "npx",
115
- "args": ["-y", "@kydycode/todoist-mcp-server-ext"],
131
+ "args": ["-y", "@kydycode/todoist-mcp-server-ext@latest"],
116
132
  "env": {
117
133
  "TODOIST_API_TOKEN": "your_api_token_here"
118
134
  }
@@ -124,7 +140,7 @@ Add to your `claude_desktop_config.json`:
124
140
  #### Option 3: Install globally first
125
141
  ```bash
126
142
  # Install the extended version globally
127
- npm install -g @kydycode/todoist-mcp-server-ext
143
+ npm install -g @kydycode/todoist-mcp-server-ext@latest
128
144
 
129
145
  # Then use in Claude Desktop config
130
146
  {
@@ -141,53 +157,40 @@ npm install -g @kydycode/todoist-mcp-server-ext
141
157
 
142
158
  ## 📖 Usage Examples
143
159
 
144
- ### 🎯 Advanced Task Creation
160
+ ### 🎯 Advanced Task Creation & Management
145
161
  ```
146
- "Create task 'Team Meeting' in project 'Work'"
147
- "Add high priority task 'Fix critical bug' with labels 'urgent' and 'backend'"
162
+ "Create task 'Team Meeting @Tomorrow #Work p1'"
163
+ "Add task 'Fix critical bug +KydyCode @DevProject L:Urgent L:Backend'"
148
164
  "Quick add: 'Buy milk tomorrow at 2pm #shopping !p1'"
149
- "Create subtask 'Prepare agenda' under existing task"
165
+ "Move task with ID {task_id} to project {project_id}"
166
+ "Search tasks: search: API deployment"
150
167
  ```
151
168
 
152
- ### 🔍 Task Management & Search
153
- ```
154
- "Get all tasks in project 'Work'"
155
- "Search for tasks containing 'meeting'"
156
- "Show task details for specific task ID"
157
- "Update task priority to urgent"
158
- "Complete task and then reopen it"
159
- ```
160
-
161
- ### 🗂️ Project Organization
169
+ ### 🗂️ Project, Section, and Label Management
162
170
  ```
163
171
  "List all my projects"
164
- "Create project 'Q1 Planning' with blue color and board view"
165
- "Create sub-project 'Marketing' under 'Business'"
166
- "Update project to favorite"
167
- "Get specific project details"
168
- ```
169
-
170
- ### 📋 Section Management
171
- ```
172
- "Create section 'In Progress' in Development project"
173
- "List all sections in Work project"
174
- "Update section name to 'Completed'"
175
- "Delete empty section"
172
+ "Create project 'Q2 Planning' color:blue favorite:true view:board"
173
+ "Get sections for project {project_id}"
174
+ "Create label 'HighPriority' color:red isFavorite:true"
175
+ "List all labels"
176
176
  ```
177
177
 
178
178
  ## 🆚 Extended vs Original Comparison
179
179
 
180
- | Feature | Original | Extended Version |
181
- |---------|----------|------------------|
182
- | **MCP SDK Compatibility** | Older version | ✅ Latest MCP SDK 0.5.0+ |
183
- | **Error Handling** | Basic | ✅ Comprehensive with detailed messages |
184
- | **TypeScript Support** | Limited | ✅ Full type safety |
185
- | **Task Operations** | Search-based | ✅ Direct ID-based + Search fallback |
186
- | **Project Management** | Limited | ✅ Full CRUD operations |
187
- | **Section Management** | Basic | ✅ Complete section operations |
188
- | **API Parameter Handling** | Inconsistent | ✅ Proper parameter validation |
189
- | **Response Formatting** | Basic | ✅ Enhanced readability |
190
- | **Build System** | Issues | ✅ Clean compilation |
180
+ | Feature | Original | Extended Version (`@kydycode/todoist-mcp-server-ext`) |
181
+ |-----------------------------|--------------------------------------|-------------------------------------------------------|
182
+ | **Todoist SDK Version** | Older | ✅ `@doist/todoist-api-typescript@4.0.4` |
183
+ | **MCP SDK Compatibility** | Older version | ✅ Latest MCP SDK 0.5.0+ |
184
+ | **Error Handling** | Basic | ✅ Comprehensive with detailed messages |
185
+ | **TypeScript Support** | Limited | ✅ Full type safety |
186
+ | **Task Operations** | Search-based, limited features | ✅ 10 Tools: Direct ID-based, `moveTasks`, robust search, QuickAdd, full CRUD-like ops |
187
+ | **Project Management** | Limited | ✅ 5 Tools: Full CRUD operations, sub-projects, pagination |
188
+ | **Section Management** | Basic | ✅ 4 Tools: Complete section operations |
189
+ | **Label Management** | Not Available | ✅ 5 Tools: Full CRUD operations, pagination |
190
+ | **API Parameter Handling** | Inconsistent | ✅ Proper parameter validation |
191
+ | **Response Formatting** | Basic | ✅ Enhanced readability, more details |
192
+ | **Build System** | Issues | ✅ Clean compilation |
193
+ | **Search Functionality** | Basic local filter | ✅ Robust `getTasksByFilter` (Todoist engine) |
191
194
 
192
195
  ## 🔧 Development
193
196
 
@@ -195,9 +198,13 @@ npm install -g @kydycode/todoist-mcp-server-ext
195
198
  ```
196
199
  src/
197
200
  ├── index.ts # Main server implementation with all tools
198
- ├── package.json # Dependencies and scripts
199
- ├── tsconfig.json # TypeScript configuration
200
- └── dist/ # Compiled JavaScript output
201
+ package.json # Dependencies and scripts
202
+ tsconfig.json # TypeScript configuration
203
+ README.md # This file
204
+ local-instructions.md # Personal publishing guide
205
+ LICENSE
206
+ .gitignore
207
+ dist/ # Compiled JavaScript output (after `npm run build`)
201
208
  ├── index.js
202
209
  └── index.d.ts
203
210
  ```
@@ -211,14 +218,16 @@ npm install
211
218
  npm run build
212
219
 
213
220
  # Test the server (requires TODOIST_API_TOKEN)
214
- TODOIST_API_TOKEN=your_token node dist/index.js
221
+ # Example: Set token and pipe a list tools request
222
+ export TODOIST_API_TOKEN="your_actual_todoist_api_token"
223
+ echo '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}' | node dist/index.js
215
224
  ```
216
225
 
217
226
  ### Development Scripts
218
227
  ```bash
219
- npm run build # Compile TypeScript
220
- npm run watch # Watch for changes and rebuild
221
- npm run prepare # Pre-publish build
228
+ npm run build # Compile TypeScript and make output executable
229
+ npm run watch # Watch for changes and rebuild (doesn't make output executable)
230
+ npm run prepare # Pre-publish build (runs build)
222
231
  ```
223
232
 
224
233
  ## 🤝 Contributing
@@ -251,6 +260,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
251
260
  ## 🔗 Related Links
252
261
 
253
262
  - **Extended Repository**: [kydycode/todoist-mcp-server-ext](https://github.com/kydycode/todoist-mcp-server-ext)
263
+ - **NPM Package**: [`@kydycode/todoist-mcp-server-ext`](https://www.npmjs.com/package/@kydycode/todoist-mcp-server-ext)
254
264
  - **Original Repository**: [abhiz123/todoist-mcp-server](https://github.com/abhiz123/todoist-mcp-server)
255
265
  - [Todoist API Documentation](https://developer.todoist.com/)
256
266
  - [Model Context Protocol](https://modelcontextprotocol.io/)
package/dist/index.js CHANGED
@@ -211,7 +211,7 @@ const REOPEN_TASK_TOOL = {
211
211
  };
212
212
  const MOVE_TASK_TOOL = {
213
213
  name: "todoist_move_task",
214
- description: "Move a task to a different project, section, or make it a subtask of another task. Provide the taskId and exactly one of: projectId, sectionId, or parentId.",
214
+ description: "Move a single task (and its subtasks, if any) to a different project, section, or make it a subtask of another task. Provide the taskId and exactly one of: projectId, sectionId, or parentId.",
215
215
  inputSchema: {
216
216
  type: "object",
217
217
  properties: {
@@ -238,6 +238,36 @@ const MOVE_TASK_TOOL = {
238
238
  // A more complex JSON schema with oneOf could enforce this, but client support varies.
239
239
  }
240
240
  };
241
+ const BULK_MOVE_TASKS_TOOL = {
242
+ name: "todoist_bulk_move_tasks",
243
+ description: "Move multiple tasks (and their respective subtasks, if any; e.g., up to 10-20 parent tasks for best performance) to a different project, section, or make them subtasks of another task. Provide an array of taskIds and exactly one destination (projectId, sectionId, or parentId).",
244
+ inputSchema: {
245
+ type: "object",
246
+ properties: {
247
+ taskIds: {
248
+ type: "array",
249
+ items: { type: "string" },
250
+ description: "An array of task IDs to move.",
251
+ minItems: 1 // Ensure at least one task ID is provided
252
+ },
253
+ projectId: {
254
+ type: "string",
255
+ description: "The ID of the destination project. (Optional, use only one of projectId, sectionId, parentId)"
256
+ },
257
+ sectionId: {
258
+ type: "string",
259
+ description: "The ID of the destination section. (Optional, use only one of projectId, sectionId, parentId)"
260
+ },
261
+ parentId: {
262
+ type: "string",
263
+ description: "The ID of the parent task to move these tasks under. (Optional, use only one of projectId, sectionId, parentId)"
264
+ }
265
+ },
266
+ required: ["taskIds"]
267
+ // Note: Validation for providing exactly one of projectId, sectionId, or parentId
268
+ // is handled in the isBulkMoveTasksArgs type guard and the tool handler.
269
+ }
270
+ };
241
271
  // Label Management Tools
242
272
  const CREATE_LABEL_TOOL = {
243
273
  name: "todoist_create_label",
@@ -419,13 +449,21 @@ const DELETE_PROJECT_TOOL = {
419
449
  // Section Management Tools
420
450
  const GET_SECTIONS_TOOL = {
421
451
  name: "todoist_get_sections",
422
- description: "Get all sections or sections for a specific project",
452
+ description: "Get all sections, or sections for a specific project. Supports pagination.",
423
453
  inputSchema: {
424
454
  type: "object",
425
455
  properties: {
426
456
  projectId: {
427
457
  type: "string",
428
- description: "Filter sections by project ID (optional)"
458
+ description: "Filter sections by project ID (optional)."
459
+ },
460
+ cursor: {
461
+ type: "string",
462
+ description: "Pagination cursor for next page (optional)."
463
+ },
464
+ limit: {
465
+ type: "number",
466
+ description: "Maximum number of sections to return (default: 50) (optional)."
429
467
  }
430
468
  }
431
469
  }
@@ -603,6 +641,7 @@ function isUpdateProjectArgs(args) {
603
641
  typeof args.projectId === "string");
604
642
  }
605
643
  function isSectionArgs(args) {
644
+ // Allows empty object or object with optional projectId, cursor, limit
606
645
  return typeof args === "object" && args !== null;
607
646
  }
608
647
  function isCreateSectionArgs(args) {
@@ -644,6 +683,21 @@ function isMoveTaskArgs(args) {
644
683
  return providedDestinations.length === 1 &&
645
684
  providedDestinations.every(dest => typeof dest === 'string');
646
685
  }
686
+ function isBulkMoveTasksArgs(args) {
687
+ if (typeof args !== 'object' ||
688
+ args === null ||
689
+ !('taskIds' in args) ||
690
+ !Array.isArray(args.taskIds) ||
691
+ args.taskIds.length === 0 ||
692
+ !args.taskIds.every((id) => typeof id === 'string')) {
693
+ return false;
694
+ }
695
+ const { projectId, sectionId, parentId } = args;
696
+ const destinations = [projectId, sectionId, parentId];
697
+ const providedDestinations = destinations.filter(dest => dest !== undefined && dest !== null && String(dest).trim() !== '');
698
+ return providedDestinations.length === 1 &&
699
+ providedDestinations.every(dest => typeof dest === 'string');
700
+ }
647
701
  function isCreateLabelArgs(args) {
648
702
  return (typeof args === "object" &&
649
703
  args !== null &&
@@ -680,6 +734,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
680
734
  REOPEN_TASK_TOOL,
681
735
  SEARCH_TASKS_TOOL,
682
736
  MOVE_TASK_TOOL,
737
+ BULK_MOVE_TASKS_TOOL,
683
738
  // Project tools
684
739
  GET_PROJECTS_TOOL,
685
740
  GET_PROJECT_TOOL,
@@ -1017,14 +1072,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1017
1072
  const params = {};
1018
1073
  if (args.projectId)
1019
1074
  params.projectId = args.projectId;
1020
- const sections = await todoistClient.getSections(Object.keys(params).length > 0 ? params : {});
1021
- // Handle simple array response
1022
- const sectionResults = Array.isArray(sections) ? sections : [];
1023
- const sectionList = sectionResults.map((section) => `- ${section.name} (ID: ${section.id}, Project: ${section.projectId})`).join('\n');
1075
+ if (args.cursor)
1076
+ params.cursor = args.cursor;
1077
+ if (args.limit)
1078
+ params.limit = args.limit;
1079
+ const sectionsResponse = await todoistClient.getSections(params);
1080
+ const sectionList = sectionsResponse.results?.map((section) => `- ${section.name} (ID: ${section.id}, Project ID: ${section.projectId})`).join('\n') || 'No sections found';
1081
+ const nextCursorMessage = sectionsResponse.nextCursor ? `\n\nNext cursor for more sections: ${sectionsResponse.nextCursor}` : '';
1024
1082
  return {
1025
1083
  content: [{
1026
1084
  type: "text",
1027
- text: `Sections:\n${sectionList || 'No sections found'}`
1085
+ text: `Sections:\n${sectionList}${nextCursorMessage}`
1028
1086
  }],
1029
1087
  isError: false,
1030
1088
  };
@@ -1189,6 +1247,82 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1189
1247
  return { content: [{ type: "text", text: `Error moving task: ${error.message}` }], isError: true };
1190
1248
  }
1191
1249
  }
1250
+ if (name === "todoist_bulk_move_tasks") {
1251
+ if (!isBulkMoveTasksArgs(args)) {
1252
+ return { content: [{ type: "text", text: "Invalid arguments for bulk_move_tasks. Provide a non-empty array of taskIds and exactly one of: projectId, sectionId, or parentId (must be a non-empty string)." }], isError: true };
1253
+ }
1254
+ try {
1255
+ const moveArgs = {};
1256
+ if (args.projectId)
1257
+ moveArgs.projectId = args.projectId;
1258
+ else if (args.sectionId)
1259
+ moveArgs.sectionId = args.sectionId;
1260
+ else if (args.parentId)
1261
+ moveArgs.parentId = args.parentId;
1262
+ console.error(`[DEBUG] todoist_bulk_move_tasks: Attempting to move ${args.taskIds.length} task(s) individually. Destination args: ${JSON.stringify(moveArgs)}`);
1263
+ const results = {
1264
+ succeeded: [],
1265
+ failed: [],
1266
+ };
1267
+ for (const taskId of args.taskIds) {
1268
+ try {
1269
+ console.error(`[DEBUG] Moving task ${taskId} to: ${JSON.stringify(moveArgs)}`);
1270
+ const individualMoveResult = await todoistClient.moveTasks([taskId], moveArgs);
1271
+ // Check if the API returned the task and if its properties reflect the move
1272
+ // For simplicity, we assume if no error is thrown, it was accepted by the API.
1273
+ // A more robust check would be to fetch the task again and verify its sectionId/projectId.
1274
+ if (individualMoveResult && individualMoveResult.length > 0 && individualMoveResult[0].id === taskId) {
1275
+ console.error(`[DEBUG] Task ${taskId} processed by API. Result: ${JSON.stringify(individualMoveResult[0])}`);
1276
+ // Further check if sectionId or projectId in individualMoveResult[0] matches moveArgs
1277
+ const movedTaskDetails = individualMoveResult[0];
1278
+ let successfulMove = false;
1279
+ if (moveArgs.sectionId && movedTaskDetails.sectionId === moveArgs.sectionId)
1280
+ successfulMove = true;
1281
+ else if (moveArgs.projectId && movedTaskDetails.projectId === moveArgs.projectId)
1282
+ successfulMove = true;
1283
+ else if (moveArgs.parentId && movedTaskDetails.parentId === moveArgs.parentId)
1284
+ successfulMove = true;
1285
+ // If the API doesn't reflect the change immediately in the returned object, we might still count it as succeeded based on no error.
1286
+ // For now, we count as success if API call didn't throw and returned our task.
1287
+ if (successfulMove) {
1288
+ results.succeeded.push(taskId);
1289
+ }
1290
+ else {
1291
+ // This case means API processed it but didn't reflect the change in the returned object, or it was already there.
1292
+ // Could be a race condition or API behavior. We'll count it as attempted but not fully confirmed by response.
1293
+ console.warn(`[DEBUG] Task ${taskId} processed, but move not immediately confirmed in API response object. Counting as succeeded based on no error.`);
1294
+ results.succeeded.push(taskId); // Tentatively count as success
1295
+ }
1296
+ }
1297
+ else {
1298
+ // API call succeeded but didn't return our task, or returned empty array
1299
+ console.warn(`[DEBUG] Task ${taskId} move API call succeeded but task not found in response or empty response.`);
1300
+ results.succeeded.push(taskId); // Tentatively count as success if API didn't error
1301
+ }
1302
+ }
1303
+ catch (taskError) {
1304
+ console.error(`[DEBUG] Failed to move task ${taskId}: ${taskError.message}`);
1305
+ results.failed.push({ id: taskId, error: taskError.message });
1306
+ }
1307
+ }
1308
+ let summaryMessage = `Bulk move attempt complete for ${args.taskIds.length} task(s). `;
1309
+ summaryMessage += `Succeeded: ${results.succeeded.length}. `;
1310
+ if (results.succeeded.length > 0)
1311
+ summaryMessage += `Moved IDs: ${results.succeeded.join(", ")}. `;
1312
+ summaryMessage += `Failed: ${results.failed.length}.`;
1313
+ if (results.failed.length > 0) {
1314
+ summaryMessage += ` Failed IDs: ${results.failed.map(f => `${f.id} (${f.error})`).join("; ")}`;
1315
+ }
1316
+ return {
1317
+ content: [{ type: "text", text: summaryMessage }],
1318
+ isError: results.failed.length > 0 && results.succeeded.length === 0, // Overall error if all fails
1319
+ };
1320
+ }
1321
+ catch (error) {
1322
+ console.error(`[DEBUG] todoist_bulk_move_tasks: Outer error caught: ${error.message}`, error);
1323
+ return { content: [{ type: "text", text: `Error in bulk moving tasks: ${error.message}` }], isError: true };
1324
+ }
1325
+ }
1192
1326
  return {
1193
1327
  content: [{ type: "text", text: `Unknown tool: ${name}` }],
1194
1328
  isError: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kydycode/todoist-mcp-server-ext",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Extended MCP server for Todoist API integration with enhanced features and improved compatibility",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -46,4 +46,4 @@
46
46
  "shx": "^0.3.4",
47
47
  "typescript": "^5.7.2"
48
48
  }
49
- }
49
+ }