todoist-mcp 1.2.1 → 1.2.2

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 (49) hide show
  1. package/dist/clients.d.ts +4 -0
  2. package/dist/clients.js +10 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +3 -47
  5. package/dist/prompts/projects.d.ts +0 -2
  6. package/dist/prompts/projects.js +60 -62
  7. package/dist/prompts.d.ts +1 -7
  8. package/dist/prompts.js +1 -5
  9. package/dist/tools/comments.d.ts +1 -4
  10. package/dist/tools/comments.js +53 -184
  11. package/dist/tools/labels.d.ts +1 -4
  12. package/dist/tools/labels.js +92 -284
  13. package/dist/tools/projects.d.ts +1 -4
  14. package/dist/tools/projects.js +89 -278
  15. package/dist/tools/sections.d.ts +1 -4
  16. package/dist/tools/sections.js +57 -191
  17. package/dist/tools/tasks.d.ts +1 -4
  18. package/dist/tools/tasks.js +179 -470
  19. package/dist/tools/utils.d.ts +1 -4
  20. package/dist/tools/utils.js +16 -33
  21. package/dist/tools.d.ts +6 -15
  22. package/dist/tools.js +6 -22
  23. package/dist/utils/TodoistClient.d.ts +2 -5
  24. package/dist/utils/handlers.d.ts +15 -7
  25. package/dist/utils/handlers.js +51 -19
  26. package/dist/utils/helpers.d.ts +0 -2
  27. package/dist/utils/helpers.js +0 -2
  28. package/dist/utils/types.d.ts +5 -10
  29. package/dist/utils/version.d.ts +1 -1
  30. package/dist/utils/version.js +2 -7
  31. package/package.json +3 -2
  32. package/dist/prompts/projects_list.d.ts +0 -6
  33. package/dist/prompts/projects_list.js +0 -23
  34. package/dist/tools/create_task.d.ts +0 -4
  35. package/dist/tools/create_task.js +0 -179
  36. package/dist/tools/example.d.ts +0 -14
  37. package/dist/tools/example.js +0 -99
  38. package/dist/tools/example.test.d.ts +0 -1
  39. package/dist/tools/example.test.js +0 -123
  40. package/dist/tools/get_tasks.d.ts +0 -4
  41. package/dist/tools/get_tasks.js +0 -92
  42. package/dist/tools/task_tools.d.ts +0 -4
  43. package/dist/tools/task_tools.js +0 -284
  44. package/dist/tools/tests/example_data.d.ts +0 -21
  45. package/dist/tools/tests/example_data.js +0 -65
  46. package/dist/tools/tests/get_tasks.test.d.ts +0 -1
  47. package/dist/tools/tests/get_tasks.test.js +0 -60
  48. package/dist/utils/TestClient.d.ts +0 -17
  49. package/dist/utils/TestClient.js +0 -23
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { TodoistClient } from './utils/TodoistClient.js';
3
+ export declare const todoistApi: TodoistClient;
4
+ export declare const server: McpServer;
@@ -0,0 +1,10 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { TodoistClient } from './utils/TodoistClient.js';
3
+ import { config, version } from './utils/helpers.js';
4
+ export const todoistApi = new TodoistClient(config.API_KEY);
5
+ export const server = new McpServer({
6
+ name: 'todoist-mcp',
7
+ version,
8
+ }, {
9
+ instructions: 'Use this server to interact with Todoist API',
10
+ });
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  #!/usr/bin/env node
2
+ import './prompts.js';
3
+ import './tools.js';
2
4
  export declare function main(): Promise<void>;
package/dist/index.js CHANGED
@@ -1,53 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
- import { ALL_PROMPT_HANDLERS, ALL_PROMPTS } from './prompts.js';
6
- import { ALL_HANDLERS, ALL_TOOLS } from './tools.js';
3
+ import { server } from './clients.js';
7
4
  import { config, log } from './utils/helpers.js';
8
- import { version } from './utils/version.js';
9
- const server = new Server({
10
- name: 'todoist-mcp',
11
- version,
12
- }, { capabilities: { tools: {}, prompts: {} } });
13
- server.setRequestHandler(ListToolsRequestSchema, async () => {
14
- return { tools: ALL_TOOLS };
15
- });
16
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
17
- return { prompts: ALL_PROMPTS };
18
- });
19
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
20
- const toolName = request.params.name;
21
- log('Tool call: ', toolName);
22
- try {
23
- const handler = ALL_HANDLERS[toolName];
24
- if (!handler) {
25
- throw new Error(`Unknown tool: ${toolName}`);
26
- }
27
- return await handler(request);
28
- }
29
- catch (error) {
30
- log('Error handling tool call:', error);
31
- return {
32
- content: [
33
- {
34
- type: 'text',
35
- text: `Error: ${error instanceof Error ? error.message : String(error)}`,
36
- },
37
- ],
38
- isError: true,
39
- };
40
- }
41
- });
42
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
43
- const promptName = request.params.name;
44
- log('Prompt call: ', promptName);
45
- const handler = ALL_PROMPT_HANDLERS[promptName];
46
- if (!handler) {
47
- throw new Error(`Unknown prompt: ${promptName}`);
48
- }
49
- return await handler(request);
50
- });
5
+ import './prompts.js';
6
+ import './tools.js';
51
7
  export async function main() {
52
8
  if (!config.API_KEY || config.API_KEY.length === 0) {
53
9
  log('Missing required configuration: API_KEY');
@@ -1,6 +1,4 @@
1
- import { PromptHandlers } from '../utils/types.js';
2
1
  export declare const PROJECT_LIST_PROMPT: {
3
2
  name: string;
4
3
  description: string;
5
4
  };
6
- export declare const PROJECT_LIST_RPOMPT_HANDLER: PromptHandlers;
@@ -1,67 +1,65 @@
1
- import { todoistApi } from '../utils/helpers.js';
1
+ import { server, todoistApi } from '../clients.js';
2
2
  export const PROJECT_LIST_PROMPT = {
3
3
  name: 'projects_list',
4
4
  description: 'List of projects',
5
5
  };
6
- export const PROJECT_LIST_RPOMPT_HANDLER = {
7
- projects_list: async () => {
8
- const [projects, sections] = await Promise.all([
9
- todoistApi.get('/projects'),
10
- todoistApi.get('/sections'),
11
- ]);
12
- const sectionsByProject = sections.reduce((acc, section) => {
13
- acc[section.project_id] = acc[section.project_id] || [];
14
- acc[section.project_id].push(section);
15
- return acc;
16
- }, {});
17
- const markdownParts = [
18
- '# Todoist Projects Overview',
19
- '',
20
- `*Total Projects: ${projects.length}*`,
21
- '',
22
- ];
23
- projects.forEach((project) => {
24
- const projectSections = sectionsByProject[project.id] || [];
25
- markdownParts.push(`## ${project.name}`);
26
- markdownParts.push('| Property | Value |');
27
- markdownParts.push('| -------- | ----- |');
28
- markdownParts.push(`| ID | \`${project.id}\` |`);
29
- markdownParts.push(`| Order | ${project.order} |`);
30
- markdownParts.push(`| Parent ID | ${project.parent_id || 'None'} |`);
31
- markdownParts.push(`| View Style | ${project.view_style} |`);
32
- if (project.is_inbox_project)
33
- markdownParts.push(`| Status | Inbox Project |`);
34
- if (project.is_shared)
35
- markdownParts.push(`| Sharing | Shared |`);
36
- // if (project.url) markdownParts.push(`| URL | [Open in Todoist](${project.url}) |`);
37
- if (project.description?.length > 0) {
38
- const truncatedDescription = project.description.length > 100
39
- ? `${project.description.substring(0, 100).split(' ').slice(0, -1).join(' ')}...`
40
- : project.description;
41
- markdownParts.push(`| Description | ${truncatedDescription} |`);
42
- }
43
- markdownParts.push('');
44
- if (projectSections.length > 0) {
45
- markdownParts.push(`### Sections (${projectSections.length})`);
46
- projectSections.forEach(section => {
47
- markdownParts.push(`- **${section.name}** (ID: \`${section.id}\`)`);
48
- });
49
- }
50
- else {
51
- markdownParts.push('### Sections\n*No sections found*');
52
- }
53
- markdownParts.push('');
54
- });
55
- return {
56
- messages: [
57
- {
58
- role: 'user',
59
- content: {
60
- type: 'text',
61
- text: markdownParts.join('\n'),
62
- },
6
+ server.prompt(PROJECT_LIST_PROMPT.name, {}, async () => {
7
+ const [projects, sections] = await Promise.all([
8
+ todoistApi.get('/projects'),
9
+ todoistApi.get('/sections'),
10
+ ]);
11
+ const sectionsByProject = sections.reduce((acc, section) => {
12
+ acc[section.project_id] = acc[section.project_id] || [];
13
+ acc[section.project_id].push(section);
14
+ return acc;
15
+ }, {});
16
+ const markdownParts = [
17
+ '# Todoist Projects Overview',
18
+ '',
19
+ `*Total Projects: ${projects.length}*`,
20
+ '',
21
+ ];
22
+ projects.forEach((project) => {
23
+ const projectSections = sectionsByProject[project.id] || [];
24
+ markdownParts.push(`## ${project.name}`);
25
+ markdownParts.push('| Property | Value |');
26
+ markdownParts.push('| -------- | ----- |');
27
+ markdownParts.push(`| ID | \`${project.id}\` |`);
28
+ markdownParts.push(`| Order | ${project.order} |`);
29
+ markdownParts.push(`| Parent ID | ${project.parent_id || 'None'} |`);
30
+ markdownParts.push(`| View Style | ${project.view_style} |`);
31
+ if (project.is_inbox_project)
32
+ markdownParts.push(`| Status | Inbox Project |`);
33
+ if (project.is_shared)
34
+ markdownParts.push(`| Sharing | Shared |`);
35
+ // if (project.url) markdownParts.push(`| URL | [Open in Todoist](${project.url}) |`);
36
+ if (project.description?.length > 0) {
37
+ const truncatedDescription = project.description.length > 100
38
+ ? `${project.description.substring(0, 100).split(' ').slice(0, -1).join(' ')}...`
39
+ : project.description;
40
+ markdownParts.push(`| Description | ${truncatedDescription} |`);
41
+ }
42
+ markdownParts.push('');
43
+ if (projectSections.length > 0) {
44
+ markdownParts.push(`### Sections (${projectSections.length})`);
45
+ projectSections.forEach(section => {
46
+ markdownParts.push(`- **${section.name}** (ID: \`${section.id}\`)`);
47
+ });
48
+ }
49
+ else {
50
+ markdownParts.push('### Sections\n*No sections found*');
51
+ }
52
+ markdownParts.push('');
53
+ });
54
+ return {
55
+ messages: [
56
+ {
57
+ role: 'user',
58
+ content: {
59
+ type: 'text',
60
+ text: markdownParts.join('\n'),
63
61
  },
64
- ],
65
- };
66
- },
67
- };
62
+ },
63
+ ],
64
+ };
65
+ });
package/dist/prompts.d.ts CHANGED
@@ -1,7 +1 @@
1
- export declare const ALL_PROMPTS: {
2
- name: string;
3
- description: string;
4
- }[];
5
- export declare const ALL_PROMPT_HANDLERS: {
6
- [x: string]: (request: import("zod").TypeOf<typeof import("@modelcontextprotocol/sdk/types.js").GetPromptRequestSchema>) => Promise<import("./utils/types.js").PromptResult>;
7
- };
1
+ import './prompts/projects.js';
package/dist/prompts.js CHANGED
@@ -1,5 +1 @@
1
- import { PROJECT_LIST_PROMPT, PROJECT_LIST_RPOMPT_HANDLER } from './prompts/projects.js';
2
- export const ALL_PROMPTS = [PROJECT_LIST_PROMPT];
3
- export const ALL_PROMPT_HANDLERS = {
4
- ...PROJECT_LIST_RPOMPT_HANDLER,
5
- };
1
+ import './prompts/projects.js';
@@ -1,4 +1 @@
1
- import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
- import { ToolHandlers } from '../utils/types.js';
3
- export declare const COMMENTS_TOOLS: Tool[];
4
- export declare const COMMENT_HANDLERS: ToolHandlers;
1
+ export {};
@@ -1,190 +1,59 @@
1
- import z from 'zod';
1
+ import { z } from 'zod';
2
2
  import { createApiHandler, createBatchApiHandler } from '../utils/handlers.js';
3
- export const COMMENTS_TOOLS = [
4
- {
5
- name: 'get_comments_list',
6
- description: 'Get all comments from Todoist',
7
- inputSchema: {
8
- type: 'object',
9
- required: [],
10
- properties: {
11
- project_id: {
12
- type: 'string',
13
- description: 'ID of the project used to filter comments',
14
- },
15
- task_id: {
16
- type: 'string',
17
- description: 'ID of the task used to filter comments',
18
- },
19
- },
20
- anyOf: [{ required: ['project_id'] }, { required: ['task_id'] }],
21
- },
3
+ createApiHandler({
4
+ name: 'get_comments_list',
5
+ description: 'Get comments list from Todoist',
6
+ schemaShape: {
7
+ project_id: z.string().optional().describe('Filter by project'),
8
+ task_id: z.string().optional().describe('Filter by task'),
22
9
  },
23
- {
24
- name: 'create_comments',
25
- description: 'Create new comments in Todoist',
26
- inputSchema: {
27
- type: 'object',
28
- required: ['items'],
29
- properties: {
30
- items: {
31
- type: 'array',
32
- description: 'Array of comment objects to create',
33
- items: {
34
- type: 'object',
35
- required: ['content'],
36
- properties: {
37
- task_id: {
38
- type: 'string',
39
- description: "Comment's task ID (for task comments)",
40
- },
41
- project_id: {
42
- type: 'string',
43
- description: "Comment's project ID (for project comments)",
44
- },
45
- content: {
46
- type: 'string',
47
- description: 'Comment markdown-formatted text and hyperlinks',
48
- },
49
- // attachment: {
50
- // type: "object",
51
- // description: 'Object for attachment object'
52
- // }
53
- },
54
- anyOf: [{ required: ['task_id'] }, { required: ['project_id'] }],
55
- },
56
- },
57
- },
58
- },
10
+ method: 'GET',
11
+ path: '/comments',
12
+ });
13
+ createBatchApiHandler({
14
+ name: 'create_comments',
15
+ description: 'Create new comments in Todoist',
16
+ itemSchema: {
17
+ task_id: z.string().optional(),
18
+ project_id: z.string().optional(),
19
+ content: z.string().describe('Markdown-formatted text and hyperlinks'),
20
+ // attachment: z.object({}).optional(),
59
21
  },
60
- {
61
- name: 'get_comments',
62
- description: 'Get comments from Todoist by ID',
63
- inputSchema: {
64
- type: 'object',
65
- required: ['items'],
66
- properties: {
67
- items: {
68
- type: 'array',
69
- description: 'Array of comment identifiers to retrieve',
70
- items: {
71
- type: 'object',
72
- required: ['id'],
73
- properties: {
74
- id: {
75
- type: 'string',
76
- description: 'ID of the comment to retrieve',
77
- },
78
- },
79
- },
80
- },
81
- },
82
- },
22
+ method: 'POST',
23
+ path: '/comments',
24
+ mode: 'create',
25
+ });
26
+ createBatchApiHandler({
27
+ name: 'get_comments',
28
+ description: 'Get comments from Todoist by ID',
29
+ itemSchema: {
30
+ id: z.string(),
83
31
  },
84
- {
85
- name: 'update_comments',
86
- description: 'Update comments in Todoist',
87
- inputSchema: {
88
- type: 'object',
89
- required: ['items'],
90
- properties: {
91
- items: {
92
- type: 'array',
93
- description: 'Array of comment objects to update',
94
- items: {
95
- type: 'object',
96
- required: ['id', 'content'],
97
- properties: {
98
- id: {
99
- type: 'string',
100
- description: 'ID of the comment to update',
101
- },
102
- content: {
103
- type: 'string',
104
- description: 'New content, markdown-formatted text and hyperlinks',
105
- },
106
- },
107
- },
108
- },
109
- },
110
- },
32
+ method: 'GET',
33
+ path: '/comments/{id}',
34
+ mode: 'read',
35
+ idField: 'id',
36
+ });
37
+ createBatchApiHandler({
38
+ name: 'update_comments',
39
+ description: 'Update comments in Todoist',
40
+ itemSchema: {
41
+ id: z.string(),
42
+ content: z.string().describe('Markdown-formatted text and hyperlinks'),
111
43
  },
112
- {
113
- name: 'delete_comments',
114
- description: 'Delete comments in Todoist',
115
- inputSchema: {
116
- type: 'object',
117
- required: ['items'],
118
- properties: {
119
- items: {
120
- type: 'array',
121
- description: 'Array of comments to delete',
122
- items: {
123
- type: 'object',
124
- required: ['id'],
125
- properties: {
126
- id: {
127
- type: 'string',
128
- description: 'ID of the comment to delete',
129
- },
130
- },
131
- },
132
- },
133
- },
134
- },
44
+ method: 'POST',
45
+ path: '/comments/{id}',
46
+ mode: 'update',
47
+ idField: 'id',
48
+ });
49
+ createBatchApiHandler({
50
+ name: 'delete_comments',
51
+ description: 'Delete comments in Todoist',
52
+ itemSchema: {
53
+ id: z.string(),
135
54
  },
136
- ];
137
- export const COMMENT_HANDLERS = {
138
- get_comments_list: createApiHandler({
139
- schemaShape: {
140
- project_id: z.string().optional(),
141
- task_id: z.string().optional(),
142
- },
143
- method: 'GET',
144
- path: '/comments',
145
- errorPrefix: 'Failed to get comments',
146
- }),
147
- create_comments: createBatchApiHandler({
148
- itemSchema: {
149
- task_id: z.string().optional(),
150
- project_id: z.string().optional(),
151
- content: z.string(),
152
- // attachment: z.object({}).optional(),
153
- },
154
- method: 'POST',
155
- path: '/comments',
156
- errorPrefix: 'Failed to create comments',
157
- mode: 'create',
158
- }),
159
- get_comments: createBatchApiHandler({
160
- itemSchema: {
161
- id: z.string(),
162
- },
163
- method: 'GET',
164
- path: '/comments/{id}',
165
- errorPrefix: 'Failed to get comments',
166
- mode: 'read',
167
- idField: 'id',
168
- }),
169
- update_comments: createBatchApiHandler({
170
- itemSchema: {
171
- id: z.string(),
172
- content: z.string(),
173
- },
174
- method: 'POST',
175
- path: '/comments/{id}',
176
- errorPrefix: 'Failed to update comments',
177
- mode: 'update',
178
- idField: 'id',
179
- }),
180
- delete_comments: createBatchApiHandler({
181
- itemSchema: {
182
- id: z.string(),
183
- },
184
- method: 'DELETE',
185
- path: '/comments/{id}',
186
- idField: 'id',
187
- errorPrefix: 'Failed to delete comments',
188
- mode: 'delete',
189
- }),
190
- };
55
+ method: 'DELETE',
56
+ path: '/comments/{id}',
57
+ idField: 'id',
58
+ mode: 'delete',
59
+ });
@@ -1,4 +1 @@
1
- import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
- import { ToolHandlers } from '../utils/types.js';
3
- export declare const LABELS_TOOLS: Tool[];
4
- export declare const LABEL_HANDLERS: ToolHandlers;
1
+ export {};