@doist/todoist-ai 0.1.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 (119) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +93 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/main.d.ts +2 -0
  7. package/dist/main.d.ts.map +1 -0
  8. package/dist/main.js +23 -0
  9. package/dist/mcp-helpers.d.ts +13 -0
  10. package/dist/mcp-helpers.d.ts.map +1 -0
  11. package/dist/mcp-helpers.js +52 -0
  12. package/dist/mcp-server.d.ts +11 -0
  13. package/dist/mcp-server.d.ts.map +1 -0
  14. package/dist/mcp-server.js +66 -0
  15. package/dist/todoist-tool.d.ts +35 -0
  16. package/dist/todoist-tool.d.ts.map +1 -0
  17. package/dist/todoist-tool.js +1 -0
  18. package/dist/tools/account-overview.d.ts +9 -0
  19. package/dist/tools/account-overview.d.ts.map +1 -0
  20. package/dist/tools/account-overview.js +94 -0
  21. package/dist/tools/index.d.ts +23 -0
  22. package/dist/tools/index.d.ts.map +1 -0
  23. package/dist/tools/index.js +22 -0
  24. package/dist/tools/project-overview.d.ts +14 -0
  25. package/dist/tools/project-overview.d.ts.map +1 -0
  26. package/dist/tools/project-overview.js +107 -0
  27. package/dist/tools/projects-add-one.d.ts +22 -0
  28. package/dist/tools/projects-add-one.d.ts.map +1 -0
  29. package/dist/tools/projects-add-one.js +15 -0
  30. package/dist/tools/projects-delete-one.d.ts +15 -0
  31. package/dist/tools/projects-delete-one.d.ts.map +1 -0
  32. package/dist/tools/projects-delete-one.js +14 -0
  33. package/dist/tools/projects-list.d.ts +18 -0
  34. package/dist/tools/projects-list.d.ts.map +1 -0
  35. package/dist/tools/projects-list.js +30 -0
  36. package/dist/tools/projects-search.d.ts +29 -0
  37. package/dist/tools/projects-search.d.ts.map +1 -0
  38. package/dist/tools/projects-search.js +39 -0
  39. package/dist/tools/projects-update-one.d.ts +15 -0
  40. package/dist/tools/projects-update-one.d.ts.map +1 -0
  41. package/dist/tools/projects-update-one.js +16 -0
  42. package/dist/tools/sections-add-one.d.ts +15 -0
  43. package/dist/tools/sections-add-one.d.ts.map +1 -0
  44. package/dist/tools/sections-add-one.js +21 -0
  45. package/dist/tools/sections-delete-one.d.ts +15 -0
  46. package/dist/tools/sections-delete-one.d.ts.map +1 -0
  47. package/dist/tools/sections-delete-one.js +14 -0
  48. package/dist/tools/sections-search.d.ts +18 -0
  49. package/dist/tools/sections-search.d.ts.map +1 -0
  50. package/dist/tools/sections-search.js +30 -0
  51. package/dist/tools/sections-update-one.d.ts +15 -0
  52. package/dist/tools/sections-update-one.d.ts.map +1 -0
  53. package/dist/tools/sections-update-one.js +16 -0
  54. package/dist/tools/shared.d.ts +55 -0
  55. package/dist/tools/shared.d.ts.map +1 -0
  56. package/dist/tools/shared.js +71 -0
  57. package/dist/tools/subtasks-list-for-parent-task.d.ts +31 -0
  58. package/dist/tools/subtasks-list-for-parent-task.d.ts.map +1 -0
  59. package/dist/tools/subtasks-list-for-parent-task.js +37 -0
  60. package/dist/tools/tasks-add-multiple.d.ts +50 -0
  61. package/dist/tools/tasks-add-multiple.d.ts.map +1 -0
  62. package/dist/tools/tasks-add-multiple.js +47 -0
  63. package/dist/tools/tasks-by-date-range.d.ts +33 -0
  64. package/dist/tools/tasks-by-date-range.d.ts.map +1 -0
  65. package/dist/tools/tasks-by-date-range.js +47 -0
  66. package/dist/tools/tasks-by-project.d.ts +31 -0
  67. package/dist/tools/tasks-by-project.d.ts.map +1 -0
  68. package/dist/tools/tasks-by-project.js +37 -0
  69. package/dist/tools/tasks-complete-multiple.d.ts +16 -0
  70. package/dist/tools/tasks-complete-multiple.d.ts.map +1 -0
  71. package/dist/tools/tasks-complete-multiple.js +26 -0
  72. package/dist/tools/tasks-delete-one.d.ts +15 -0
  73. package/dist/tools/tasks-delete-one.d.ts.map +1 -0
  74. package/dist/tools/tasks-delete-one.js +14 -0
  75. package/dist/tools/tasks-list-for-section.d.ts +31 -0
  76. package/dist/tools/tasks-list-for-section.d.ts.map +1 -0
  77. package/dist/tools/tasks-list-for-section.js +37 -0
  78. package/dist/tools/tasks-list-overdue.d.ts +29 -0
  79. package/dist/tools/tasks-list-overdue.d.ts.map +1 -0
  80. package/dist/tools/tasks-list-overdue.js +29 -0
  81. package/dist/tools/tasks-organize-multiple.d.ts +37 -0
  82. package/dist/tools/tasks-organize-multiple.d.ts.map +1 -0
  83. package/dist/tools/tasks-organize-multiple.js +40 -0
  84. package/dist/tools/tasks-search.d.ts +31 -0
  85. package/dist/tools/tasks-search.d.ts.map +1 -0
  86. package/dist/tools/tasks-search.js +30 -0
  87. package/dist/tools/tasks-update-one.d.ts +27 -0
  88. package/dist/tools/tasks-update-one.d.ts.map +1 -0
  89. package/dist/tools/tasks-update-one.js +42 -0
  90. package/package.json +60 -0
  91. package/src/index.ts +1 -0
  92. package/src/main.ts +26 -0
  93. package/src/mcp-helpers.ts +76 -0
  94. package/src/mcp-server.ts +79 -0
  95. package/src/todoist-tool.ts +42 -0
  96. package/src/tools/account-overview.ts +130 -0
  97. package/src/tools/index.ts +26 -0
  98. package/src/tools/project-overview.ts +130 -0
  99. package/src/tools/projects-add-one.ts +19 -0
  100. package/src/tools/projects-delete-one.ts +18 -0
  101. package/src/tools/projects-list.ts +36 -0
  102. package/src/tools/projects-search.ts +49 -0
  103. package/src/tools/projects-update-one.ts +20 -0
  104. package/src/tools/sections-add-one.ts +25 -0
  105. package/src/tools/sections-delete-one.ts +18 -0
  106. package/src/tools/sections-search.ts +39 -0
  107. package/src/tools/sections-update-one.ts +20 -0
  108. package/src/tools/shared.ts +94 -0
  109. package/src/tools/subtasks-list-for-parent-task.ts +43 -0
  110. package/src/tools/tasks-add-multiple.ts +53 -0
  111. package/src/tools/tasks-by-date-range.ts +58 -0
  112. package/src/tools/tasks-by-project.ts +43 -0
  113. package/src/tools/tasks-complete-multiple.ts +29 -0
  114. package/src/tools/tasks-delete-one.ts +18 -0
  115. package/src/tools/tasks-list-for-section.ts +43 -0
  116. package/src/tools/tasks-list-overdue.ts +35 -0
  117. package/src/tools/tasks-organize-multiple.ts +45 -0
  118. package/src/tools/tasks-search.ts +36 -0
  119. package/src/tools/tasks-update-one.ts +48 -0
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ernesto García
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Todoist AI SDK
2
+
3
+ Library for connecting AI agents to Todoist. Includes tools that can be integrated into LLMs,
4
+ enabling them to access and modify a Todoist account on the user's behalf.
5
+
6
+ These tools can be used both through an MCP server, or imported directly in other projects to
7
+ integrate them to your own AI conversational interfaces.
8
+
9
+ ## Using tools
10
+
11
+ ### 1. Add this repository as a dependency
12
+
13
+ ```sh
14
+ npm install @doist/todoist-ai
15
+ ```
16
+
17
+ ### 2. Import the tools and plug them to an AI
18
+
19
+ Here's an example using [Vercel's AI SDK](https://ai-sdk.dev/docs/ai-sdk-core/generating-text#streamtext).
20
+
21
+ ```js
22
+ import { tasksListByDate, tasksAddMultiple } from "@doist/todoist-ai/tools";
23
+ import { streamText } from "ai";
24
+
25
+ const result = streamText({
26
+ model: yourModel,
27
+ system: "You are a helpful Todoist assistant",
28
+ tools: {
29
+ tasksListByDate,
30
+ tasksAddMultiple,
31
+ },
32
+ });
33
+ ```
34
+
35
+ ## Using as an MCP server
36
+
37
+ For convenience, we already include a function that initializes an MCP Server with all the tools available:
38
+
39
+ ```js
40
+ import { getMcpServer } from "@doist/todoist-ai";
41
+
42
+ async function main() {
43
+ const server = getMcpServer({ todoistApiKey: process.env.TODOIST_API_KEY });
44
+ const transport = new StdioServerTransport();
45
+ await server.connect(transport);
46
+ }
47
+ ```
48
+
49
+ ## Features
50
+
51
+ A key feature of this project is that tools can be reused, and are not written specifically for use in an MCP server. They can be hooked up as tools to other conversational AI interfaces (e.g. Vercel's AI SDK).
52
+
53
+ This project is in its early stages. Expect more and/or better tools soon.
54
+
55
+ Nevertheless, our goal is to provide a small set of tools that enable complete workflows, rather than just atomic actions, striking a balance between flexibility and efficiency for LLMs.
56
+
57
+ ### Available Tools
58
+
59
+ - **account-overview**: Get a Markdown overview of all projects (with hierarchy and sections) and the inbox project.
60
+ - **project-overview**: Get a Markdown overview of a single project, including its sections and all tasks. Tasks are grouped by section, with tasks not in any section listed first.
61
+ - **projects-list**: List all projects for the user.
62
+ - **projects-search**: Search for projects by name or other criteria.
63
+ - **projects-add-one**: Add a new project.
64
+ - **projects-update-one**: Update a project's name by its ID.
65
+ - **projects-delete-one**: Delete a project by its ID.
66
+ - **sections-search**: Search for sections by name or other criteria in a project.
67
+ - **sections-add-one**: Add a new section to a project.
68
+ - **sections-update-one**: Update a section's name by its ID.
69
+ - **sections-delete-one**: Delete a section by its ID.
70
+ - **tasks-list-by-date**: Get tasks by date range.
71
+ - **tasks-list-overdue**: Get overdue tasks.
72
+ - **tasks-list-for-project**: Get tasks by project ID.
73
+ - **tasks-list-for-section**: List tasks for a given section.
74
+ - **tasks-search**: Search tasks by text using Todoist's filter query.
75
+ - **tasks-add-multiple**: Add one or more tasks to a project, section, or parent.
76
+ - **tasks-update-one**: Update an existing task with new values.
77
+ - **tasks-delete-one**: Delete a task by its ID.
78
+ - **tasks-complete-multiple**: Complete one or multiple tasks by ID.
79
+ - **tasks-organize-multiple**: Organize multiple tasks (move, reorder, etc.) in bulk.
80
+ - **subtasks-list-for-parent-task**: List subtasks for a given parent task.
81
+
82
+ ## Dependencies
83
+
84
+ - MCP server using the official [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#installation)
85
+ - Todoist Typescript API client [@doist/todoist-api-typescript](https://github.com/Doist/todoist-api-typescript)
86
+
87
+ ## MCP Server Setup
88
+
89
+ See [docs/mcp-server.md](docs/mcp-server.md) for full instructions on setting up the MCP server.
90
+
91
+ ## Local Development Setup
92
+
93
+ See [docs/dev-setup.md](docs/dev-setup.md) for full instructions on setting up this repository locally for development and contributing.
@@ -0,0 +1,2 @@
1
+ export { getMcpServer } from "./mcp-server.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { getMcpServer } from "./mcp-server.js";
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
package/dist/main.js ADDED
@@ -0,0 +1,23 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import dotenv from "dotenv";
3
+ import { getMcpServer } from "./mcp-server.js";
4
+ function main() {
5
+ const todoistApiKey = process.env.TODOIST_API_KEY;
6
+ if (!todoistApiKey) {
7
+ throw new Error("TODOIST_API_KEY is not set");
8
+ }
9
+ const server = getMcpServer({ todoistApiKey });
10
+ const transport = new StdioServerTransport();
11
+ server
12
+ .connect(transport)
13
+ .then(() => {
14
+ // We use console.error because standard I/O is being used for the MCP server communication.
15
+ console.error("Server started");
16
+ })
17
+ .catch((error) => {
18
+ console.error("Error starting the Todoist MCP server:", error);
19
+ process.exit(1);
20
+ });
21
+ }
22
+ dotenv.config();
23
+ main();
@@ -0,0 +1,13 @@
1
+ import type { TodoistApi } from "@doist/todoist-api-typescript";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import type { z } from "zod";
4
+ import type { TodoistTool } from "./todoist-tool.js";
5
+ /**
6
+ * Register a Todoist tool in an MCP server.
7
+ * @param tool - The tool to register.
8
+ * @param server - The server to register the tool on.
9
+ * @param client - The Todoist API client to use to execute the tool.
10
+ */
11
+ declare function registerTool<Params extends z.ZodRawShape>(tool: TodoistTool<Params>, server: McpServer, client: TodoistApi): void;
12
+ export { registerTool };
13
+ //# sourceMappingURL=mcp-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-helpers.d.ts","sourceRoot":"","sources":["../src/mcp-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EACX,SAAS,EAET,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAc,CAAC,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA+BrD;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,MAAM,SAAS,CAAC,CAAC,WAAW,EACjD,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EACzB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,QA2BlB;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,52 @@
1
+ function textContent(text) {
2
+ return {
3
+ content: [{ type: "text", text }],
4
+ };
5
+ }
6
+ function jsonContent(data) {
7
+ return {
8
+ content: [
9
+ {
10
+ type: "text",
11
+ mimeType: "application/json",
12
+ text: JSON.stringify(data, null, 2),
13
+ },
14
+ ],
15
+ };
16
+ }
17
+ function textOrJsonContent(data) {
18
+ return typeof data === "string" ? textContent(data) : jsonContent(data);
19
+ }
20
+ function errorContent(error) {
21
+ return {
22
+ ...textContent(error),
23
+ isError: true,
24
+ };
25
+ }
26
+ /**
27
+ * Register a Todoist tool in an MCP server.
28
+ * @param tool - The tool to register.
29
+ * @param server - The server to register the tool on.
30
+ * @param client - The Todoist API client to use to execute the tool.
31
+ */
32
+ function registerTool(tool, server, client) {
33
+ // @ts-ignore I give up
34
+ const cb = async (args, _context) => {
35
+ try {
36
+ const result = await tool.execute(args, client);
37
+ return textOrJsonContent(result);
38
+ }
39
+ catch (error) {
40
+ console.error(`Error executing tool ${tool.name}:`, {
41
+ args,
42
+ error,
43
+ });
44
+ const message = error instanceof Error
45
+ ? error.message
46
+ : "An unknown error occurred";
47
+ return errorContent(message);
48
+ }
49
+ };
50
+ server.tool(tool.name, tool.description, tool.parameters, cb);
51
+ }
52
+ export { registerTool };
@@ -0,0 +1,11 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * Create the MCP server.
4
+ * @param todoistApiKey - The API key for the todoist account.
5
+ * @returns the MCP server.
6
+ */
7
+ declare function getMcpServer({ todoistApiKey }: {
8
+ todoistApiKey: string;
9
+ }): McpServer;
10
+ export { getMcpServer };
11
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCpE;;;;GAIG;AACH,iBAAS,YAAY,CAAC,EAAE,aAAa,EAAE,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,aAqCjE;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,66 @@
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 { projectsAddOne } from "./tools/projects-add-one.js";
5
+ import { projectsDeleteOne } from "./tools/projects-delete-one.js";
6
+ import { projectsList } from "./tools/projects-list.js";
7
+ import { projectsSearch } from "./tools/projects-search.js";
8
+ import { projectsUpdateOne } from "./tools/projects-update-one.js";
9
+ import { sectionsAddOne } from "./tools/sections-add-one.js";
10
+ import { sectionsDeleteOne } from "./tools/sections-delete-one.js";
11
+ import { sectionsSearch } from "./tools/sections-search.js";
12
+ import { sectionsUpdateOne } from "./tools/sections-update-one.js";
13
+ import { subtasksListForParentTask } from "./tools/subtasks-list-for-parent-task.js";
14
+ import { accountOverview } from "./tools/account-overview.js";
15
+ import { projectOverview } from "./tools/project-overview.js";
16
+ import { tasksAddMultiple } from "./tools/tasks-add-multiple.js";
17
+ import { tasksListByDate } from "./tools/tasks-by-date-range.js";
18
+ import { tasksListForProject } from "./tools/tasks-by-project.js";
19
+ import { tasksCompleteMultiple } from "./tools/tasks-complete-multiple.js";
20
+ import { tasksDeleteOne } from "./tools/tasks-delete-one.js";
21
+ import { tasksListForSection } from "./tools/tasks-list-for-section.js";
22
+ import { tasksListOverdue } from "./tools/tasks-list-overdue.js";
23
+ import { tasksOrganizeMultiple } from "./tools/tasks-organize-multiple.js";
24
+ import { tasksSearch } from "./tools/tasks-search.js";
25
+ import { tasksUpdateOne } from "./tools/tasks-update-one.js";
26
+ const instructions = `
27
+ Tools to help you manage your todoist tasks.
28
+ `;
29
+ /**
30
+ * Create the MCP server.
31
+ * @param todoistApiKey - The API key for the todoist account.
32
+ * @returns the MCP server.
33
+ */
34
+ function getMcpServer({ todoistApiKey }) {
35
+ const server = new McpServer({ name: "todoist-mcp-server", version: "0.1.0" }, {
36
+ capabilities: {
37
+ tools: { listChanged: true },
38
+ },
39
+ instructions,
40
+ });
41
+ const todoist = new TodoistApi(todoistApiKey);
42
+ registerTool(tasksListByDate, server, todoist);
43
+ registerTool(tasksListOverdue, server, todoist);
44
+ registerTool(tasksListForProject, server, todoist);
45
+ registerTool(tasksSearch, server, todoist);
46
+ registerTool(projectsList, server, todoist);
47
+ registerTool(tasksAddMultiple, server, todoist);
48
+ registerTool(tasksUpdateOne, server, todoist);
49
+ registerTool(tasksDeleteOne, server, todoist);
50
+ registerTool(tasksCompleteMultiple, server, todoist);
51
+ registerTool(projectsAddOne, server, todoist);
52
+ registerTool(projectsUpdateOne, server, todoist);
53
+ registerTool(sectionsAddOne, server, todoist);
54
+ registerTool(sectionsUpdateOne, server, todoist);
55
+ registerTool(tasksOrganizeMultiple, server, todoist);
56
+ registerTool(subtasksListForParentTask, server, todoist);
57
+ registerTool(tasksListForSection, server, todoist);
58
+ registerTool(projectsDeleteOne, server, todoist);
59
+ registerTool(projectsSearch, server, todoist);
60
+ registerTool(sectionsDeleteOne, server, todoist);
61
+ registerTool(sectionsSearch, server, todoist);
62
+ registerTool(accountOverview, server, todoist);
63
+ registerTool(projectOverview, server, todoist);
64
+ return server;
65
+ }
66
+ export { getMcpServer };
@@ -0,0 +1,35 @@
1
+ import type { TodoistApi } from "@doist/todoist-api-typescript";
2
+ import type { z } from "zod";
3
+ /**
4
+ * A Todoist tool that can be used in an MCP server or other conversational AI interfaces.
5
+ */
6
+ type TodoistTool<Params extends z.ZodRawShape> = {
7
+ /**
8
+ * The name of the tool.
9
+ */
10
+ name: string;
11
+ /**
12
+ * The description of the tool. This is important for the LLM to understand what the tool does,
13
+ * and how to use it.
14
+ */
15
+ description: string;
16
+ /**
17
+ * The schema of the parameters of the tool.
18
+ *
19
+ * This is used to validate the parameters of the tool, as well as to let the LLM know what the
20
+ * parameters are.
21
+ */
22
+ parameters: Params;
23
+ /**
24
+ * The function that executes the tool.
25
+ *
26
+ * This is the main function that will be called when the tool is used.
27
+ *
28
+ * @param args - The arguments of the tool.
29
+ * @param client - The Todoist API client used to make requests to the Todoist API.
30
+ * @returns The result of the tool.
31
+ */
32
+ execute: (args: z.infer<z.ZodObject<Params>>, client: TodoistApi) => Promise<unknown>;
33
+ };
34
+ export type { TodoistTool };
35
+ //# sourceMappingURL=todoist-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todoist-tool.d.ts","sourceRoot":"","sources":["../src/todoist-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;GAEG;AACH,KAAK,WAAW,CAAC,MAAM,SAAS,CAAC,CAAC,WAAW,IAAI;IAChD;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;;;;;OAQG;IACH,OAAO,EAAE,CACR,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAClC,MAAM,EAAE,UAAU,KACd,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB,CAAC;AAEF,YAAY,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { TodoistApi } from "@doist/todoist-api-typescript";
2
+ declare const accountOverview: {
3
+ name: string;
4
+ description: string;
5
+ parameters: {};
6
+ execute(_args: {}, client: TodoistApi): Promise<string>;
7
+ };
8
+ export { accountOverview };
9
+ //# sourceMappingURL=account-overview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-overview.d.ts","sourceRoot":"","sources":["../../src/tools/account-overview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,UAAU,EACV,MAAM,+BAA+B,CAAC;AA8EvC,QAAA,MAAM,eAAe;;;;;CA6CqB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,94 @@
1
+ const ArgsSchema = {};
2
+ function buildProjectTree(projects) {
3
+ // Sort projects by childOrder, then build a tree
4
+ const byId = {};
5
+ for (const p of projects) {
6
+ byId[p.id] = {
7
+ ...p,
8
+ children: [],
9
+ childOrder: p.childOrder ?? 0,
10
+ };
11
+ }
12
+ const roots = [];
13
+ for (const p of projects) {
14
+ const current = byId[p.id];
15
+ if (!current)
16
+ continue;
17
+ if (p.parentId) {
18
+ const parent = byId[p.parentId];
19
+ if (parent) {
20
+ parent.children.push(current);
21
+ }
22
+ else {
23
+ roots.push(current);
24
+ }
25
+ }
26
+ else {
27
+ roots.push(current);
28
+ }
29
+ }
30
+ function sortTree(nodes) {
31
+ nodes.sort((a, b) => a.childOrder - b.childOrder);
32
+ for (const n of nodes) {
33
+ sortTree(n.children);
34
+ }
35
+ }
36
+ sortTree(roots);
37
+ return roots;
38
+ }
39
+ async function getSectionsByProject(client, projectIds) {
40
+ const result = {};
41
+ await Promise.all(projectIds.map(async (projectId) => {
42
+ const { results } = await client.getSections({ projectId });
43
+ result[projectId] = results;
44
+ }));
45
+ return result;
46
+ }
47
+ function renderProjectMarkdown(project, sectionsByProject, indent = "") {
48
+ const lines = [];
49
+ lines.push(`${indent}- Project: ${project.name} (id=${project.id})`);
50
+ const sections = sectionsByProject[project.id] || [];
51
+ for (const section of sections) {
52
+ lines.push(`${indent} - Section: ${section.name} (id=${section.id})`);
53
+ }
54
+ for (const child of project.children) {
55
+ lines.push(...renderProjectMarkdown(child, sectionsByProject, `${indent} `));
56
+ }
57
+ return lines;
58
+ }
59
+ const accountOverview = {
60
+ name: "account-overview",
61
+ description: "Get a Markdown overview of all projects (with hierarchy and sections) and the inbox project. Useful in almost any context before engaging with Todoist further.",
62
+ parameters: ArgsSchema,
63
+ async execute(_args, client) {
64
+ const { results: projects } = await client.getProjects({});
65
+ const inbox = projects.find((p) => p.isInboxProject === true);
66
+ const nonInbox = projects.filter((p) => p.isInboxProject !== true);
67
+ const tree = buildProjectTree(nonInbox);
68
+ const allProjectIds = projects.map((p) => p.id);
69
+ const sectionsByProject = await getSectionsByProject(client, allProjectIds);
70
+ const lines = ["# Personal Projects", ""];
71
+ if (inbox) {
72
+ lines.push(`- Inbox Project: ${inbox.name} (id=${inbox.id})`);
73
+ for (const section of sectionsByProject[inbox.id] || []) {
74
+ lines.push(` - Section: ${section.name} (id=${section.id})`);
75
+ }
76
+ }
77
+ if (tree.length) {
78
+ for (const project of tree) {
79
+ lines.push(...renderProjectMarkdown(project, sectionsByProject));
80
+ }
81
+ }
82
+ else {
83
+ lines.push("_No projects found._");
84
+ }
85
+ lines.push("");
86
+ // Add explanation about nesting if there are nested projects
87
+ const hasNested = tree.some((p) => p.children.length > 0);
88
+ if (hasNested) {
89
+ lines.push("_Note: Indentation indicates that a project is a sub-project of the one above it. This allows for organizing projects hierarchically, with parent projects containing related sub-projects._", "");
90
+ }
91
+ return lines.join("\n");
92
+ },
93
+ };
94
+ export { accountOverview };
@@ -0,0 +1,23 @@
1
+ export { projectsList } from "./projects-list.js";
2
+ export { projectsSearch } from "./projects-search.js";
3
+ export { projectsAddOne } from "./projects-add-one.js";
4
+ export { projectsUpdateOne } from "./projects-update-one.js";
5
+ export { projectsDeleteOne } from "./projects-delete-one.js";
6
+ export { sectionsSearch } from "./sections-search.js";
7
+ export { sectionsAddOne } from "./sections-add-one.js";
8
+ export { sectionsUpdateOne } from "./sections-update-one.js";
9
+ export { sectionsDeleteOne } from "./sections-delete-one.js";
10
+ export { tasksListByDate } from "./tasks-by-date-range.js";
11
+ export { tasksDeleteOne } from "./tasks-delete-one.js";
12
+ export { tasksCompleteMultiple } from "./tasks-complete-multiple.js";
13
+ export { tasksListForProject } from "./tasks-by-project.js";
14
+ export { tasksListOverdue } from "./tasks-list-overdue.js";
15
+ export { tasksSearch } from "./tasks-search.js";
16
+ export { tasksAddMultiple } from "./tasks-add-multiple.js";
17
+ export { tasksUpdateOne } from "./tasks-update-one.js";
18
+ export { tasksOrganizeMultiple } from "./tasks-organize-multiple.js";
19
+ export { tasksListForSection } from "./tasks-list-for-section.js";
20
+ export { subtasksListForParentTask } from "./subtasks-list-for-parent-task.js";
21
+ export { accountOverview } from "./account-overview.js";
22
+ export { projectOverview } from "./project-overview.js";
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAE/E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,22 @@
1
+ export { projectsList } from "./projects-list.js";
2
+ export { projectsSearch } from "./projects-search.js";
3
+ export { projectsAddOne } from "./projects-add-one.js";
4
+ export { projectsUpdateOne } from "./projects-update-one.js";
5
+ export { projectsDeleteOne } from "./projects-delete-one.js";
6
+ export { sectionsSearch } from "./sections-search.js";
7
+ export { sectionsAddOne } from "./sections-add-one.js";
8
+ export { sectionsUpdateOne } from "./sections-update-one.js";
9
+ export { sectionsDeleteOne } from "./sections-delete-one.js";
10
+ export { tasksListByDate } from "./tasks-by-date-range.js";
11
+ export { tasksDeleteOne } from "./tasks-delete-one.js";
12
+ export { tasksCompleteMultiple } from "./tasks-complete-multiple.js";
13
+ export { tasksListForProject } from "./tasks-by-project.js";
14
+ export { tasksListOverdue } from "./tasks-list-overdue.js";
15
+ export { tasksSearch } from "./tasks-search.js";
16
+ export { tasksAddMultiple } from "./tasks-add-multiple.js";
17
+ export { tasksUpdateOne } from "./tasks-update-one.js";
18
+ export { tasksOrganizeMultiple } from "./tasks-organize-multiple.js";
19
+ export { tasksListForSection } from "./tasks-list-for-section.js";
20
+ export { subtasksListForParentTask } from "./subtasks-list-for-parent-task.js";
21
+ export { accountOverview } from "./account-overview.js";
22
+ export { projectOverview } from "./project-overview.js";
@@ -0,0 +1,14 @@
1
+ import type { TodoistApi } from "@doist/todoist-api-typescript";
2
+ import { z } from "zod";
3
+ declare const projectOverview: {
4
+ name: string;
5
+ description: string;
6
+ parameters: {
7
+ projectId: z.ZodString;
8
+ };
9
+ execute(args: {
10
+ projectId: string;
11
+ }, client: TodoistApi): Promise<string>;
12
+ };
13
+ export { projectOverview };
14
+ //# sourceMappingURL=project-overview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-overview.d.ts","sourceRoot":"","sources":["../../src/tools/project-overview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,UAAU,EACV,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA8ExB,QAAA,MAAM,eAAe;;;;;;;;;CA4CqB,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,107 @@
1
+ import { z } from "zod";
2
+ import { mapTask } from "./shared.js";
3
+ const ArgsSchema = {
4
+ projectId: z
5
+ .string()
6
+ .min(1)
7
+ .describe("The ID of the project to get an overview for."),
8
+ };
9
+ function buildTaskTree(tasks) {
10
+ const byId = {};
11
+ for (const task of tasks) {
12
+ byId[task.id] = { ...task, children: [] };
13
+ }
14
+ const roots = [];
15
+ for (const task of tasks) {
16
+ const node = byId[task.id];
17
+ if (!node)
18
+ continue;
19
+ if (!task.parentId) {
20
+ roots.push(node);
21
+ continue;
22
+ }
23
+ const parent = byId[task.parentId];
24
+ if (parent) {
25
+ parent.children.push(node);
26
+ }
27
+ else {
28
+ roots.push(node);
29
+ }
30
+ }
31
+ return roots;
32
+ }
33
+ function renderTaskTreeMarkdown(tasks, indent = "") {
34
+ const lines = [];
35
+ for (const task of tasks) {
36
+ const idPart = `id=${task.id}`;
37
+ const duePart = task.dueDate ? `; due=${task.dueDate}` : "";
38
+ const contentPart = `; content=${task.content}`;
39
+ lines.push(`${indent}- ${idPart}${duePart}${contentPart}`);
40
+ if (task.children.length > 0) {
41
+ lines.push(...renderTaskTreeMarkdown(task.children, `${indent} `));
42
+ }
43
+ }
44
+ return lines;
45
+ }
46
+ async function getAllTasksForProject(client, projectId) {
47
+ let allTasks = [];
48
+ let cursor = undefined;
49
+ do {
50
+ const { results, nextCursor } = await client.getTasks({
51
+ projectId,
52
+ limit: 50,
53
+ cursor: cursor ?? undefined,
54
+ });
55
+ allTasks = allTasks.concat(results.map(mapTask));
56
+ cursor = nextCursor ?? undefined;
57
+ } while (cursor);
58
+ return allTasks;
59
+ }
60
+ async function getProjectSections(client, projectId) {
61
+ const { results } = await client.getSections({ projectId });
62
+ return results;
63
+ }
64
+ const projectOverview = {
65
+ name: "project-overview",
66
+ description: "Get a Markdown overview of a single project, including its sections and all tasks. Tasks are grouped by section, with tasks not in any section listed first. Each task is listed as '- id=TASKID; due=YYYY-MM-DD; content=TASK CONTENT' (omit due if not present). Subtasks are nested as indented list items.",
67
+ parameters: ArgsSchema,
68
+ async execute(args, client) {
69
+ const { projectId } = args;
70
+ const project = await client.getProject(projectId);
71
+ const sections = await getProjectSections(client, projectId);
72
+ const allTasks = await getAllTasksForProject(client, projectId);
73
+ // Group tasks by sectionId
74
+ const tasksBySection = {};
75
+ for (const section of sections) {
76
+ tasksBySection[section.id] = [];
77
+ }
78
+ const tasksWithoutSection = [];
79
+ for (const task of allTasks) {
80
+ if (task.sectionId && tasksBySection[task.sectionId]) {
81
+ // biome-ignore lint/style/noNonNullAssertion: the "if" above ensures that it is defined
82
+ tasksBySection[task.sectionId].push(task);
83
+ }
84
+ else {
85
+ tasksWithoutSection.push(task);
86
+ }
87
+ }
88
+ const lines = [`# ${project.name}`];
89
+ if (tasksWithoutSection.length > 0) {
90
+ lines.push("");
91
+ const tree = buildTaskTree(tasksWithoutSection);
92
+ lines.push(...renderTaskTreeMarkdown(tree));
93
+ }
94
+ for (const section of sections) {
95
+ lines.push("");
96
+ lines.push(`## ${section.name}`);
97
+ const sectionTasks = tasksBySection[section.id];
98
+ if (!sectionTasks?.length) {
99
+ continue;
100
+ }
101
+ const tree = buildTaskTree(sectionTasks);
102
+ lines.push(...renderTaskTreeMarkdown(tree));
103
+ }
104
+ return lines.join("\n");
105
+ },
106
+ };
107
+ export { projectOverview };