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.
- package/dist/clients.d.ts +4 -0
- package/dist/clients.js +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -47
- package/dist/prompts/projects.d.ts +0 -2
- package/dist/prompts/projects.js +60 -62
- package/dist/prompts.d.ts +1 -7
- package/dist/prompts.js +1 -5
- package/dist/tools/comments.d.ts +1 -4
- package/dist/tools/comments.js +53 -184
- package/dist/tools/labels.d.ts +1 -4
- package/dist/tools/labels.js +92 -284
- package/dist/tools/projects.d.ts +1 -4
- package/dist/tools/projects.js +89 -278
- package/dist/tools/sections.d.ts +1 -4
- package/dist/tools/sections.js +57 -191
- package/dist/tools/tasks.d.ts +1 -4
- package/dist/tools/tasks.js +179 -470
- package/dist/tools/utils.d.ts +1 -4
- package/dist/tools/utils.js +16 -33
- package/dist/tools.d.ts +6 -15
- package/dist/tools.js +6 -22
- package/dist/utils/TodoistClient.d.ts +2 -5
- package/dist/utils/handlers.d.ts +15 -7
- package/dist/utils/handlers.js +51 -19
- package/dist/utils/helpers.d.ts +0 -2
- package/dist/utils/helpers.js +0 -2
- package/dist/utils/types.d.ts +5 -10
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.js +2 -7
- package/package.json +3 -2
- package/dist/prompts/projects_list.d.ts +0 -6
- package/dist/prompts/projects_list.js +0 -23
- package/dist/tools/create_task.d.ts +0 -4
- package/dist/tools/create_task.js +0 -179
- package/dist/tools/example.d.ts +0 -14
- package/dist/tools/example.js +0 -99
- package/dist/tools/example.test.d.ts +0 -1
- package/dist/tools/example.test.js +0 -123
- package/dist/tools/get_tasks.d.ts +0 -4
- package/dist/tools/get_tasks.js +0 -92
- package/dist/tools/task_tools.d.ts +0 -4
- package/dist/tools/task_tools.js +0 -284
- package/dist/tools/tests/example_data.d.ts +0 -21
- package/dist/tools/tests/example_data.js +0 -65
- package/dist/tools/tests/get_tasks.test.d.ts +0 -1
- package/dist/tools/tests/get_tasks.test.js +0 -60
- package/dist/utils/TestClient.d.ts +0 -17
- package/dist/utils/TestClient.js +0 -23
package/dist/clients.js
ADDED
|
@@ -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
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 {
|
|
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
|
|
9
|
-
|
|
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');
|
package/dist/prompts/projects.js
CHANGED
|
@@ -1,67 +1,65 @@
|
|
|
1
|
-
import { todoistApi } from '../
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
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
package/dist/tools/comments.d.ts
CHANGED
package/dist/tools/comments.js
CHANGED
|
@@ -1,190 +1,59 @@
|
|
|
1
|
-
import z from 'zod';
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
import { createApiHandler, createBatchApiHandler } from '../utils/handlers.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
+
});
|
package/dist/tools/labels.d.ts
CHANGED