@doist/todoist-ai 2.2.1 → 3.0.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.
- package/README.md +11 -3
- package/dist/index.d.ts +496 -255
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -29
- package/dist/mcp-helpers.d.ts +25 -3
- package/dist/mcp-helpers.d.ts.map +1 -1
- package/dist/mcp-helpers.js +37 -19
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +32 -28
- package/dist/tools/__tests__/add-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/add-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{tasks-add-multiple.test.js → add-tasks.test.js} +85 -81
- package/dist/tools/__tests__/complete-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/complete-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/complete-tasks.test.js +206 -0
- package/dist/tools/__tests__/delete-object.test.d.ts +2 -0
- package/dist/tools/__tests__/delete-object.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{delete-one.test.js → delete-object.test.js} +42 -22
- package/dist/tools/__tests__/find-completed-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{tasks-list-completed.test.js → find-completed-tasks.test.js} +13 -36
- package/dist/tools/__tests__/find-projects.test.d.ts +2 -0
- package/dist/tools/__tests__/find-projects.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{projects-list.test.js → find-projects.test.js} +55 -39
- package/dist/tools/__tests__/find-sections.test.d.ts +2 -0
- package/dist/tools/__tests__/find-sections.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{sections-search.test.js → find-sections.test.js} +64 -50
- package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +2 -0
- package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{tasks-list-by-date.test.js → find-tasks-by-date.test.js} +96 -14
- package/dist/tools/__tests__/find-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/find-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/find-tasks.test.js +334 -0
- package/dist/tools/__tests__/get-overview.test.d.ts +2 -0
- package/dist/tools/__tests__/get-overview.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{overview.test.js → get-overview.test.js} +77 -13
- package/dist/tools/__tests__/manage-projects.test.d.ts +2 -0
- package/dist/tools/__tests__/manage-projects.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{projects-manage.test.js → manage-projects.test.js} +33 -30
- package/dist/tools/__tests__/manage-sections.test.d.ts +2 -0
- package/dist/tools/__tests__/manage-sections.test.d.ts.map +1 -0
- package/dist/tools/__tests__/manage-sections.test.js +162 -0
- package/dist/tools/__tests__/update-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/update-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/update-tasks.test.js +645 -0
- package/dist/tools/{tasks-add-multiple.d.ts → add-tasks.d.ts} +36 -16
- package/dist/tools/add-tasks.d.ts.map +1 -0
- package/dist/tools/{tasks-add-multiple.js → add-tasks.js} +39 -4
- package/dist/tools/complete-tasks.d.ts +40 -0
- package/dist/tools/complete-tasks.d.ts.map +1 -0
- package/dist/tools/complete-tasks.js +68 -0
- package/dist/tools/delete-object.d.ts +38 -0
- package/dist/tools/delete-object.d.ts.map +1 -0
- package/dist/tools/delete-object.js +69 -0
- package/dist/tools/find-completed-tasks.d.ts +74 -0
- package/dist/tools/find-completed-tasks.d.ts.map +1 -0
- package/dist/tools/find-completed-tasks.js +112 -0
- package/dist/tools/find-projects.d.ts +53 -0
- package/dist/tools/find-projects.d.ts.map +1 -0
- package/dist/tools/find-projects.js +101 -0
- package/dist/tools/find-sections.d.ts +42 -0
- package/dist/tools/find-sections.d.ts.map +1 -0
- package/dist/tools/find-sections.js +96 -0
- package/dist/tools/find-tasks-by-date.d.ts +59 -0
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -0
- package/dist/tools/find-tasks-by-date.js +121 -0
- package/dist/tools/find-tasks.d.ts +65 -0
- package/dist/tools/find-tasks.d.ts.map +1 -0
- package/dist/tools/find-tasks.js +182 -0
- package/dist/tools/get-overview.d.ts +67 -0
- package/dist/tools/get-overview.d.ts.map +1 -0
- package/dist/tools/{overview.js → get-overview.js} +66 -19
- package/dist/tools/manage-projects.d.ts +35 -0
- package/dist/tools/manage-projects.d.ts.map +1 -0
- package/dist/tools/manage-projects.js +63 -0
- package/dist/tools/manage-sections.d.ts +38 -0
- package/dist/tools/manage-sections.d.ts.map +1 -0
- package/dist/tools/manage-sections.js +78 -0
- package/dist/tools/update-tasks.d.ts +94 -0
- package/dist/tools/update-tasks.d.ts.map +1 -0
- package/dist/tools/update-tasks.js +120 -0
- package/dist/utils/constants.d.ts +35 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +37 -0
- package/dist/utils/response-builders.d.ts +88 -0
- package/dist/utils/response-builders.d.ts.map +1 -0
- package/dist/utils/response-builders.js +202 -0
- package/dist/{tools → utils}/test-helpers.d.ts +16 -0
- package/dist/utils/test-helpers.d.ts.map +1 -0
- package/dist/{tools → utils}/test-helpers.js +51 -0
- package/dist/utils/tool-names.d.ts +23 -0
- package/dist/utils/tool-names.d.ts.map +1 -0
- package/dist/utils/tool-names.js +25 -0
- package/package.json +2 -2
- package/dist/tools/__tests__/delete-one.test.d.ts +0 -2
- package/dist/tools/__tests__/delete-one.test.d.ts.map +0 -1
- package/dist/tools/__tests__/overview.test.d.ts +0 -2
- package/dist/tools/__tests__/overview.test.d.ts.map +0 -1
- package/dist/tools/__tests__/projects-list.test.d.ts +0 -2
- package/dist/tools/__tests__/projects-list.test.d.ts.map +0 -1
- package/dist/tools/__tests__/projects-manage.test.d.ts +0 -2
- package/dist/tools/__tests__/projects-manage.test.d.ts.map +0 -1
- package/dist/tools/__tests__/sections-manage.test.d.ts +0 -2
- package/dist/tools/__tests__/sections-manage.test.d.ts.map +0 -1
- package/dist/tools/__tests__/sections-manage.test.js +0 -138
- package/dist/tools/__tests__/sections-search.test.d.ts +0 -2
- package/dist/tools/__tests__/sections-search.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-complete-multiple.test.js +0 -146
- package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-list-completed.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-list-for-container.test.js +0 -232
- package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-organize-multiple.test.js +0 -245
- package/dist/tools/__tests__/tasks-search.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-search.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-search.test.js +0 -106
- package/dist/tools/__tests__/tasks-update-one.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-update-one.test.js +0 -251
- package/dist/tools/delete-one.d.ts +0 -17
- package/dist/tools/delete-one.d.ts.map +0 -1
- package/dist/tools/delete-one.js +0 -25
- package/dist/tools/overview.d.ts +0 -14
- package/dist/tools/overview.d.ts.map +0 -1
- package/dist/tools/projects-list.d.ts +0 -29
- package/dist/tools/projects-list.d.ts.map +0 -1
- package/dist/tools/projects-list.js +0 -39
- package/dist/tools/projects-manage.d.ts +0 -24
- package/dist/tools/projects-manage.d.ts.map +0 -1
- package/dist/tools/projects-manage.js +0 -26
- package/dist/tools/sections-manage.d.ts +0 -23
- package/dist/tools/sections-manage.d.ts.map +0 -1
- package/dist/tools/sections-manage.js +0 -37
- package/dist/tools/sections-search.d.ts +0 -18
- package/dist/tools/sections-search.d.ts.map +0 -1
- package/dist/tools/sections-search.js +0 -27
- package/dist/tools/tasks-add-multiple.d.ts.map +0 -1
- package/dist/tools/tasks-complete-multiple.d.ts +0 -16
- package/dist/tools/tasks-complete-multiple.d.ts.map +0 -1
- package/dist/tools/tasks-complete-multiple.js +0 -23
- package/dist/tools/tasks-list-by-date.d.ts +0 -34
- package/dist/tools/tasks-list-by-date.d.ts.map +0 -1
- package/dist/tools/tasks-list-by-date.js +0 -53
- package/dist/tools/tasks-list-completed.d.ts +0 -44
- package/dist/tools/tasks-list-completed.d.ts.map +0 -1
- package/dist/tools/tasks-list-completed.js +0 -49
- package/dist/tools/tasks-list-for-container.d.ts +0 -34
- package/dist/tools/tasks-list-for-container.d.ts.map +0 -1
- package/dist/tools/tasks-list-for-container.js +0 -48
- package/dist/tools/tasks-organize-multiple.d.ts +0 -37
- package/dist/tools/tasks-organize-multiple.d.ts.map +0 -1
- package/dist/tools/tasks-organize-multiple.js +0 -34
- package/dist/tools/tasks-search.d.ts +0 -32
- package/dist/tools/tasks-search.d.ts.map +0 -1
- package/dist/tools/tasks-search.js +0 -30
- package/dist/tools/tasks-update-one.d.ts +0 -29
- package/dist/tools/tasks-update-one.d.ts.map +0 -1
- package/dist/tools/tasks-update-one.js +0 -63
- package/dist/tools/test-helpers.d.ts.map +0 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG9C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,QAAA,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiBV,CAAA;AAED,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;AAE9B,OAAO,EAEH,QAAQ,EACR,aAAa,EACb,WAAW,EACX,SAAS,EACT,eAAe,EACf,kBAAkB,EAElB,YAAY,EACZ,cAAc,EAEd,YAAY,EACZ,cAAc,EAEd,WAAW,EACX,YAAY,GACf,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
import { getMcpServer } from './mcp-server.js';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
2
|
+
// Task management tools
|
|
3
|
+
import { addTasks } from './tools/add-tasks.js';
|
|
4
|
+
import { completeTasks } from './tools/complete-tasks.js';
|
|
5
|
+
import { findCompletedTasks } from './tools/find-completed-tasks.js';
|
|
6
|
+
import { findTasksByDate } from './tools/find-tasks-by-date.js';
|
|
7
|
+
import { findTasks } from './tools/find-tasks.js';
|
|
8
|
+
import { updateTasks } from './tools/update-tasks.js';
|
|
9
|
+
// Project management tools
|
|
10
|
+
import { findProjects } from './tools/find-projects.js';
|
|
11
|
+
import { manageProjects } from './tools/manage-projects.js';
|
|
12
|
+
// Section management tools
|
|
13
|
+
import { findSections } from './tools/find-sections.js';
|
|
14
|
+
import { manageSections } from './tools/manage-sections.js';
|
|
15
|
+
// General tools
|
|
16
|
+
import { deleteObject } from './tools/delete-object.js';
|
|
17
|
+
import { getOverview } from './tools/get-overview.js';
|
|
16
18
|
const tools = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
// Task management tools
|
|
20
|
+
addTasks,
|
|
21
|
+
completeTasks,
|
|
22
|
+
updateTasks,
|
|
23
|
+
findTasks,
|
|
24
|
+
findTasksByDate,
|
|
25
|
+
findCompletedTasks,
|
|
26
|
+
// Project management tools
|
|
27
|
+
findProjects,
|
|
28
|
+
manageProjects,
|
|
29
|
+
// Section management tools
|
|
30
|
+
findSections,
|
|
31
|
+
manageSections,
|
|
32
|
+
// General tools
|
|
33
|
+
getOverview,
|
|
34
|
+
deleteObject,
|
|
31
35
|
};
|
|
32
36
|
export { tools, getMcpServer };
|
|
33
|
-
export {
|
|
37
|
+
export {
|
|
38
|
+
// Task management tools
|
|
39
|
+
addTasks, completeTasks, updateTasks, findTasks, findTasksByDate, findCompletedTasks,
|
|
40
|
+
// Project management tools
|
|
41
|
+
findProjects, manageProjects,
|
|
42
|
+
// Section management tools
|
|
43
|
+
findSections, manageSections,
|
|
44
|
+
// General tools
|
|
45
|
+
getOverview, deleteObject, };
|
package/dist/mcp-helpers.d.ts
CHANGED
|
@@ -2,12 +2,34 @@ import type { TodoistApi } from '@doist/todoist-api-typescript';
|
|
|
2
2
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import type { z } from 'zod';
|
|
4
4
|
import type { TodoistTool } from './todoist-tool.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Get the output payload for a tool, in the correct format expected by MCP client apps.
|
|
7
|
+
*
|
|
8
|
+
* @param textContent - The text content to return.
|
|
9
|
+
* @param structuredContent - The structured content to return.
|
|
10
|
+
* @returns The output payload.
|
|
11
|
+
* @see USE_STRUCTURED_CONTENT - Wether to use the structured content feature of the MCP protocol.
|
|
12
|
+
*/
|
|
13
|
+
declare function getToolOutput<StructuredContent extends Record<string, unknown>>({ textContent, structuredContent, }: {
|
|
14
|
+
textContent: string;
|
|
15
|
+
structuredContent: StructuredContent;
|
|
16
|
+
}): {
|
|
7
17
|
content: {
|
|
8
18
|
type: "text";
|
|
9
19
|
text: string;
|
|
10
20
|
}[];
|
|
21
|
+
structuredContent: StructuredContent;
|
|
22
|
+
} | {
|
|
23
|
+
content: ({
|
|
24
|
+
type: "text";
|
|
25
|
+
text: string;
|
|
26
|
+
mimeType?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
type: "text";
|
|
29
|
+
mimeType: string;
|
|
30
|
+
text: string;
|
|
31
|
+
})[];
|
|
32
|
+
structuredContent?: undefined;
|
|
11
33
|
};
|
|
12
34
|
/**
|
|
13
35
|
* Register a Todoist tool in an MCP server.
|
|
@@ -16,5 +38,5 @@ declare function errorContent(error: string): {
|
|
|
16
38
|
* @param client - The Todoist API client to use to execute the tool.
|
|
17
39
|
*/
|
|
18
40
|
declare function registerTool<Params extends z.ZodRawShape>(tool: TodoistTool<Params>, server: McpServer, client: TodoistApi): void;
|
|
19
|
-
export { registerTool,
|
|
41
|
+
export { registerTool, getToolOutput };
|
|
20
42
|
//# sourceMappingURL=mcp-helpers.d.ts.map
|
|
@@ -1 +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,CAAA;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,yCAAyC,CAAA;AACtF,OAAO,KAAK,EAAc,CAAC,EAAE,MAAM,KAAK,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
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,CAAA;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,yCAAyC,CAAA;AACtF,OAAO,KAAK,EAAc,CAAC,EAAE,MAAM,KAAK,CAAA;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAkBpD;;;;;;;GAOG;AACH,iBAAS,aAAa,CAAC,iBAAiB,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACtE,WAAW,EACX,iBAAiB,GACpB,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAA;CAAE;;;;;;;;;;;;;;;;;EAe/D;AASD;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,MAAM,SAAS,CAAC,CAAC,WAAW,EAC9C,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EACzB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,QAqBrB;AAED,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAA"}
|
package/dist/mcp-helpers.js
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Wether to return the structured content directly, vs. in the `content` part of the output.
|
|
3
|
+
*
|
|
4
|
+
* The `structuredContent` part of the output is relatively new in the spec, and it's not yet
|
|
5
|
+
* supported by all clients. This flag controls wether we return the structured content using this
|
|
6
|
+
* new feature of the MCP protocol or not.
|
|
7
|
+
*
|
|
8
|
+
* If `false`, the `structuredContent` will be returned as stringified JSON in one of the `content`
|
|
9
|
+
* parts.
|
|
10
|
+
*
|
|
11
|
+
* Eventually we should be able to remove this, and change the code to always work with the
|
|
12
|
+
* structured content returned directly, once most or all MCP clients support it.
|
|
13
|
+
*/
|
|
14
|
+
const USE_STRUCTURED_CONTENT = process.env.USE_STRUCTURED_CONTENT === 'true' || process.env.NODE_ENV === 'test';
|
|
15
|
+
/**
|
|
16
|
+
* Get the output payload for a tool, in the correct format expected by MCP client apps.
|
|
17
|
+
*
|
|
18
|
+
* @param textContent - The text content to return.
|
|
19
|
+
* @param structuredContent - The structured content to return.
|
|
20
|
+
* @returns The output payload.
|
|
21
|
+
* @see USE_STRUCTURED_CONTENT - Wether to use the structured content feature of the MCP protocol.
|
|
22
|
+
*/
|
|
23
|
+
function getToolOutput({ textContent, structuredContent, }) {
|
|
24
|
+
if (USE_STRUCTURED_CONTENT) {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: 'text', text: textContent }],
|
|
27
|
+
structuredContent,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const json = JSON.stringify(structuredContent);
|
|
7
31
|
return {
|
|
8
32
|
content: [
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
mimeType: 'application/json',
|
|
12
|
-
text: JSON.stringify(data, null, 2),
|
|
13
|
-
},
|
|
33
|
+
{ type: 'text', text: textContent },
|
|
34
|
+
{ type: 'text', mimeType: 'application/json', text: json },
|
|
14
35
|
],
|
|
15
36
|
};
|
|
16
37
|
}
|
|
17
|
-
function
|
|
18
|
-
return typeof data === 'string' ? textContent(data) : jsonContent(data);
|
|
19
|
-
}
|
|
20
|
-
function errorContent(error) {
|
|
38
|
+
function getErrorOutput(error) {
|
|
21
39
|
return {
|
|
22
|
-
|
|
40
|
+
content: [{ type: 'text', text: error }],
|
|
23
41
|
isError: true,
|
|
24
42
|
};
|
|
25
43
|
}
|
|
@@ -34,7 +52,7 @@ function registerTool(tool, server, client) {
|
|
|
34
52
|
const cb = async (args, _context) => {
|
|
35
53
|
try {
|
|
36
54
|
const result = await tool.execute(args, client);
|
|
37
|
-
return
|
|
55
|
+
return result;
|
|
38
56
|
}
|
|
39
57
|
catch (error) {
|
|
40
58
|
console.error(`Error executing tool ${tool.name}:`, {
|
|
@@ -42,9 +60,9 @@ function registerTool(tool, server, client) {
|
|
|
42
60
|
error,
|
|
43
61
|
});
|
|
44
62
|
const message = error instanceof Error ? error.message : 'An unknown error occurred';
|
|
45
|
-
return
|
|
63
|
+
return getErrorOutput(message);
|
|
46
64
|
}
|
|
47
65
|
};
|
|
48
66
|
server.tool(tool.name, tool.description, tool.parameters, cb);
|
|
49
67
|
}
|
|
50
|
-
export { registerTool,
|
|
68
|
+
export { registerTool, getToolOutput };
|
package/dist/mcp-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AA2BnE;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,aAkC5F;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { TodoistApi } from '@doist/todoist-api-typescript';
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { registerTool } from './mcp-helpers.js';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
4
|
+
// Task management tools
|
|
5
|
+
import { addTasks } from './tools/add-tasks.js';
|
|
6
|
+
import { completeTasks } from './tools/complete-tasks.js';
|
|
7
|
+
import { findCompletedTasks } from './tools/find-completed-tasks.js';
|
|
8
|
+
import { findTasksByDate } from './tools/find-tasks-by-date.js';
|
|
9
|
+
import { findTasks } from './tools/find-tasks.js';
|
|
10
|
+
import { updateTasks } from './tools/update-tasks.js';
|
|
11
|
+
// Project management tools
|
|
12
|
+
import { findProjects } from './tools/find-projects.js';
|
|
13
|
+
import { manageProjects } from './tools/manage-projects.js';
|
|
14
|
+
// Section management tools
|
|
15
|
+
import { findSections } from './tools/find-sections.js';
|
|
16
|
+
import { manageSections } from './tools/manage-sections.js';
|
|
17
|
+
// General tools
|
|
18
|
+
import { deleteObject } from './tools/delete-object.js';
|
|
19
|
+
import { getOverview } from './tools/get-overview.js';
|
|
18
20
|
const instructions = `
|
|
19
21
|
Tools to help you manage your todoist tasks.
|
|
20
22
|
`;
|
|
@@ -32,20 +34,22 @@ function getMcpServer({ todoistApiKey, baseUrl }) {
|
|
|
32
34
|
instructions,
|
|
33
35
|
});
|
|
34
36
|
const todoist = new TodoistApi(todoistApiKey, baseUrl);
|
|
35
|
-
|
|
36
|
-
registerTool(
|
|
37
|
-
registerTool(
|
|
38
|
-
registerTool(
|
|
39
|
-
registerTool(
|
|
40
|
-
registerTool(
|
|
41
|
-
registerTool(
|
|
42
|
-
|
|
43
|
-
registerTool(
|
|
44
|
-
registerTool(
|
|
45
|
-
|
|
46
|
-
registerTool(
|
|
47
|
-
registerTool(
|
|
48
|
-
|
|
37
|
+
// Task management tools
|
|
38
|
+
registerTool(addTasks, server, todoist);
|
|
39
|
+
registerTool(completeTasks, server, todoist);
|
|
40
|
+
registerTool(updateTasks, server, todoist);
|
|
41
|
+
registerTool(findTasks, server, todoist);
|
|
42
|
+
registerTool(findTasksByDate, server, todoist);
|
|
43
|
+
registerTool(findCompletedTasks, server, todoist);
|
|
44
|
+
// Project management tools
|
|
45
|
+
registerTool(findProjects, server, todoist);
|
|
46
|
+
registerTool(manageProjects, server, todoist);
|
|
47
|
+
// Section management tools
|
|
48
|
+
registerTool(findSections, server, todoist);
|
|
49
|
+
registerTool(manageSections, server, todoist);
|
|
50
|
+
// General tools
|
|
51
|
+
registerTool(getOverview, server, todoist);
|
|
52
|
+
registerTool(deleteObject, server, todoist);
|
|
49
53
|
return server;
|
|
50
54
|
}
|
|
51
55
|
export { getMcpServer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-tasks.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/add-tasks.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jest } from '@jest/globals';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TODAY, createMockTask, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { addTasks } from '../add-tasks.js';
|
|
4
5
|
// Mock the Todoist API
|
|
5
6
|
const mockTodoistApi = {
|
|
6
7
|
addTask: jest.fn(),
|
|
7
8
|
};
|
|
8
|
-
|
|
9
|
+
const { ADD_TASKS, GET_OVERVIEW } = ToolNames;
|
|
10
|
+
describe(`${ADD_TASKS} tool`, () => {
|
|
9
11
|
beforeEach(() => {
|
|
10
12
|
jest.clearAllMocks();
|
|
11
13
|
});
|
|
@@ -38,7 +40,7 @@ describe('tasks-add-multiple tool', () => {
|
|
|
38
40
|
mockTodoistApi.addTask
|
|
39
41
|
.mockResolvedValueOnce(mockApiResponse1)
|
|
40
42
|
.mockResolvedValueOnce(mockApiResponse2);
|
|
41
|
-
const result = await
|
|
43
|
+
const result = await addTasks.execute({
|
|
42
44
|
projectId: '6cfCcrrCFg2xP94Q',
|
|
43
45
|
tasks: [
|
|
44
46
|
{ content: 'First task content' },
|
|
@@ -67,23 +69,18 @@ describe('tasks-add-multiple tool', () => {
|
|
|
67
69
|
sectionId: undefined,
|
|
68
70
|
parentId: undefined,
|
|
69
71
|
});
|
|
70
|
-
// Verify result is
|
|
71
|
-
expect(result).
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
id: '8485093749',
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
dueDate: '2025-08-15',
|
|
83
|
-
priority: 2,
|
|
84
|
-
labels: ['work', 'urgent'],
|
|
85
|
-
}),
|
|
86
|
-
]);
|
|
72
|
+
// Verify result is a concise summary
|
|
73
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
74
|
+
// Verify structured content
|
|
75
|
+
const structuredContent = extractStructuredContent(result);
|
|
76
|
+
expect(structuredContent.tasks).toHaveLength(2);
|
|
77
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
78
|
+
totalCount: 2,
|
|
79
|
+
tasks: expect.arrayContaining([
|
|
80
|
+
expect.objectContaining({ id: '8485093748' }),
|
|
81
|
+
expect.objectContaining({ id: '8485093749' }),
|
|
82
|
+
]),
|
|
83
|
+
}));
|
|
87
84
|
});
|
|
88
85
|
it('should handle tasks with section and parent IDs', async () => {
|
|
89
86
|
const mockApiResponse = createMockTask({
|
|
@@ -97,7 +94,7 @@ describe('tasks-add-multiple tool', () => {
|
|
|
97
94
|
addedAt: '2025-08-13T22:09:58.123456Z',
|
|
98
95
|
});
|
|
99
96
|
mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
|
|
100
|
-
const result = await
|
|
97
|
+
const result = await addTasks.execute({
|
|
101
98
|
projectId: '6cfCcrrCFg2xP94Q',
|
|
102
99
|
sectionId: 'section-123',
|
|
103
100
|
parentId: 'parent-task-456',
|
|
@@ -117,17 +114,14 @@ describe('tasks-add-multiple tool', () => {
|
|
|
117
114
|
sectionId: 'section-123',
|
|
118
115
|
parentId: 'parent-task-456',
|
|
119
116
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
labels: [],
|
|
129
|
-
}),
|
|
130
|
-
]);
|
|
117
|
+
// Verify result is a concise summary
|
|
118
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
119
|
+
// Verify structured content
|
|
120
|
+
const structuredContent = extractStructuredContent(result);
|
|
121
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
122
|
+
totalCount: 1,
|
|
123
|
+
tasks: expect.arrayContaining([expect.objectContaining({ id: '8485093750' })]),
|
|
124
|
+
}));
|
|
131
125
|
});
|
|
132
126
|
it('should add tasks with duration', async () => {
|
|
133
127
|
const mockApiResponse1 = createMockTask({
|
|
@@ -147,17 +141,11 @@ describe('tasks-add-multiple tool', () => {
|
|
|
147
141
|
mockTodoistApi.addTask
|
|
148
142
|
.mockResolvedValueOnce(mockApiResponse1)
|
|
149
143
|
.mockResolvedValueOnce(mockApiResponse2);
|
|
150
|
-
const result = await
|
|
144
|
+
const result = await addTasks.execute({
|
|
151
145
|
projectId: '6cfCcrrCFg2xP94Q',
|
|
152
146
|
tasks: [
|
|
153
|
-
{
|
|
154
|
-
|
|
155
|
-
duration: '2h',
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
content: 'Task with 45 minute duration',
|
|
159
|
-
duration: '45m',
|
|
160
|
-
},
|
|
147
|
+
{ content: 'Task with 2 hour duration', duration: '2h' },
|
|
148
|
+
{ content: 'Task with 45 minute duration', duration: '45m' },
|
|
161
149
|
],
|
|
162
150
|
}, mockTodoistApi);
|
|
163
151
|
// Verify API was called with parsed duration
|
|
@@ -177,19 +165,18 @@ describe('tasks-add-multiple tool', () => {
|
|
|
177
165
|
duration: 45,
|
|
178
166
|
durationUnit: 'minute',
|
|
179
167
|
});
|
|
180
|
-
// Verify result
|
|
181
|
-
expect(result).
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
expect.
|
|
188
|
-
id: '
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
]);
|
|
168
|
+
// Verify result is a concise summary
|
|
169
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
170
|
+
// Verify structured content
|
|
171
|
+
const structuredContent = extractStructuredContent(result);
|
|
172
|
+
expect(structuredContent.tasks).toHaveLength(2);
|
|
173
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
174
|
+
totalCount: 2,
|
|
175
|
+
tasks: expect.arrayContaining([
|
|
176
|
+
expect.objectContaining({ id: '8485093752' }),
|
|
177
|
+
expect.objectContaining({ id: '8485093753' }),
|
|
178
|
+
]),
|
|
179
|
+
}));
|
|
193
180
|
});
|
|
194
181
|
it('should handle various duration formats', async () => {
|
|
195
182
|
const mockApiResponse = createMockTask({
|
|
@@ -209,14 +196,7 @@ describe('tasks-add-multiple tool', () => {
|
|
|
209
196
|
];
|
|
210
197
|
for (const testCase of testCases) {
|
|
211
198
|
mockTodoistApi.addTask.mockClear();
|
|
212
|
-
await
|
|
213
|
-
tasks: [
|
|
214
|
-
{
|
|
215
|
-
content: 'Test task',
|
|
216
|
-
duration: testCase.input,
|
|
217
|
-
},
|
|
218
|
-
],
|
|
219
|
-
}, mockTodoistApi);
|
|
199
|
+
await addTasks.execute({ tasks: [{ content: 'Test task', duration: testCase.input }] }, mockTodoistApi);
|
|
220
200
|
expect(mockTodoistApi.addTask).toHaveBeenCalledWith(expect.objectContaining({
|
|
221
201
|
duration: testCase.expectedMinutes,
|
|
222
202
|
durationUnit: 'minute',
|
|
@@ -226,29 +206,15 @@ describe('tasks-add-multiple tool', () => {
|
|
|
226
206
|
});
|
|
227
207
|
describe('error handling', () => {
|
|
228
208
|
it('should throw error for invalid duration format', async () => {
|
|
229
|
-
await expect(
|
|
230
|
-
tasks: [
|
|
231
|
-
{
|
|
232
|
-
content: 'Task with invalid duration',
|
|
233
|
-
duration: 'invalid',
|
|
234
|
-
},
|
|
235
|
-
],
|
|
236
|
-
}, mockTodoistApi)).rejects.toThrow('Task "Task with invalid duration": Invalid duration format "invalid"');
|
|
209
|
+
await expect(addTasks.execute({ tasks: [{ content: 'Task with invalid duration', duration: 'invalid' }] }, mockTodoistApi)).rejects.toThrow('Task "Task with invalid duration": Invalid duration format "invalid"');
|
|
237
210
|
});
|
|
238
211
|
it('should throw error for duration exceeding 24 hours', async () => {
|
|
239
|
-
await expect(
|
|
240
|
-
tasks: [
|
|
241
|
-
{
|
|
242
|
-
content: 'Task with too long duration',
|
|
243
|
-
duration: '25h',
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
}, mockTodoistApi)).rejects.toThrow('Task "Task with too long duration": Invalid duration format "25h": Duration cannot exceed 24 hours (1440 minutes)');
|
|
212
|
+
await expect(addTasks.execute({ tasks: [{ content: 'Task with too long duration', duration: '25h' }] }, mockTodoistApi)).rejects.toThrow('Task "Task with too long duration": Invalid duration format "25h": Duration cannot exceed 24 hours (1440 minutes)');
|
|
247
213
|
});
|
|
248
214
|
it('should propagate API errors', async () => {
|
|
249
215
|
const apiError = new Error('API Error: Task content is required');
|
|
250
216
|
mockTodoistApi.addTask.mockRejectedValue(apiError);
|
|
251
|
-
await expect(
|
|
217
|
+
await expect(addTasks.execute({ tasks: [{ content: '' }] }, mockTodoistApi)).rejects.toThrow(apiError.message);
|
|
252
218
|
});
|
|
253
219
|
it('should handle partial failures when adding multiple tasks', async () => {
|
|
254
220
|
const mockApiResponse = createMockTask({
|
|
@@ -261,7 +227,7 @@ describe('tasks-add-multiple tool', () => {
|
|
|
261
227
|
mockTodoistApi.addTask
|
|
262
228
|
.mockResolvedValueOnce(mockApiResponse)
|
|
263
229
|
.mockRejectedValueOnce(apiError);
|
|
264
|
-
await expect(
|
|
230
|
+
await expect(addTasks.execute({
|
|
265
231
|
tasks: [
|
|
266
232
|
{ content: 'First task content' },
|
|
267
233
|
{ content: 'Second task content' },
|
|
@@ -271,4 +237,42 @@ describe('tasks-add-multiple tool', () => {
|
|
|
271
237
|
expect(mockTodoistApi.addTask).toHaveBeenCalledTimes(2);
|
|
272
238
|
});
|
|
273
239
|
});
|
|
240
|
+
describe('next steps logic', () => {
|
|
241
|
+
it('should suggest find-tasks-by-date for today when hasToday is true', async () => {
|
|
242
|
+
const mockApiResponse = createMockTask({
|
|
243
|
+
id: '8485093755',
|
|
244
|
+
content: 'Task due today',
|
|
245
|
+
url: 'https://todoist.com/showTask?id=8485093755',
|
|
246
|
+
addedAt: '2025-08-13T22:09:56.123456Z',
|
|
247
|
+
due: {
|
|
248
|
+
date: TODAY,
|
|
249
|
+
isRecurring: false,
|
|
250
|
+
lang: 'en',
|
|
251
|
+
string: 'today',
|
|
252
|
+
timezone: null,
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
|
|
256
|
+
const result = await addTasks.execute({ tasks: [{ content: 'Task due today', dueString: 'today' }] }, mockTodoistApi);
|
|
257
|
+
const textContent = extractTextContent(result);
|
|
258
|
+
expect(textContent).toMatchSnapshot();
|
|
259
|
+
expect(textContent).toContain(`Use ${GET_OVERVIEW} to see your updated project organization`);
|
|
260
|
+
});
|
|
261
|
+
it('should suggest overview tool when no hasToday context', async () => {
|
|
262
|
+
const mockApiResponse = createMockTask({
|
|
263
|
+
id: '8485093756',
|
|
264
|
+
content: 'Regular task',
|
|
265
|
+
url: 'https://todoist.com/showTask?id=8485093756',
|
|
266
|
+
addedAt: '2025-08-13T22:09:56.123456Z',
|
|
267
|
+
});
|
|
268
|
+
mockTodoistApi.addTask.mockResolvedValue(mockApiResponse);
|
|
269
|
+
const result = await addTasks.execute({
|
|
270
|
+
projectId: '6cfCcrrCFg2xP94Q',
|
|
271
|
+
tasks: [{ content: 'Regular task' }],
|
|
272
|
+
}, mockTodoistApi);
|
|
273
|
+
const textContent = extractTextContent(result);
|
|
274
|
+
expect(textContent).toMatchSnapshot();
|
|
275
|
+
expect(textContent).toContain(`Use ${GET_OVERVIEW} to see your updated project organization`);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
274
278
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complete-tasks.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/complete-tasks.test.ts"],"names":[],"mappings":""}
|