ticktick-mcp 0.1.0 → 0.2.1
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/index.js +47 -1096
- package/dist/index.js.map +1 -1
- package/dist/sdk/__tests__/client.test.d.ts +2 -0
- package/dist/sdk/__tests__/client.test.d.ts.map +1 -0
- package/dist/sdk/__tests__/client.test.js +251 -0
- package/dist/sdk/__tests__/client.test.js.map +1 -0
- package/dist/sdk/__tests__/errors.test.d.ts +2 -0
- package/dist/sdk/__tests__/errors.test.d.ts.map +1 -0
- package/dist/sdk/__tests__/errors.test.js +164 -0
- package/dist/sdk/__tests__/errors.test.js.map +1 -0
- package/dist/sdk/__tests__/types.test.d.ts +2 -0
- package/dist/sdk/__tests__/types.test.d.ts.map +1 -0
- package/dist/sdk/__tests__/types.test.js +134 -0
- package/dist/sdk/__tests__/types.test.js.map +1 -0
- package/dist/sdk/client.d.ts +10 -2
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +14 -3
- package/dist/sdk/client.js.map +1 -1
- package/dist/sdk/index.d.ts +5 -3
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +10 -2
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/types.d.ts +215 -23
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/types.js +169 -6
- package/dist/sdk/types.js.map +1 -1
- package/dist/tools/authExchangeCode.d.ts +9 -0
- package/dist/tools/authExchangeCode.d.ts.map +1 -0
- package/dist/tools/authExchangeCode.js +49 -0
- package/dist/tools/authExchangeCode.js.map +1 -0
- package/dist/tools/authGetAuthorizationUrl.d.ts +10 -0
- package/dist/tools/authGetAuthorizationUrl.d.ts.map +1 -0
- package/dist/tools/authGetAuthorizationUrl.js +53 -0
- package/dist/tools/authGetAuthorizationUrl.js.map +1 -0
- package/dist/tools/authLogout.d.ts +9 -0
- package/dist/tools/authLogout.d.ts.map +1 -0
- package/dist/tools/authLogout.js +43 -0
- package/dist/tools/authLogout.js.map +1 -0
- package/dist/tools/authRefreshToken.d.ts +9 -0
- package/dist/tools/authRefreshToken.d.ts.map +1 -0
- package/dist/tools/authRefreshToken.js +60 -0
- package/dist/tools/authRefreshToken.js.map +1 -0
- package/dist/tools/authStatus.d.ts +9 -0
- package/dist/tools/authStatus.d.ts.map +1 -0
- package/dist/tools/authStatus.js +63 -0
- package/dist/tools/authStatus.js.map +1 -0
- package/dist/tools/batchCreateTasks.d.ts +9 -0
- package/dist/tools/batchCreateTasks.d.ts.map +1 -0
- package/dist/tools/batchCreateTasks.js +75 -0
- package/dist/tools/batchCreateTasks.js.map +1 -0
- package/dist/tools/completeTask.d.ts +9 -0
- package/dist/tools/completeTask.d.ts.map +1 -0
- package/dist/tools/completeTask.js +47 -0
- package/dist/tools/completeTask.js.map +1 -0
- package/dist/tools/createProject.d.ts +9 -0
- package/dist/tools/createProject.d.ts.map +1 -0
- package/dist/tools/createProject.js +64 -0
- package/dist/tools/createProject.js.map +1 -0
- package/dist/tools/createTask.d.ts +9 -0
- package/dist/tools/createTask.d.ts.map +1 -0
- package/dist/tools/createTask.js +131 -0
- package/dist/tools/createTask.js.map +1 -0
- package/dist/tools/deleteProject.d.ts +9 -0
- package/dist/tools/deleteProject.d.ts.map +1 -0
- package/dist/tools/deleteProject.js +46 -0
- package/dist/tools/deleteProject.js.map +1 -0
- package/dist/tools/deleteTask.d.ts +9 -0
- package/dist/tools/deleteTask.d.ts.map +1 -0
- package/dist/tools/deleteTask.js +47 -0
- package/dist/tools/deleteTask.js.map +1 -0
- package/dist/tools/getHighPriorityTasks.d.ts +9 -0
- package/dist/tools/getHighPriorityTasks.d.ts.map +1 -0
- package/dist/tools/getHighPriorityTasks.js +114 -0
- package/dist/tools/getHighPriorityTasks.js.map +1 -0
- package/dist/tools/getProject.d.ts +9 -0
- package/dist/tools/getProject.d.ts.map +1 -0
- package/dist/tools/getProject.js +62 -0
- package/dist/tools/getProject.js.map +1 -0
- package/dist/tools/getProjectById.d.ts +9 -0
- package/dist/tools/getProjectById.d.ts.map +1 -0
- package/dist/tools/getProjectById.js +52 -0
- package/dist/tools/getProjectById.js.map +1 -0
- package/dist/tools/getTask.d.ts +9 -0
- package/dist/tools/getTask.d.ts.map +1 -0
- package/dist/tools/getTask.js +65 -0
- package/dist/tools/getTask.js.map +1 -0
- package/dist/tools/getTasksDueSoon.d.ts +9 -0
- package/dist/tools/getTasksDueSoon.d.ts.map +1 -0
- package/dist/tools/getTasksDueSoon.js +118 -0
- package/dist/tools/getTasksDueSoon.js.map +1 -0
- package/dist/tools/getUser.d.ts +9 -0
- package/dist/tools/getUser.d.ts.map +1 -0
- package/dist/tools/getUser.js +47 -0
- package/dist/tools/getUser.js.map +1 -0
- package/dist/tools/listProjects.d.ts +9 -0
- package/dist/tools/listProjects.d.ts.map +1 -0
- package/dist/tools/listProjects.js +78 -0
- package/dist/tools/listProjects.js.map +1 -0
- package/dist/tools/listTasksInProject.d.ts +10 -0
- package/dist/tools/listTasksInProject.d.ts.map +1 -0
- package/dist/tools/listTasksInProject.js +177 -0
- package/dist/tools/listTasksInProject.js.map +1 -0
- package/dist/tools/searchTasks.d.ts +9 -0
- package/dist/tools/searchTasks.d.ts.map +1 -0
- package/dist/tools/searchTasks.js +134 -0
- package/dist/tools/searchTasks.js.map +1 -0
- package/dist/tools/updateProject.d.ts +9 -0
- package/dist/tools/updateProject.d.ts.map +1 -0
- package/dist/tools/updateProject.js +66 -0
- package/dist/tools/updateProject.js.map +1 -0
- package/dist/tools/updateTask.d.ts +9 -0
- package/dist/tools/updateTask.d.ts.map +1 -0
- package/dist/tools/updateTask.js +132 -0
- package/dist/tools/updateTask.js.map +1 -0
- package/package.json +14 -4
package/dist/index.js
CHANGED
|
@@ -7,9 +7,31 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
9
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
-
import { z } from "zod";
|
|
11
10
|
import { createOAuthFromEnv } from "./oauth.js";
|
|
12
11
|
import { TickTickClient } from "./sdk/client.js";
|
|
12
|
+
// Import all tool registration functions
|
|
13
|
+
import { registerAuthGetAuthorizationUrlTool } from "./tools/authGetAuthorizationUrl.js";
|
|
14
|
+
import { registerAuthExchangeCodeTool } from "./tools/authExchangeCode.js";
|
|
15
|
+
import { registerAuthStatusTool } from "./tools/authStatus.js";
|
|
16
|
+
import { registerAuthRefreshTokenTool } from "./tools/authRefreshToken.js";
|
|
17
|
+
import { registerAuthLogoutTool } from "./tools/authLogout.js";
|
|
18
|
+
import { registerGetUserTool } from "./tools/getUser.js";
|
|
19
|
+
import { registerListProjectsTool } from "./tools/listProjects.js";
|
|
20
|
+
import { registerGetProjectTool } from "./tools/getProject.js";
|
|
21
|
+
import { registerGetProjectByIdTool } from "./tools/getProjectById.js";
|
|
22
|
+
import { registerCreateProjectTool } from "./tools/createProject.js";
|
|
23
|
+
import { registerUpdateProjectTool } from "./tools/updateProject.js";
|
|
24
|
+
import { registerDeleteProjectTool } from "./tools/deleteProject.js";
|
|
25
|
+
import { registerListTasksInProjectTool } from "./tools/listTasksInProject.js";
|
|
26
|
+
import { registerCreateTaskTool } from "./tools/createTask.js";
|
|
27
|
+
import { registerUpdateTaskTool } from "./tools/updateTask.js";
|
|
28
|
+
import { registerCompleteTaskTool } from "./tools/completeTask.js";
|
|
29
|
+
import { registerDeleteTaskTool } from "./tools/deleteTask.js";
|
|
30
|
+
import { registerGetTaskTool } from "./tools/getTask.js";
|
|
31
|
+
import { registerBatchCreateTasksTool } from "./tools/batchCreateTasks.js";
|
|
32
|
+
import { registerGetTasksDueSoonTool } from "./tools/getTasksDueSoon.js";
|
|
33
|
+
import { registerSearchTasksTool } from "./tools/searchTasks.js";
|
|
34
|
+
import { registerGetHighPriorityTasksTool } from "./tools/getHighPriorityTasks.js";
|
|
13
35
|
// =============================================================================
|
|
14
36
|
// Server Setup
|
|
15
37
|
// =============================================================================
|
|
@@ -38,1105 +60,34 @@ async function getClient() {
|
|
|
38
60
|
return new TickTickClient({ accessToken, region });
|
|
39
61
|
}
|
|
40
62
|
// =============================================================================
|
|
41
|
-
//
|
|
42
|
-
// =============================================================================
|
|
43
|
-
/**
|
|
44
|
-
* Tool: Get OAuth authorization URL
|
|
45
|
-
*
|
|
46
|
-
* Returns the URL that users should visit to authorize the application.
|
|
47
|
-
* This initiates the OAuth 2.0 authorization code flow.
|
|
48
|
-
*/
|
|
49
|
-
server.tool("auth_get_authorization_url", "Get the OAuth authorization URL for TickTick. Returns a URL that the user should visit in their browser to authorize the application.", {}, async () => {
|
|
50
|
-
try {
|
|
51
|
-
const oauth = getOAuthHelper();
|
|
52
|
-
const { url, state } = oauth.getAuthorizationUrl();
|
|
53
|
-
return {
|
|
54
|
-
content: [
|
|
55
|
-
{
|
|
56
|
-
type: "text",
|
|
57
|
-
text: JSON.stringify({
|
|
58
|
-
success: true,
|
|
59
|
-
authorizationUrl: url,
|
|
60
|
-
state: state,
|
|
61
|
-
instructions: [
|
|
62
|
-
"1. Open the authorization URL in your browser",
|
|
63
|
-
"2. Log in to TickTick and authorize the application",
|
|
64
|
-
"3. After authorization, you will be redirected to a URL containing a 'code' parameter",
|
|
65
|
-
"4. Copy the 'code' value from the URL",
|
|
66
|
-
"5. Use the auth_exchange_code tool with the code to complete authentication",
|
|
67
|
-
],
|
|
68
|
-
}, null, 2),
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
75
|
-
return {
|
|
76
|
-
content: [
|
|
77
|
-
{
|
|
78
|
-
type: "text",
|
|
79
|
-
text: JSON.stringify({
|
|
80
|
-
success: false,
|
|
81
|
-
error: errorMessage,
|
|
82
|
-
hint: "Make sure TICKTICK_CLIENT_ID and TICKTICK_CLIENT_SECRET environment variables are set",
|
|
83
|
-
}, null, 2),
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
isError: true,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
/**
|
|
91
|
-
* Tool: Exchange authorization code for tokens
|
|
92
|
-
*
|
|
93
|
-
* Exchanges an authorization code (from the OAuth callback) for access and refresh tokens.
|
|
94
|
-
*/
|
|
95
|
-
server.tool("auth_exchange_code", "Exchange an OAuth authorization code for access tokens. Use this after the user has authorized the application and received a code.", {
|
|
96
|
-
code: z.string().describe("The authorization code from the OAuth callback URL"),
|
|
97
|
-
}, async ({ code }) => {
|
|
98
|
-
try {
|
|
99
|
-
const oauth = getOAuthHelper();
|
|
100
|
-
const tokens = await oauth.exchangeCode(code);
|
|
101
|
-
await oauth.storeToken(tokens);
|
|
102
|
-
return {
|
|
103
|
-
content: [
|
|
104
|
-
{
|
|
105
|
-
type: "text",
|
|
106
|
-
text: JSON.stringify({
|
|
107
|
-
success: true,
|
|
108
|
-
message: "Authentication successful! Tokens have been stored.",
|
|
109
|
-
expiresIn: tokens.expires_in,
|
|
110
|
-
tokenType: tokens.token_type,
|
|
111
|
-
}, null, 2),
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
118
|
-
return {
|
|
119
|
-
content: [
|
|
120
|
-
{
|
|
121
|
-
type: "text",
|
|
122
|
-
text: JSON.stringify({
|
|
123
|
-
success: false,
|
|
124
|
-
error: errorMessage,
|
|
125
|
-
}, null, 2),
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
isError: true,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
/**
|
|
133
|
-
* Tool: Check authentication status
|
|
134
|
-
*
|
|
135
|
-
* Returns information about the current authentication state.
|
|
136
|
-
*/
|
|
137
|
-
server.tool("auth_status", "Check the current authentication status. Shows whether the user is authenticated and when the token expires.", {}, async () => {
|
|
138
|
-
try {
|
|
139
|
-
const oauth = getOAuthHelper();
|
|
140
|
-
const status = await oauth.getAuthStatus();
|
|
141
|
-
if (!status.isAuthenticated) {
|
|
142
|
-
return {
|
|
143
|
-
content: [
|
|
144
|
-
{
|
|
145
|
-
type: "text",
|
|
146
|
-
text: JSON.stringify({
|
|
147
|
-
success: true,
|
|
148
|
-
isAuthenticated: false,
|
|
149
|
-
message: "Not authenticated. Use auth_get_authorization_url to start the OAuth flow.",
|
|
150
|
-
}, null, 2),
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
content: [
|
|
157
|
-
{
|
|
158
|
-
type: "text",
|
|
159
|
-
text: JSON.stringify({
|
|
160
|
-
success: true,
|
|
161
|
-
isAuthenticated: true,
|
|
162
|
-
isExpired: status.isExpired,
|
|
163
|
-
expiresAt: status.expiresAt,
|
|
164
|
-
expiresIn: status.expiresIn,
|
|
165
|
-
message: status.isExpired
|
|
166
|
-
? "Token is expired. It will be automatically refreshed on next API call."
|
|
167
|
-
: `Token is valid for ${status.expiresIn} more seconds.`,
|
|
168
|
-
}, null, 2),
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
catch (error) {
|
|
174
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
175
|
-
return {
|
|
176
|
-
content: [
|
|
177
|
-
{
|
|
178
|
-
type: "text",
|
|
179
|
-
text: JSON.stringify({
|
|
180
|
-
success: false,
|
|
181
|
-
error: errorMessage,
|
|
182
|
-
}, null, 2),
|
|
183
|
-
},
|
|
184
|
-
],
|
|
185
|
-
isError: true,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
/**
|
|
190
|
-
* Tool: Refresh access token
|
|
191
|
-
*
|
|
192
|
-
* Manually refresh the access token using the stored refresh token.
|
|
193
|
-
*/
|
|
194
|
-
server.tool("auth_refresh_token", "Manually refresh the OAuth access token. Usually not needed as tokens are automatically refreshed when expired.", {}, async () => {
|
|
195
|
-
try {
|
|
196
|
-
const oauth = getOAuthHelper();
|
|
197
|
-
const storedToken = await oauth.loadToken();
|
|
198
|
-
if (!storedToken) {
|
|
199
|
-
return {
|
|
200
|
-
content: [
|
|
201
|
-
{
|
|
202
|
-
type: "text",
|
|
203
|
-
text: JSON.stringify({
|
|
204
|
-
success: false,
|
|
205
|
-
error: "Not authenticated. No stored token found.",
|
|
206
|
-
}, null, 2),
|
|
207
|
-
},
|
|
208
|
-
],
|
|
209
|
-
isError: true,
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
const newTokens = await oauth.refreshToken(storedToken.refreshToken);
|
|
213
|
-
await oauth.storeToken(newTokens);
|
|
214
|
-
return {
|
|
215
|
-
content: [
|
|
216
|
-
{
|
|
217
|
-
type: "text",
|
|
218
|
-
text: JSON.stringify({
|
|
219
|
-
success: true,
|
|
220
|
-
message: "Token refreshed successfully!",
|
|
221
|
-
expiresIn: newTokens.expires_in,
|
|
222
|
-
}, null, 2),
|
|
223
|
-
},
|
|
224
|
-
],
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
catch (error) {
|
|
228
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
229
|
-
return {
|
|
230
|
-
content: [
|
|
231
|
-
{
|
|
232
|
-
type: "text",
|
|
233
|
-
text: JSON.stringify({
|
|
234
|
-
success: false,
|
|
235
|
-
error: errorMessage,
|
|
236
|
-
}, null, 2),
|
|
237
|
-
},
|
|
238
|
-
],
|
|
239
|
-
isError: true,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
/**
|
|
244
|
-
* Tool: Logout / Clear tokens
|
|
245
|
-
*
|
|
246
|
-
* Remove stored authentication tokens.
|
|
247
|
-
*/
|
|
248
|
-
server.tool("auth_logout", "Remove stored authentication tokens. This will log out the user from the TickTick integration.", {}, async () => {
|
|
249
|
-
try {
|
|
250
|
-
const oauth = getOAuthHelper();
|
|
251
|
-
await oauth.clearToken();
|
|
252
|
-
return {
|
|
253
|
-
content: [
|
|
254
|
-
{
|
|
255
|
-
type: "text",
|
|
256
|
-
text: JSON.stringify({
|
|
257
|
-
success: true,
|
|
258
|
-
message: "Logged out successfully. Stored tokens have been cleared.",
|
|
259
|
-
}, null, 2),
|
|
260
|
-
},
|
|
261
|
-
],
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
catch (error) {
|
|
265
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
266
|
-
return {
|
|
267
|
-
content: [
|
|
268
|
-
{
|
|
269
|
-
type: "text",
|
|
270
|
-
text: JSON.stringify({
|
|
271
|
-
success: false,
|
|
272
|
-
error: errorMessage,
|
|
273
|
-
}, null, 2),
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
isError: true,
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
});
|
|
63
|
+
// Register All Tools
|
|
280
64
|
// =============================================================================
|
|
65
|
+
// OAuth Authentication Tools
|
|
66
|
+
registerAuthGetAuthorizationUrlTool(server, getOAuthHelper);
|
|
67
|
+
registerAuthExchangeCodeTool(server, getOAuthHelper);
|
|
68
|
+
registerAuthStatusTool(server, getOAuthHelper);
|
|
69
|
+
registerAuthRefreshTokenTool(server, getOAuthHelper);
|
|
70
|
+
registerAuthLogoutTool(server, getOAuthHelper);
|
|
281
71
|
// User Tools
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Tool: Get current user
|
|
285
|
-
*
|
|
286
|
-
* Returns information about the authenticated TickTick user.
|
|
287
|
-
*/
|
|
288
|
-
server.tool("get_user", "Get the current authenticated user's information from TickTick.", {}, async () => {
|
|
289
|
-
try {
|
|
290
|
-
const client = await getClient();
|
|
291
|
-
const user = await client.getUser();
|
|
292
|
-
return {
|
|
293
|
-
content: [
|
|
294
|
-
{
|
|
295
|
-
type: "text",
|
|
296
|
-
text: JSON.stringify({
|
|
297
|
-
success: true,
|
|
298
|
-
user: {
|
|
299
|
-
id: user.id,
|
|
300
|
-
username: user.username,
|
|
301
|
-
name: user.name,
|
|
302
|
-
},
|
|
303
|
-
}, null, 2),
|
|
304
|
-
},
|
|
305
|
-
],
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
catch (error) {
|
|
309
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
310
|
-
return {
|
|
311
|
-
content: [
|
|
312
|
-
{
|
|
313
|
-
type: "text",
|
|
314
|
-
text: JSON.stringify({
|
|
315
|
-
success: false,
|
|
316
|
-
error: errorMessage,
|
|
317
|
-
}, null, 2),
|
|
318
|
-
},
|
|
319
|
-
],
|
|
320
|
-
isError: true,
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
// =============================================================================
|
|
72
|
+
registerGetUserTool(server, getClient);
|
|
325
73
|
// Project Tools
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
server.tool("list_projects", "List all projects in the user's TickTick account.", {}, async () => {
|
|
333
|
-
try {
|
|
334
|
-
const client = await getClient();
|
|
335
|
-
const projects = await client.listProjects();
|
|
336
|
-
return {
|
|
337
|
-
content: [
|
|
338
|
-
{
|
|
339
|
-
type: "text",
|
|
340
|
-
text: JSON.stringify({
|
|
341
|
-
success: true,
|
|
342
|
-
count: projects.length,
|
|
343
|
-
projects: projects.map((p) => ({
|
|
344
|
-
id: p.id,
|
|
345
|
-
name: p.name,
|
|
346
|
-
color: p.color,
|
|
347
|
-
viewMode: p.viewMode,
|
|
348
|
-
closed: p.closed,
|
|
349
|
-
})),
|
|
350
|
-
}, null, 2),
|
|
351
|
-
},
|
|
352
|
-
],
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
catch (error) {
|
|
356
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
357
|
-
return {
|
|
358
|
-
content: [
|
|
359
|
-
{
|
|
360
|
-
type: "text",
|
|
361
|
-
text: JSON.stringify({
|
|
362
|
-
success: false,
|
|
363
|
-
error: errorMessage,
|
|
364
|
-
}, null, 2),
|
|
365
|
-
},
|
|
366
|
-
],
|
|
367
|
-
isError: true,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
/**
|
|
372
|
-
* Tool: Get project with tasks
|
|
373
|
-
*
|
|
374
|
-
* Returns a specific project and all its tasks.
|
|
375
|
-
*/
|
|
376
|
-
server.tool("get_project", "Get a specific project and all its tasks.", {
|
|
377
|
-
projectId: z.string().describe("The ID of the project to retrieve"),
|
|
378
|
-
}, async ({ projectId }) => {
|
|
379
|
-
try {
|
|
380
|
-
const client = await getClient();
|
|
381
|
-
const data = await client.getProjectWithTasks(projectId);
|
|
382
|
-
return {
|
|
383
|
-
content: [
|
|
384
|
-
{
|
|
385
|
-
type: "text",
|
|
386
|
-
text: JSON.stringify({
|
|
387
|
-
success: true,
|
|
388
|
-
project: {
|
|
389
|
-
id: data.project.id,
|
|
390
|
-
name: data.project.name,
|
|
391
|
-
color: data.project.color,
|
|
392
|
-
viewMode: data.project.viewMode,
|
|
393
|
-
closed: data.project.closed,
|
|
394
|
-
},
|
|
395
|
-
taskCount: data.tasks.length,
|
|
396
|
-
tasks: data.tasks.map((t) => ({
|
|
397
|
-
id: t.id,
|
|
398
|
-
title: t.title,
|
|
399
|
-
content: t.content,
|
|
400
|
-
priority: t.priority,
|
|
401
|
-
status: t.status,
|
|
402
|
-
dueDate: t.dueDate,
|
|
403
|
-
tags: t.tags,
|
|
404
|
-
})),
|
|
405
|
-
}, null, 2),
|
|
406
|
-
},
|
|
407
|
-
],
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
catch (error) {
|
|
411
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
412
|
-
return {
|
|
413
|
-
content: [
|
|
414
|
-
{
|
|
415
|
-
type: "text",
|
|
416
|
-
text: JSON.stringify({
|
|
417
|
-
success: false,
|
|
418
|
-
error: errorMessage,
|
|
419
|
-
}, null, 2),
|
|
420
|
-
},
|
|
421
|
-
],
|
|
422
|
-
isError: true,
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
/**
|
|
427
|
-
* Tool: Get project by ID (metadata only)
|
|
428
|
-
*
|
|
429
|
-
* Returns a specific project's metadata without its tasks.
|
|
430
|
-
*/
|
|
431
|
-
server.tool("get_project_by_id", "Get a specific project's metadata by ID (without tasks). Use this when you only need project info, not its tasks.", {
|
|
432
|
-
projectId: z.string().describe("The ID of the project to retrieve"),
|
|
433
|
-
}, async ({ projectId }) => {
|
|
434
|
-
try {
|
|
435
|
-
const client = await getClient();
|
|
436
|
-
const project = await client.getProject(projectId);
|
|
437
|
-
return {
|
|
438
|
-
content: [
|
|
439
|
-
{
|
|
440
|
-
type: "text",
|
|
441
|
-
text: JSON.stringify({
|
|
442
|
-
success: true,
|
|
443
|
-
project: {
|
|
444
|
-
id: project.id,
|
|
445
|
-
name: project.name,
|
|
446
|
-
color: project.color,
|
|
447
|
-
viewMode: project.viewMode,
|
|
448
|
-
closed: project.closed,
|
|
449
|
-
},
|
|
450
|
-
}, null, 2),
|
|
451
|
-
},
|
|
452
|
-
],
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
catch (error) {
|
|
456
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
457
|
-
return {
|
|
458
|
-
content: [
|
|
459
|
-
{
|
|
460
|
-
type: "text",
|
|
461
|
-
text: JSON.stringify({
|
|
462
|
-
success: false,
|
|
463
|
-
error: errorMessage,
|
|
464
|
-
}, null, 2),
|
|
465
|
-
},
|
|
466
|
-
],
|
|
467
|
-
isError: true,
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
/**
|
|
472
|
-
* Tool: Create project
|
|
473
|
-
*
|
|
474
|
-
* Creates a new project.
|
|
475
|
-
*/
|
|
476
|
-
server.tool("create_project", "Create a new project in TickTick.", {
|
|
477
|
-
name: z.string().describe("The name of the project"),
|
|
478
|
-
color: z
|
|
479
|
-
.string()
|
|
480
|
-
.optional()
|
|
481
|
-
.describe('Hex color code (e.g., "#ff6b6b")'),
|
|
482
|
-
viewMode: z
|
|
483
|
-
.enum(["list", "kanban", "timeline"])
|
|
484
|
-
.optional()
|
|
485
|
-
.describe("View mode for the project"),
|
|
486
|
-
}, async ({ name, color, viewMode }) => {
|
|
487
|
-
try {
|
|
488
|
-
const client = await getClient();
|
|
489
|
-
const project = await client.createProject({
|
|
490
|
-
name,
|
|
491
|
-
color,
|
|
492
|
-
viewMode,
|
|
493
|
-
});
|
|
494
|
-
return {
|
|
495
|
-
content: [
|
|
496
|
-
{
|
|
497
|
-
type: "text",
|
|
498
|
-
text: JSON.stringify({
|
|
499
|
-
success: true,
|
|
500
|
-
message: `Project "${project.name}" created successfully!`,
|
|
501
|
-
project: {
|
|
502
|
-
id: project.id,
|
|
503
|
-
name: project.name,
|
|
504
|
-
color: project.color,
|
|
505
|
-
viewMode: project.viewMode,
|
|
506
|
-
},
|
|
507
|
-
}, null, 2),
|
|
508
|
-
},
|
|
509
|
-
],
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
catch (error) {
|
|
513
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
514
|
-
return {
|
|
515
|
-
content: [
|
|
516
|
-
{
|
|
517
|
-
type: "text",
|
|
518
|
-
text: JSON.stringify({
|
|
519
|
-
success: false,
|
|
520
|
-
error: errorMessage,
|
|
521
|
-
}, null, 2),
|
|
522
|
-
},
|
|
523
|
-
],
|
|
524
|
-
isError: true,
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
/**
|
|
529
|
-
* Tool: Update project
|
|
530
|
-
*
|
|
531
|
-
* Updates an existing project.
|
|
532
|
-
*/
|
|
533
|
-
server.tool("update_project", "Update an existing project in TickTick.", {
|
|
534
|
-
projectId: z.string().describe("The ID of the project to update"),
|
|
535
|
-
name: z.string().optional().describe("New name for the project"),
|
|
536
|
-
color: z
|
|
537
|
-
.string()
|
|
538
|
-
.optional()
|
|
539
|
-
.describe('New hex color code (e.g., "#ff6b6b")'),
|
|
540
|
-
viewMode: z
|
|
541
|
-
.enum(["list", "kanban", "timeline"])
|
|
542
|
-
.optional()
|
|
543
|
-
.describe("New view mode for the project"),
|
|
544
|
-
}, async ({ projectId, name, color, viewMode }) => {
|
|
545
|
-
try {
|
|
546
|
-
const client = await getClient();
|
|
547
|
-
const project = await client.updateProject(projectId, {
|
|
548
|
-
name,
|
|
549
|
-
color,
|
|
550
|
-
viewMode,
|
|
551
|
-
});
|
|
552
|
-
return {
|
|
553
|
-
content: [
|
|
554
|
-
{
|
|
555
|
-
type: "text",
|
|
556
|
-
text: JSON.stringify({
|
|
557
|
-
success: true,
|
|
558
|
-
message: `Project "${project.name}" updated successfully!`,
|
|
559
|
-
project: {
|
|
560
|
-
id: project.id,
|
|
561
|
-
name: project.name,
|
|
562
|
-
color: project.color,
|
|
563
|
-
viewMode: project.viewMode,
|
|
564
|
-
closed: project.closed,
|
|
565
|
-
},
|
|
566
|
-
}, null, 2),
|
|
567
|
-
},
|
|
568
|
-
],
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
catch (error) {
|
|
572
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
573
|
-
return {
|
|
574
|
-
content: [
|
|
575
|
-
{
|
|
576
|
-
type: "text",
|
|
577
|
-
text: JSON.stringify({
|
|
578
|
-
success: false,
|
|
579
|
-
error: errorMessage,
|
|
580
|
-
}, null, 2),
|
|
581
|
-
},
|
|
582
|
-
],
|
|
583
|
-
isError: true,
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
});
|
|
587
|
-
/**
|
|
588
|
-
* Tool: Delete project
|
|
589
|
-
*
|
|
590
|
-
* Deletes a project.
|
|
591
|
-
*/
|
|
592
|
-
server.tool("delete_project", "Delete a project from TickTick.", {
|
|
593
|
-
projectId: z.string().describe("The ID of the project to delete"),
|
|
594
|
-
}, async ({ projectId }) => {
|
|
595
|
-
try {
|
|
596
|
-
const client = await getClient();
|
|
597
|
-
await client.deleteProject(projectId);
|
|
598
|
-
return {
|
|
599
|
-
content: [
|
|
600
|
-
{
|
|
601
|
-
type: "text",
|
|
602
|
-
text: JSON.stringify({
|
|
603
|
-
success: true,
|
|
604
|
-
message: "Project deleted successfully!",
|
|
605
|
-
}, null, 2),
|
|
606
|
-
},
|
|
607
|
-
],
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
catch (error) {
|
|
611
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
612
|
-
return {
|
|
613
|
-
content: [
|
|
614
|
-
{
|
|
615
|
-
type: "text",
|
|
616
|
-
text: JSON.stringify({
|
|
617
|
-
success: false,
|
|
618
|
-
error: errorMessage,
|
|
619
|
-
}, null, 2),
|
|
620
|
-
},
|
|
621
|
-
],
|
|
622
|
-
isError: true,
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
// =============================================================================
|
|
74
|
+
registerListProjectsTool(server, getClient);
|
|
75
|
+
registerGetProjectTool(server, getClient);
|
|
76
|
+
registerGetProjectByIdTool(server, getClient);
|
|
77
|
+
registerCreateProjectTool(server, getClient);
|
|
78
|
+
registerUpdateProjectTool(server, getClient);
|
|
79
|
+
registerDeleteProjectTool(server, getClient);
|
|
627
80
|
// Task Tools
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
server
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
try {
|
|
639
|
-
const client = await getClient();
|
|
640
|
-
const data = await client.getProjectWithTasks(projectId);
|
|
641
|
-
return {
|
|
642
|
-
content: [
|
|
643
|
-
{
|
|
644
|
-
type: "text",
|
|
645
|
-
text: JSON.stringify({
|
|
646
|
-
success: true,
|
|
647
|
-
count: data.tasks.length,
|
|
648
|
-
tasks: data.tasks.map((t) => ({
|
|
649
|
-
id: t.id,
|
|
650
|
-
title: t.title,
|
|
651
|
-
content: t.content,
|
|
652
|
-
priority: t.priority,
|
|
653
|
-
status: t.status,
|
|
654
|
-
dueDate: t.dueDate,
|
|
655
|
-
startDate: t.startDate,
|
|
656
|
-
allDay: t.allDay,
|
|
657
|
-
tags: t.tags,
|
|
658
|
-
items: t.items?.map((item) => ({
|
|
659
|
-
id: item.id,
|
|
660
|
-
title: item.title,
|
|
661
|
-
status: item.status,
|
|
662
|
-
})),
|
|
663
|
-
})),
|
|
664
|
-
}, null, 2),
|
|
665
|
-
},
|
|
666
|
-
],
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
catch (error) {
|
|
670
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
671
|
-
return {
|
|
672
|
-
content: [
|
|
673
|
-
{
|
|
674
|
-
type: "text",
|
|
675
|
-
text: JSON.stringify({
|
|
676
|
-
success: false,
|
|
677
|
-
error: errorMessage,
|
|
678
|
-
}, null, 2),
|
|
679
|
-
},
|
|
680
|
-
],
|
|
681
|
-
isError: true,
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
/**
|
|
686
|
-
* Tool: Create task
|
|
687
|
-
*
|
|
688
|
-
* Creates a new task.
|
|
689
|
-
*/
|
|
690
|
-
server.tool("create_task", "Create a new task in TickTick.", {
|
|
691
|
-
title: z.string().describe("The title of the task"),
|
|
692
|
-
projectId: z
|
|
693
|
-
.string()
|
|
694
|
-
.optional()
|
|
695
|
-
.describe("The project ID (defaults to inbox if not specified)"),
|
|
696
|
-
content: z.string().optional().describe("Task description/notes"),
|
|
697
|
-
dueDate: z
|
|
698
|
-
.string()
|
|
699
|
-
.optional()
|
|
700
|
-
.describe("Due date in ISO 8601 format (e.g., 2024-01-15T17:00:00+0000)"),
|
|
701
|
-
priority: z
|
|
702
|
-
.number()
|
|
703
|
-
.min(0)
|
|
704
|
-
.max(5)
|
|
705
|
-
.optional()
|
|
706
|
-
.describe("Priority: 0=None, 1=Low, 3=Medium, 5=High"),
|
|
707
|
-
tags: z.array(z.string()).optional().describe("Array of tag names"),
|
|
708
|
-
allDay: z
|
|
709
|
-
.boolean()
|
|
710
|
-
.optional()
|
|
711
|
-
.describe("Whether this is an all-day task (no specific time)"),
|
|
712
|
-
startDate: z
|
|
713
|
-
.string()
|
|
714
|
-
.optional()
|
|
715
|
-
.describe("Start date in ISO 8601 format (e.g., 2024-01-15T09:00:00+0000)"),
|
|
716
|
-
timeZone: z
|
|
717
|
-
.string()
|
|
718
|
-
.optional()
|
|
719
|
-
.describe("IANA timezone (e.g., 'America/New_York', 'Europe/London')"),
|
|
720
|
-
reminders: z
|
|
721
|
-
.array(z.string())
|
|
722
|
-
.optional()
|
|
723
|
-
.describe("Array of reminder strings in iCalendar TRIGGER format (e.g., 'TRIGGER:P0DT9H0M0S' for 9:00 AM, 'TRIGGER:-PT15M' for 15 minutes before)"),
|
|
724
|
-
repeat: z
|
|
725
|
-
.string()
|
|
726
|
-
.optional()
|
|
727
|
-
.describe("Recurrence rule in RRULE format (e.g., 'RRULE:FREQ=DAILY;INTERVAL=1' for daily, 'RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR' for Mon/Wed/Fri)"),
|
|
728
|
-
items: z
|
|
729
|
-
.array(z.object({
|
|
730
|
-
title: z.string().describe("Subtask/checklist item text"),
|
|
731
|
-
status: z
|
|
732
|
-
.number()
|
|
733
|
-
.min(0)
|
|
734
|
-
.max(1)
|
|
735
|
-
.optional()
|
|
736
|
-
.describe("Status: 0=Unchecked (default), 1=Checked"),
|
|
737
|
-
}))
|
|
738
|
-
.optional()
|
|
739
|
-
.describe("Array of subtask/checklist items"),
|
|
740
|
-
}, async ({ title, projectId, content, dueDate, priority, tags, allDay, startDate, timeZone, reminders, repeat, items }) => {
|
|
741
|
-
try {
|
|
742
|
-
const client = await getClient();
|
|
743
|
-
const task = await client.createTask({
|
|
744
|
-
title,
|
|
745
|
-
projectId,
|
|
746
|
-
content,
|
|
747
|
-
dueDate,
|
|
748
|
-
priority,
|
|
749
|
-
allDay,
|
|
750
|
-
startDate,
|
|
751
|
-
timeZone,
|
|
752
|
-
reminders,
|
|
753
|
-
repeat,
|
|
754
|
-
items,
|
|
755
|
-
});
|
|
756
|
-
// If tags are provided, update the task with tags
|
|
757
|
-
let finalTask = task;
|
|
758
|
-
if (tags && tags.length > 0) {
|
|
759
|
-
finalTask = await client.updateTask(task.id, { tags });
|
|
760
|
-
}
|
|
761
|
-
return {
|
|
762
|
-
content: [
|
|
763
|
-
{
|
|
764
|
-
type: "text",
|
|
765
|
-
text: JSON.stringify({
|
|
766
|
-
success: true,
|
|
767
|
-
message: `Task "${finalTask.title}" created successfully!`,
|
|
768
|
-
task: {
|
|
769
|
-
id: finalTask.id,
|
|
770
|
-
title: finalTask.title,
|
|
771
|
-
projectId: finalTask.projectId,
|
|
772
|
-
content: finalTask.content,
|
|
773
|
-
priority: finalTask.priority,
|
|
774
|
-
dueDate: finalTask.dueDate,
|
|
775
|
-
startDate: finalTask.startDate,
|
|
776
|
-
allDay: finalTask.allDay,
|
|
777
|
-
timeZone: finalTask.timeZone,
|
|
778
|
-
reminders: finalTask.reminders,
|
|
779
|
-
repeat: finalTask.repeat,
|
|
780
|
-
status: finalTask.status,
|
|
781
|
-
tags: finalTask.tags,
|
|
782
|
-
items: finalTask.items?.map((item) => ({
|
|
783
|
-
id: item.id,
|
|
784
|
-
title: item.title,
|
|
785
|
-
status: item.status,
|
|
786
|
-
})),
|
|
787
|
-
},
|
|
788
|
-
}, null, 2),
|
|
789
|
-
},
|
|
790
|
-
],
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
catch (error) {
|
|
794
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
795
|
-
return {
|
|
796
|
-
content: [
|
|
797
|
-
{
|
|
798
|
-
type: "text",
|
|
799
|
-
text: JSON.stringify({
|
|
800
|
-
success: false,
|
|
801
|
-
error: errorMessage,
|
|
802
|
-
}, null, 2),
|
|
803
|
-
},
|
|
804
|
-
],
|
|
805
|
-
isError: true,
|
|
806
|
-
};
|
|
807
|
-
}
|
|
808
|
-
});
|
|
809
|
-
/**
|
|
810
|
-
* Tool: Update task
|
|
811
|
-
*
|
|
812
|
-
* Updates an existing task.
|
|
813
|
-
*/
|
|
814
|
-
server.tool("update_task", "Update an existing task in TickTick. Supports all task fields including scheduling, reminders, recurrence, and subtasks.", {
|
|
815
|
-
taskId: z.string().describe("The ID of the task to update"),
|
|
816
|
-
title: z.string().optional().describe("New title for the task"),
|
|
817
|
-
content: z.string().optional().describe("New description/notes"),
|
|
818
|
-
dueDate: z
|
|
819
|
-
.string()
|
|
820
|
-
.nullable()
|
|
821
|
-
.optional()
|
|
822
|
-
.describe("New due date (ISO 8601) or null to remove"),
|
|
823
|
-
priority: z
|
|
824
|
-
.number()
|
|
825
|
-
.min(0)
|
|
826
|
-
.max(5)
|
|
827
|
-
.optional()
|
|
828
|
-
.describe("New priority: 0=None, 1=Low, 3=Medium, 5=High"),
|
|
829
|
-
tags: z.array(z.string()).optional().describe("Array of tag names"),
|
|
830
|
-
projectId: z
|
|
831
|
-
.string()
|
|
832
|
-
.optional()
|
|
833
|
-
.describe("Move task to a different project by specifying the target project ID"),
|
|
834
|
-
allDay: z
|
|
835
|
-
.boolean()
|
|
836
|
-
.optional()
|
|
837
|
-
.describe("Whether this is an all-day task (no specific time)"),
|
|
838
|
-
startDate: z
|
|
839
|
-
.string()
|
|
840
|
-
.nullable()
|
|
841
|
-
.optional()
|
|
842
|
-
.describe("Start date in ISO 8601 format (e.g., 2024-01-15T09:00:00+0000) or null to remove"),
|
|
843
|
-
timeZone: z
|
|
844
|
-
.string()
|
|
845
|
-
.optional()
|
|
846
|
-
.describe("IANA timezone (e.g., 'America/New_York', 'Europe/London')"),
|
|
847
|
-
reminders: z
|
|
848
|
-
.array(z.string())
|
|
849
|
-
.nullable()
|
|
850
|
-
.optional()
|
|
851
|
-
.describe("Array of reminder strings in iCalendar TRIGGER format (e.g., 'TRIGGER:P0DT9H0M0S' for 9:00 AM, 'TRIGGER:-PT15M' for 15 minutes before) or null to clear all reminders"),
|
|
852
|
-
repeat: z
|
|
853
|
-
.string()
|
|
854
|
-
.nullable()
|
|
855
|
-
.optional()
|
|
856
|
-
.describe("Recurrence rule in RRULE format (e.g., 'RRULE:FREQ=DAILY;INTERVAL=1' for daily, 'RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR' for Mon/Wed/Fri) or null to remove recurrence"),
|
|
857
|
-
items: z
|
|
858
|
-
.array(z.object({
|
|
859
|
-
title: z.string().describe("Subtask/checklist item text"),
|
|
860
|
-
status: z
|
|
861
|
-
.number()
|
|
862
|
-
.min(0)
|
|
863
|
-
.max(1)
|
|
864
|
-
.optional()
|
|
865
|
-
.describe("Status: 0=Unchecked (default), 1=Checked"),
|
|
866
|
-
}))
|
|
867
|
-
.optional()
|
|
868
|
-
.describe("Array of subtask/checklist items. Note: This replaces existing items when provided."),
|
|
869
|
-
}, async ({ taskId, title, content, dueDate, priority, tags, projectId, allDay, startDate, timeZone, reminders, repeat, items }) => {
|
|
870
|
-
try {
|
|
871
|
-
const client = await getClient();
|
|
872
|
-
const task = await client.updateTask(taskId, {
|
|
873
|
-
title,
|
|
874
|
-
content,
|
|
875
|
-
dueDate,
|
|
876
|
-
priority,
|
|
877
|
-
tags,
|
|
878
|
-
projectId,
|
|
879
|
-
allDay,
|
|
880
|
-
startDate,
|
|
881
|
-
timeZone,
|
|
882
|
-
reminders: reminders === null ? undefined : reminders,
|
|
883
|
-
repeat: repeat === null ? "" : repeat,
|
|
884
|
-
items,
|
|
885
|
-
});
|
|
886
|
-
return {
|
|
887
|
-
content: [
|
|
888
|
-
{
|
|
889
|
-
type: "text",
|
|
890
|
-
text: JSON.stringify({
|
|
891
|
-
success: true,
|
|
892
|
-
message: `Task "${task.title}" updated successfully!`,
|
|
893
|
-
task: {
|
|
894
|
-
id: task.id,
|
|
895
|
-
title: task.title,
|
|
896
|
-
projectId: task.projectId,
|
|
897
|
-
content: task.content,
|
|
898
|
-
priority: task.priority,
|
|
899
|
-
dueDate: task.dueDate,
|
|
900
|
-
startDate: task.startDate,
|
|
901
|
-
allDay: task.allDay,
|
|
902
|
-
timeZone: task.timeZone,
|
|
903
|
-
reminders: task.reminders,
|
|
904
|
-
repeat: task.repeat,
|
|
905
|
-
status: task.status,
|
|
906
|
-
tags: task.tags,
|
|
907
|
-
items: task.items?.map((item) => ({
|
|
908
|
-
id: item.id,
|
|
909
|
-
title: item.title,
|
|
910
|
-
status: item.status,
|
|
911
|
-
})),
|
|
912
|
-
},
|
|
913
|
-
}, null, 2),
|
|
914
|
-
},
|
|
915
|
-
],
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
catch (error) {
|
|
919
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
920
|
-
return {
|
|
921
|
-
content: [
|
|
922
|
-
{
|
|
923
|
-
type: "text",
|
|
924
|
-
text: JSON.stringify({
|
|
925
|
-
success: false,
|
|
926
|
-
error: errorMessage,
|
|
927
|
-
}, null, 2),
|
|
928
|
-
},
|
|
929
|
-
],
|
|
930
|
-
isError: true,
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
});
|
|
934
|
-
/**
|
|
935
|
-
* Tool: Complete task
|
|
936
|
-
*
|
|
937
|
-
* Marks a task as complete.
|
|
938
|
-
*/
|
|
939
|
-
server.tool("complete_task", "Mark a task as complete in TickTick.", {
|
|
940
|
-
projectId: z.string().describe("The project ID containing the task"),
|
|
941
|
-
taskId: z.string().describe("The ID of the task to complete"),
|
|
942
|
-
}, async ({ projectId, taskId }) => {
|
|
943
|
-
try {
|
|
944
|
-
const client = await getClient();
|
|
945
|
-
await client.completeTask(projectId, taskId);
|
|
946
|
-
return {
|
|
947
|
-
content: [
|
|
948
|
-
{
|
|
949
|
-
type: "text",
|
|
950
|
-
text: JSON.stringify({
|
|
951
|
-
success: true,
|
|
952
|
-
message: "Task completed successfully!",
|
|
953
|
-
}, null, 2),
|
|
954
|
-
},
|
|
955
|
-
],
|
|
956
|
-
};
|
|
957
|
-
}
|
|
958
|
-
catch (error) {
|
|
959
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
960
|
-
return {
|
|
961
|
-
content: [
|
|
962
|
-
{
|
|
963
|
-
type: "text",
|
|
964
|
-
text: JSON.stringify({
|
|
965
|
-
success: false,
|
|
966
|
-
error: errorMessage,
|
|
967
|
-
}, null, 2),
|
|
968
|
-
},
|
|
969
|
-
],
|
|
970
|
-
isError: true,
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
});
|
|
974
|
-
/**
|
|
975
|
-
* Tool: Delete task
|
|
976
|
-
*
|
|
977
|
-
* Deletes a task.
|
|
978
|
-
*/
|
|
979
|
-
server.tool("delete_task", "Delete a task from TickTick.", {
|
|
980
|
-
projectId: z.string().describe("The project ID containing the task"),
|
|
981
|
-
taskId: z.string().describe("The ID of the task to delete"),
|
|
982
|
-
}, async ({ projectId, taskId }) => {
|
|
983
|
-
try {
|
|
984
|
-
const client = await getClient();
|
|
985
|
-
await client.deleteTask(projectId, taskId);
|
|
986
|
-
return {
|
|
987
|
-
content: [
|
|
988
|
-
{
|
|
989
|
-
type: "text",
|
|
990
|
-
text: JSON.stringify({
|
|
991
|
-
success: true,
|
|
992
|
-
message: "Task deleted successfully!",
|
|
993
|
-
}, null, 2),
|
|
994
|
-
},
|
|
995
|
-
],
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
catch (error) {
|
|
999
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1000
|
-
return {
|
|
1001
|
-
content: [
|
|
1002
|
-
{
|
|
1003
|
-
type: "text",
|
|
1004
|
-
text: JSON.stringify({
|
|
1005
|
-
success: false,
|
|
1006
|
-
error: errorMessage,
|
|
1007
|
-
}, null, 2),
|
|
1008
|
-
},
|
|
1009
|
-
],
|
|
1010
|
-
isError: true,
|
|
1011
|
-
};
|
|
1012
|
-
}
|
|
1013
|
-
});
|
|
1014
|
-
/**
|
|
1015
|
-
* Tool: Get task
|
|
1016
|
-
*
|
|
1017
|
-
* Gets a specific task by ID.
|
|
1018
|
-
*/
|
|
1019
|
-
server.tool("get_task", "Get a specific task from TickTick.", {
|
|
1020
|
-
projectId: z.string().describe("The project ID containing the task"),
|
|
1021
|
-
taskId: z.string().describe("The ID of the task to retrieve"),
|
|
1022
|
-
}, async ({ projectId, taskId }) => {
|
|
1023
|
-
try {
|
|
1024
|
-
const client = await getClient();
|
|
1025
|
-
const task = await client.getTask(projectId, taskId);
|
|
1026
|
-
return {
|
|
1027
|
-
content: [
|
|
1028
|
-
{
|
|
1029
|
-
type: "text",
|
|
1030
|
-
text: JSON.stringify({
|
|
1031
|
-
success: true,
|
|
1032
|
-
task: {
|
|
1033
|
-
id: task.id,
|
|
1034
|
-
title: task.title,
|
|
1035
|
-
projectId: task.projectId,
|
|
1036
|
-
content: task.content,
|
|
1037
|
-
priority: task.priority,
|
|
1038
|
-
status: task.status,
|
|
1039
|
-
dueDate: task.dueDate,
|
|
1040
|
-
startDate: task.startDate,
|
|
1041
|
-
allDay: task.allDay,
|
|
1042
|
-
tags: task.tags,
|
|
1043
|
-
items: task.items.map((item) => ({
|
|
1044
|
-
id: item.id,
|
|
1045
|
-
title: item.title,
|
|
1046
|
-
status: item.status,
|
|
1047
|
-
})),
|
|
1048
|
-
createdTime: task.createdTime,
|
|
1049
|
-
modifiedTime: task.modifiedTime,
|
|
1050
|
-
},
|
|
1051
|
-
}, null, 2),
|
|
1052
|
-
},
|
|
1053
|
-
],
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
catch (error) {
|
|
1057
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1058
|
-
return {
|
|
1059
|
-
content: [
|
|
1060
|
-
{
|
|
1061
|
-
type: "text",
|
|
1062
|
-
text: JSON.stringify({
|
|
1063
|
-
success: false,
|
|
1064
|
-
error: errorMessage,
|
|
1065
|
-
}, null, 2),
|
|
1066
|
-
},
|
|
1067
|
-
],
|
|
1068
|
-
isError: true,
|
|
1069
|
-
};
|
|
1070
|
-
}
|
|
1071
|
-
});
|
|
1072
|
-
/**
|
|
1073
|
-
* Tool: Batch create tasks
|
|
1074
|
-
*
|
|
1075
|
-
* Creates multiple tasks at once.
|
|
1076
|
-
*/
|
|
1077
|
-
server.tool("batch_create_tasks", "Create multiple tasks at once in TickTick. More efficient than creating tasks one by one.", {
|
|
1078
|
-
tasks: z
|
|
1079
|
-
.array(z.object({
|
|
1080
|
-
title: z.string().describe("The title of the task (required)"),
|
|
1081
|
-
projectId: z
|
|
1082
|
-
.string()
|
|
1083
|
-
.optional()
|
|
1084
|
-
.describe("The project ID (defaults to inbox if not specified)"),
|
|
1085
|
-
content: z.string().optional().describe("Task description/notes"),
|
|
1086
|
-
priority: z
|
|
1087
|
-
.number()
|
|
1088
|
-
.min(0)
|
|
1089
|
-
.max(5)
|
|
1090
|
-
.optional()
|
|
1091
|
-
.describe("Priority: 0=None, 1=Low, 3=Medium, 5=High"),
|
|
1092
|
-
dueDate: z
|
|
1093
|
-
.string()
|
|
1094
|
-
.optional()
|
|
1095
|
-
.describe("Due date in ISO 8601 format (e.g., 2024-01-15T17:00:00+0000)"),
|
|
1096
|
-
}))
|
|
1097
|
-
.describe("Array of task objects to create"),
|
|
1098
|
-
}, async ({ tasks }) => {
|
|
1099
|
-
try {
|
|
1100
|
-
const client = await getClient();
|
|
1101
|
-
const createdTasks = await client.batchCreateTasks(tasks);
|
|
1102
|
-
return {
|
|
1103
|
-
content: [
|
|
1104
|
-
{
|
|
1105
|
-
type: "text",
|
|
1106
|
-
text: JSON.stringify({
|
|
1107
|
-
success: true,
|
|
1108
|
-
message: `Successfully created ${createdTasks.length} tasks!`,
|
|
1109
|
-
count: createdTasks.length,
|
|
1110
|
-
tasks: createdTasks.map((t) => ({
|
|
1111
|
-
id: t.id,
|
|
1112
|
-
title: t.title,
|
|
1113
|
-
projectId: t.projectId,
|
|
1114
|
-
content: t.content,
|
|
1115
|
-
priority: t.priority,
|
|
1116
|
-
dueDate: t.dueDate,
|
|
1117
|
-
status: t.status,
|
|
1118
|
-
})),
|
|
1119
|
-
}, null, 2),
|
|
1120
|
-
},
|
|
1121
|
-
],
|
|
1122
|
-
};
|
|
1123
|
-
}
|
|
1124
|
-
catch (error) {
|
|
1125
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1126
|
-
return {
|
|
1127
|
-
content: [
|
|
1128
|
-
{
|
|
1129
|
-
type: "text",
|
|
1130
|
-
text: JSON.stringify({
|
|
1131
|
-
success: false,
|
|
1132
|
-
error: errorMessage,
|
|
1133
|
-
}, null, 2),
|
|
1134
|
-
},
|
|
1135
|
-
],
|
|
1136
|
-
isError: true,
|
|
1137
|
-
};
|
|
1138
|
-
}
|
|
1139
|
-
});
|
|
81
|
+
registerListTasksInProjectTool(server, getClient);
|
|
82
|
+
registerCreateTaskTool(server, getClient);
|
|
83
|
+
registerUpdateTaskTool(server, getClient);
|
|
84
|
+
registerCompleteTaskTool(server, getClient);
|
|
85
|
+
registerDeleteTaskTool(server, getClient);
|
|
86
|
+
registerGetTaskTool(server, getClient);
|
|
87
|
+
registerBatchCreateTasksTool(server, getClient);
|
|
88
|
+
registerGetTasksDueSoonTool(server, getClient);
|
|
89
|
+
registerSearchTasksTool(server, getClient);
|
|
90
|
+
registerGetHighPriorityTasksTool(server, getClient);
|
|
1140
91
|
// =============================================================================
|
|
1141
92
|
// Main Entry Point
|
|
1142
93
|
// =============================================================================
|