todoist-mcp 1.3.2 → 1.3.4

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/README.md CHANGED
@@ -20,6 +20,7 @@
20
20
  - **Projects**: Create and manage projects and sections
21
21
  - **Comments**: Add and manage comments on tasks and projects
22
22
  - **Labels**: Create and manage personal and shared labels
23
+ - **Smart Context**: On startup, automatically provides your projects and labels to the AI via server instructions — no extra tool calls needed
23
24
  - **Prompt Support**: You can easily provide information about your projects to client
24
25
 
25
26
  ## Configuration
@@ -73,7 +74,8 @@ API_KEY = "your_todoist_api_token"
73
74
 
74
75
  ### Tasks
75
76
 
76
- - `get_tasks_list`: Get tasks with optional filtering by project, section, label, etc.
77
+ - `get_tasks_list`: Get tasks with optional filtering by project, section, label, or IDs
78
+ - `get_tasks_by_filter`: Get tasks using Todoist filter language (e.g. `"today"`, `"overdue"`, `"P1 | P2"`, `"#Work & @urgent"`)
77
79
  - `create_tasks`: Create new tasks with various attributes
78
80
  - `get_tasks`: Get specific tasks by ID or name
79
81
  - `update_tasks`: Update existing tasks
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { server } from './clients.js';
4
4
  import { config, log } from './utils/helpers.js';
5
+ import { buildInstructions } from './utils/instructions.js';
5
6
  import './prompts.js';
6
7
  import './tools.js';
7
8
  export async function main() {
@@ -10,6 +11,8 @@ export async function main() {
10
11
  process.exit(1);
11
12
  }
12
13
  try {
14
+ server.server._instructions =
15
+ await buildInstructions();
13
16
  const transport = new StdioServerTransport();
14
17
  await server.connect(transport);
15
18
  process.stdin.resume();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+ import { todoistApi } from '../clients.js';
3
+ import { createHandler } from '../utils/handlers.js';
4
+ const VALID_RESOURCE_TYPES = [
5
+ 'labels',
6
+ 'projects',
7
+ 'items',
8
+ 'notes',
9
+ 'sections',
10
+ 'filters',
11
+ 'reminders',
12
+ 'locations',
13
+ 'user',
14
+ 'live_notifications',
15
+ 'collaborators',
16
+ 'user_settings',
17
+ 'notification_settings',
18
+ 'user_plan_limits',
19
+ 'completed_info',
20
+ 'stats',
21
+ 'workspaces',
22
+ 'workspace_users',
23
+ ];
24
+ createHandler('read_resources', `Read resources from the Todoist Sync API. Fetches one or more resource types in a single request. Available resource types: ${VALID_RESOURCE_TYPES.join(', ')}. Use sync_token '*' for a full sync, or pass a previously returned sync_token for incremental updates.`, {
25
+ resource_types: z
26
+ .array(z.string())
27
+ .min(1)
28
+ .describe(`Array of resource types to fetch. Valid types: ${VALID_RESOURCE_TYPES.join(', ')}`),
29
+ sync_token: z
30
+ .string()
31
+ .optional()
32
+ .default('*')
33
+ .describe('Sync token for incremental sync. Use "*" for full sync (default)'),
34
+ }, async (args) => {
35
+ return todoistApi.readResources(args.resource_types, args.sync_token);
36
+ });
@@ -12,7 +12,13 @@ const create_fields = {
12
12
  .optional()
13
13
  .describe('Description (detailed). May contain markdown-formatted text and hyperlinks'),
14
14
  labels: z.array(z.string()).optional(),
15
- priority: z.number().int().min(1).max(4).optional().describe('From 1 (urgent) to 4 (normal)'),
15
+ priority: z
16
+ .number()
17
+ .int()
18
+ .min(1)
19
+ .max(4)
20
+ .optional()
21
+ .describe('Todoist API priority (1-4): pass 4 when the user says "P1" or "highest priority", and pass 1 for "P4" or lowest priority'),
16
22
  due_string: z
17
23
  .string()
18
24
  .optional()
@@ -49,7 +49,7 @@ export function createHandler(name, description, paramsSchema, handler) {
49
49
  };
50
50
  }
51
51
  };
52
- // Crazy cast, if you can do it better, please, let me knows
52
+ // Cast needed: SDK uses Zod 4 types internally, project uses Zod 3
53
53
  server.tool(name, description, paramsSchema, mcpToolCallback);
54
54
  }
55
55
  export function createApiHandler(options) {
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Fetches user context (projects, labels) and builds dynamic server instructions
3
+ */
4
+ export declare function buildInstructions(): Promise<string>;
@@ -0,0 +1,49 @@
1
+ import { todoistApi } from '../clients.js';
2
+ import { log } from './helpers.js';
3
+ const HEADER = 'Use this server to interact with Todoist API.';
4
+ const PREVIEW_LIMIT = 20;
5
+ const NOTES = [
6
+ 'Notes:',
7
+ '- Todoist API priority is inverted: P1 (urgent) = 4, P2 = 3, P3 = 2, P4 (normal) = 1',
8
+ ].join('\n');
9
+ /**
10
+ * Truncates a list and appends "(+N more)" if it exceeds the limit
11
+ */
12
+ function truncateList(items) {
13
+ const visible = items.slice(0, PREVIEW_LIMIT);
14
+ const remaining = items.length - visible.length;
15
+ const result = visible.join(', ');
16
+ return remaining > 0 ? `${result} (+${remaining} more)` : result;
17
+ }
18
+ /**
19
+ * Fetches user context (projects, labels) and builds dynamic server instructions
20
+ */
21
+ export async function buildInstructions() {
22
+ try {
23
+ const [projects, personalLabels, sharedLabels] = await Promise.all([
24
+ todoistApi.get('/projects', {}),
25
+ todoistApi.get('/labels', {}),
26
+ todoistApi.get('/labels/shared', {}),
27
+ ]);
28
+ const parts = [HEADER];
29
+ if (Array.isArray(projects) && projects.length > 0) {
30
+ const projectList = projects
31
+ .map((p) => `- ${p.name} (id: ${p.id})`)
32
+ .join('\n');
33
+ parts.push(`\nUser projects:\n${projectList}`);
34
+ }
35
+ if (Array.isArray(personalLabels) && personalLabels.length > 0) {
36
+ const names = personalLabels.map((l) => l.name);
37
+ parts.push(`\nPersonal labels: ${truncateList(names)}`);
38
+ }
39
+ if (Array.isArray(sharedLabels) && sharedLabels.length > 0) {
40
+ parts.push(`\nShared labels: ${truncateList(sharedLabels)}`);
41
+ }
42
+ parts.push(`\n${NOTES}`);
43
+ return parts.join('');
44
+ }
45
+ catch (error) {
46
+ log('Failed to fetch user context for instructions:', error);
47
+ return `${HEADER}\n\n${NOTES}`;
48
+ }
49
+ }
@@ -1,6 +1,5 @@
1
- import { CallToolRequestSchema, Result } from '@modelcontextprotocol/sdk/types.js';
2
- import z from 'zod';
3
- export type ToolHandlers = Record<string, (request: z.infer<typeof CallToolRequestSchema>) => Promise<Result>>;
1
+ import { CallToolRequest, Result } from '@modelcontextprotocol/sdk/types.js';
2
+ export type ToolHandlers = Record<string, (request: CallToolRequest) => Promise<Result>>;
4
3
  export type ToolResult = {
5
4
  content: Array<{
6
5
  type: string;
@@ -1 +1 @@
1
- export declare const version = "1.3.2";
1
+ export declare const version = "1.3.4";
@@ -1,2 +1,2 @@
1
1
  // Auto-generated file, do not edit
2
- export const version = '1.3.2';
2
+ export const version = '1.3.4';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "todoist-mcp",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Todoist MCP Server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",