mcp-sunsama 0.10.2 → 0.11.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/CHANGELOG.md +13 -0
- package/README.md +1 -0
- package/bun.lock +2 -2
- package/dev/prd-update-task-due-date.md +128 -0
- package/dist/main.js +57 -3
- package/dist/schemas.d.ts +14 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +9 -0
- package/dist/schemas.test.js +102 -1
- package/package.json +2 -2
- package/src/main.ts +68 -2
- package/src/schemas.test.ts +142 -0
- package/src/schemas.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# mcp-sunsama
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9d0d694: feat: add update-task-due-date tool for setting and clearing task due dates
|
|
8
|
+
|
|
9
|
+
- Adds new `update-task-due-date` tool to set or clear task due dates using ISO datetime format or null
|
|
10
|
+
- Includes comprehensive parameter validation with Zod schema for taskId, dueDate, and limitResponsePayload
|
|
11
|
+
- Supports both setting due dates with ISO datetime strings and clearing due dates with null values
|
|
12
|
+
- Adds extensive test coverage with 11 test cases covering valid inputs, error cases, and edge conditions
|
|
13
|
+
- Updates API documentation and README with complete tool information
|
|
14
|
+
- Follows established patterns for dual transport support (stdio/httpStream) and response optimization
|
|
15
|
+
|
|
3
16
|
## 0.10.2
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -96,6 +96,7 @@ Add this configuration to your Claude Desktop MCP settings:
|
|
|
96
96
|
- `update-task-complete` - Mark tasks as complete
|
|
97
97
|
- `update-task-planned-time` - Update the planned time (time estimate) for tasks
|
|
98
98
|
- `update-task-notes` - Update task notes content (requires either `html` or `markdown` parameter, mutually exclusive)
|
|
99
|
+
- `update-task-due-date` - Update the due date for tasks (set or clear due dates)
|
|
99
100
|
- `update-task-snooze-date` - Reschedule tasks to different dates
|
|
100
101
|
- `update-task-backlog` - Move tasks to the backlog
|
|
101
102
|
- `delete-task` - Delete tasks permanently
|
package/bun.lock
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"@types/papaparse": "^5.3.16",
|
|
8
8
|
"fastmcp": "3.3.1",
|
|
9
9
|
"papaparse": "^5.5.3",
|
|
10
|
-
"sunsama-api": "0.
|
|
10
|
+
"sunsama-api": "0.9.0",
|
|
11
11
|
"zod": "3.24.4",
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
@@ -430,7 +430,7 @@
|
|
|
430
430
|
|
|
431
431
|
"strtok3": ["strtok3@10.3.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-3JWEZM6mfix/GCJBBUrkA8p2Id2pBkyTkVCJKto55w080QBKZ+8R171fGrbiSp+yMO/u6F8/yUh7K4V9K+YCnw=="],
|
|
432
432
|
|
|
433
|
-
"sunsama-api": ["sunsama-api@0.
|
|
433
|
+
"sunsama-api": ["sunsama-api@0.9.0", "", { "dependencies": { "graphql": "^16.11.0", "graphql-tag": "^2.12.6", "marked": "^14.1.3", "tough-cookie": "^5.1.2", "tslib": "^2.8.1", "turndown": "^7.2.0", "yjs": "^13.6.27", "zod": "^3.25.64" } }, "sha512-pSTS7+ZPjToeTnMiPuXDMrR/nbISl/fM5MqpdXV6LRBYlOmM/h9xUZO01BP9jhQYJWkasdw05KDHfCWYhUPjIg=="],
|
|
434
434
|
|
|
435
435
|
"term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="],
|
|
436
436
|
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Product Requirements Document: update-task-due-date
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Implement a new MCP tool `update-task-due-date` that allows updating the due date of an existing task in Sunsama.
|
|
5
|
+
|
|
6
|
+
## Research Findings
|
|
7
|
+
|
|
8
|
+
### Current State
|
|
9
|
+
- Tasks in Sunsama have a `dueDate` field (optional string, ISO format)
|
|
10
|
+
- The sunsama-api library doesn't have a dedicated `updateTaskDueDate` method
|
|
11
|
+
- Other update operations use GraphQL mutations with standardized patterns
|
|
12
|
+
- All existing update tools follow the same pattern: parameters → schema validation → client call → JSON response
|
|
13
|
+
|
|
14
|
+
### Technical Implementation Approach
|
|
15
|
+
Since there's no dedicated `updateTaskDueDate` method in the sunsama-api library, we need to implement this functionality by leveraging the existing patterns. Based on analysis of other task mutations, we have two options:
|
|
16
|
+
|
|
17
|
+
1. **Option A**: Use a general task update mutation (if available)
|
|
18
|
+
2. **Option B**: Extend the sunsama-api library functionality directly in our MCP server
|
|
19
|
+
|
|
20
|
+
For this implementation, we'll use **Option A** if a general update method exists, or create a custom GraphQL call following the existing patterns.
|
|
21
|
+
|
|
22
|
+
## Requirements
|
|
23
|
+
|
|
24
|
+
### Functional Requirements
|
|
25
|
+
1. Update a task's due date to a specific ISO date string
|
|
26
|
+
2. Clear a task's due date (set to null)
|
|
27
|
+
3. Validate the task exists before updating
|
|
28
|
+
4. Return success/failure status with updated fields
|
|
29
|
+
5. Support optional response payload limiting
|
|
30
|
+
|
|
31
|
+
### Input Parameters
|
|
32
|
+
- `taskId` (required): The ID of the task to update
|
|
33
|
+
- `dueDate` (required): New due date in ISO format (YYYY-MM-DD or ISO datetime), or null to clear
|
|
34
|
+
- `limitResponsePayload` (optional): Whether to limit response size (defaults to true)
|
|
35
|
+
|
|
36
|
+
### Output Format
|
|
37
|
+
JSON response with:
|
|
38
|
+
- `success`: Boolean indicating operation success
|
|
39
|
+
- `taskId`: The ID of the updated task
|
|
40
|
+
- `dueDate`: The new due date value
|
|
41
|
+
- `updatedFields`: Partial task data (null if limitResponsePayload is true)
|
|
42
|
+
|
|
43
|
+
### Error Handling
|
|
44
|
+
- Validate taskId format
|
|
45
|
+
- Validate dueDate format (ISO string or null)
|
|
46
|
+
- Handle task not found scenarios
|
|
47
|
+
- Handle API authentication errors
|
|
48
|
+
- Handle network/GraphQL errors
|
|
49
|
+
|
|
50
|
+
## Implementation Plan
|
|
51
|
+
|
|
52
|
+
### 1. Schema Definition (`schemas.ts`)
|
|
53
|
+
```typescript
|
|
54
|
+
export const updateTaskDueDateSchema = z.object({
|
|
55
|
+
taskId: z.string().min(1, "Task ID is required"),
|
|
56
|
+
dueDate: z.string().datetime().nullable().describe("Due date in ISO format or null to clear"),
|
|
57
|
+
limitResponsePayload: z.boolean().optional().describe("Whether to limit response payload size")
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. Tool Implementation (`main.ts`)
|
|
62
|
+
- Follow existing pattern from `update-task-planned-time`
|
|
63
|
+
- Extract parameters with validation
|
|
64
|
+
- Call sunsama-api method or custom GraphQL mutation
|
|
65
|
+
- Format and return JSON response
|
|
66
|
+
- Include comprehensive error handling and logging
|
|
67
|
+
|
|
68
|
+
### 3. API Extension Strategy
|
|
69
|
+
If no direct method exists in sunsama-api:
|
|
70
|
+
- Create custom GraphQL mutation similar to `updateTaskPlannedTime`
|
|
71
|
+
- Use `UPDATE_TASK_PAYLOAD_FRAGMENT` for consistent response format
|
|
72
|
+
- Follow existing authentication and request patterns
|
|
73
|
+
|
|
74
|
+
### 4. Test Coverage
|
|
75
|
+
- Parameter validation tests
|
|
76
|
+
- Success scenarios (set date, clear date)
|
|
77
|
+
- Error scenarios (invalid taskId, invalid date format, task not found)
|
|
78
|
+
- Response format validation
|
|
79
|
+
|
|
80
|
+
## Technical Notes
|
|
81
|
+
|
|
82
|
+
### Due Date Format
|
|
83
|
+
- Accept ISO 8601 date strings (both date-only and datetime formats)
|
|
84
|
+
- Store as ISO string in Sunsama's format
|
|
85
|
+
- Allow null to clear the due date
|
|
86
|
+
|
|
87
|
+
### Consistency with Existing Tools
|
|
88
|
+
- Use same error handling patterns as other update tools
|
|
89
|
+
- Use same logging format and parameter extraction
|
|
90
|
+
- Use same JSON response structure
|
|
91
|
+
- Apply same optional response payload limiting
|
|
92
|
+
|
|
93
|
+
### GraphQL Implementation
|
|
94
|
+
If custom mutation needed:
|
|
95
|
+
```graphql
|
|
96
|
+
mutation updateTaskDueDate($input: UpdateTaskDueDateInput!) {
|
|
97
|
+
updateTaskDueDate(input: $input) {
|
|
98
|
+
...UpdateTaskPayload
|
|
99
|
+
__typename
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Integration Points
|
|
105
|
+
|
|
106
|
+
### MCP Server Documentation
|
|
107
|
+
- Update `sunsama://api/docs` resource with new tool information
|
|
108
|
+
- Include usage examples and parameter descriptions
|
|
109
|
+
- Document relationship to other task update tools
|
|
110
|
+
|
|
111
|
+
### README Updates
|
|
112
|
+
- Add to task management section
|
|
113
|
+
- Include usage examples
|
|
114
|
+
- Update tool list
|
|
115
|
+
|
|
116
|
+
## Success Criteria
|
|
117
|
+
1. Tool successfully updates task due dates via MCP interface
|
|
118
|
+
2. Tool properly validates all input parameters
|
|
119
|
+
3. Tool handles all error scenarios gracefully
|
|
120
|
+
4. Tool follows established patterns and conventions
|
|
121
|
+
5. Comprehensive test coverage passes
|
|
122
|
+
6. Documentation is complete and accurate
|
|
123
|
+
|
|
124
|
+
## Dependencies
|
|
125
|
+
- Existing sunsama-api GraphQL infrastructure
|
|
126
|
+
- Zod schema validation system
|
|
127
|
+
- FastMCP tool registration system
|
|
128
|
+
- Task identification and authentication systems
|
package/dist/main.js
CHANGED
|
@@ -3,7 +3,7 @@ import { FastMCP } from "fastmcp";
|
|
|
3
3
|
import { httpStreamAuthenticator } from "./auth/http.js";
|
|
4
4
|
import { initializeStdioAuth } from "./auth/stdio.js";
|
|
5
5
|
import { getTransportConfig } from "./config/transport.js";
|
|
6
|
-
import { createTaskSchema, deleteTaskSchema, getArchivedTasksSchema, getStreamsSchema, getTaskByIdSchema, getTasksBacklogSchema, getTasksByDaySchema, getUserSchema, updateTaskBacklogSchema, updateTaskCompleteSchema, updateTaskNotesSchema, updateTaskPlannedTimeSchema, updateTaskSnoozeDateSchema } from "./schemas.js";
|
|
6
|
+
import { createTaskSchema, deleteTaskSchema, getArchivedTasksSchema, getStreamsSchema, getTaskByIdSchema, getTasksBacklogSchema, getTasksByDaySchema, getUserSchema, updateTaskBacklogSchema, updateTaskCompleteSchema, updateTaskDueDateSchema, updateTaskNotesSchema, updateTaskPlannedTimeSchema, updateTaskSnoozeDateSchema } from "./schemas.js";
|
|
7
7
|
import { getSunsamaClient } from "./utils/client-resolver.js";
|
|
8
8
|
import { filterTasksByCompletion } from "./utils/task-filters.js";
|
|
9
9
|
import { trimTasksForResponse } from "./utils/task-trimmer.js";
|
|
@@ -16,7 +16,7 @@ if (transportConfig.transportType === "stdio") {
|
|
|
16
16
|
}
|
|
17
17
|
const server = new FastMCP({
|
|
18
18
|
name: "Sunsama API Server",
|
|
19
|
-
version: "0.
|
|
19
|
+
version: "0.11.0",
|
|
20
20
|
instructions: `
|
|
21
21
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
22
22
|
|
|
@@ -24,7 +24,7 @@ Available tools:
|
|
|
24
24
|
- Authentication: login, logout, check authentication status
|
|
25
25
|
- User operations: get current user information
|
|
26
26
|
- Task operations: get tasks by day, get backlog tasks, get archived tasks, get task by ID
|
|
27
|
-
- Task mutations: create tasks, mark complete, delete tasks, reschedule tasks, update planned time, update task notes
|
|
27
|
+
- Task mutations: create tasks, mark complete, delete tasks, reschedule tasks, update planned time, update task notes, update task due date
|
|
28
28
|
- Stream operations: get streams/channels for the user's group
|
|
29
29
|
|
|
30
30
|
Authentication is required for all operations. You can either:
|
|
@@ -625,6 +625,53 @@ server.addTool({
|
|
|
625
625
|
}
|
|
626
626
|
}
|
|
627
627
|
});
|
|
628
|
+
server.addTool({
|
|
629
|
+
name: "update-task-due-date",
|
|
630
|
+
description: "Update the due date for a task",
|
|
631
|
+
parameters: updateTaskDueDateSchema,
|
|
632
|
+
execute: async (args, { session, log }) => {
|
|
633
|
+
try {
|
|
634
|
+
// Extract parameters
|
|
635
|
+
const { taskId, dueDate, limitResponsePayload } = args;
|
|
636
|
+
log.info("Updating task due date", {
|
|
637
|
+
taskId: taskId,
|
|
638
|
+
dueDate: dueDate,
|
|
639
|
+
limitResponsePayload: limitResponsePayload
|
|
640
|
+
});
|
|
641
|
+
// Get the appropriate client based on transport type
|
|
642
|
+
const sunsamaClient = getSunsamaClient(session);
|
|
643
|
+
// Call sunsamaClient.updateTaskDueDate(taskId, dueDate, limitResponsePayload)
|
|
644
|
+
const result = await sunsamaClient.updateTaskDueDate(taskId, dueDate, limitResponsePayload);
|
|
645
|
+
log.info("Successfully updated task due date", {
|
|
646
|
+
taskId: taskId,
|
|
647
|
+
dueDate: dueDate,
|
|
648
|
+
success: result.success
|
|
649
|
+
});
|
|
650
|
+
return {
|
|
651
|
+
content: [
|
|
652
|
+
{
|
|
653
|
+
type: "text",
|
|
654
|
+
text: JSON.stringify({
|
|
655
|
+
success: result.success,
|
|
656
|
+
taskId: taskId,
|
|
657
|
+
dueDate: dueDate,
|
|
658
|
+
dueDateUpdated: true,
|
|
659
|
+
updatedFields: result.updatedFields
|
|
660
|
+
})
|
|
661
|
+
}
|
|
662
|
+
]
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
log.error("Failed to update task due date", {
|
|
667
|
+
taskId: args.taskId,
|
|
668
|
+
dueDate: args.dueDate,
|
|
669
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
670
|
+
});
|
|
671
|
+
throw new Error(`Failed to update task due date: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
});
|
|
628
675
|
// Stream Operations
|
|
629
676
|
server.addTool({
|
|
630
677
|
name: "get-streams",
|
|
@@ -764,6 +811,13 @@ Uses HTTP Basic Auth headers (per-request authentication):
|
|
|
764
811
|
- Returns: JSON with update result
|
|
765
812
|
- Note: Exactly one of \`html\` or \`markdown\` must be provided (mutually exclusive)
|
|
766
813
|
|
|
814
|
+
- **update-task-due-date**: Update the due date for a task
|
|
815
|
+
- Parameters:
|
|
816
|
+
- \`taskId\` (required): The ID of the task to update due date for
|
|
817
|
+
- \`dueDate\` (required): Due date in ISO format (YYYY-MM-DDTHH:mm:ssZ) or null to clear the due date
|
|
818
|
+
- \`limitResponsePayload\` (optional): Whether to limit response size
|
|
819
|
+
- Returns: JSON with update result
|
|
820
|
+
|
|
767
821
|
### Stream Operations
|
|
768
822
|
- **get-streams**: Get streams for the user's group
|
|
769
823
|
- Parameters: none
|
package/dist/schemas.d.ts
CHANGED
|
@@ -171,6 +171,19 @@ export declare const updateTaskNotesSchema: z.ZodEffects<z.ZodObject<{
|
|
|
171
171
|
html?: string | undefined;
|
|
172
172
|
markdown?: string | undefined;
|
|
173
173
|
}>;
|
|
174
|
+
export declare const updateTaskDueDateSchema: z.ZodObject<{
|
|
175
|
+
taskId: z.ZodString;
|
|
176
|
+
dueDate: z.ZodUnion<[z.ZodString, z.ZodNull]>;
|
|
177
|
+
limitResponsePayload: z.ZodOptional<z.ZodBoolean>;
|
|
178
|
+
}, "strip", z.ZodTypeAny, {
|
|
179
|
+
taskId: string;
|
|
180
|
+
dueDate: string | null;
|
|
181
|
+
limitResponsePayload?: boolean | undefined;
|
|
182
|
+
}, {
|
|
183
|
+
taskId: string;
|
|
184
|
+
dueDate: string | null;
|
|
185
|
+
limitResponsePayload?: boolean | undefined;
|
|
186
|
+
}>;
|
|
174
187
|
/**
|
|
175
188
|
* Response Type Schemas (for validation and documentation)
|
|
176
189
|
*/
|
|
@@ -606,6 +619,7 @@ export type DeleteTaskInput = z.infer<typeof deleteTaskSchema>;
|
|
|
606
619
|
export type UpdateTaskSnoozeDateInput = z.infer<typeof updateTaskSnoozeDateSchema>;
|
|
607
620
|
export type UpdateTaskPlannedTimeInput = z.infer<typeof updateTaskPlannedTimeSchema>;
|
|
608
621
|
export type UpdateTaskNotesInput = z.infer<typeof updateTaskNotesSchema>;
|
|
622
|
+
export type UpdateTaskDueDateInput = z.infer<typeof updateTaskDueDateSchema>;
|
|
609
623
|
export type User = z.infer<typeof userSchema>;
|
|
610
624
|
export type Task = z.infer<typeof taskSchema>;
|
|
611
625
|
export type Stream = z.infer<typeof streamSchema>;
|
package/dist/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AAEH,eAAO,MAAM,gBAAgB,wCAO3B,CAAC;AAEH;;GAEG;AAGH,eAAO,MAAM,sBAAsB,+CAA6C,CAAC;AAGjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAI9B,CAAC;AAGH,eAAO,MAAM,qBAAqB,gDAAe,CAAC;AAGlD,eAAO,MAAM,sBAAsB;;;;;;;;;EAGjC,CAAC;AAGH,eAAO,MAAM,iBAAiB;;;;;;EAE5B,CAAC;AAEH;;GAEG;AAGH,eAAO,MAAM,aAAa,gDAAe,CAAC;AAE1C;;GAEG;AAGH,eAAO,MAAM,gBAAgB,gDAAe,CAAC;AAE7C;;GAEG;AAGH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS3B,CAAC;AAGH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;EAInC,CAAC;AAGH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAI3B,CAAC;AAGH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;EAKrC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;EAIlC,CAAC;AAGH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;EAItC,CAAC;AAGH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;EAgBjC,CAAC;
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AAEH,eAAO,MAAM,gBAAgB,wCAO3B,CAAC;AAEH;;GAEG;AAGH,eAAO,MAAM,sBAAsB,+CAA6C,CAAC;AAGjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAI9B,CAAC;AAGH,eAAO,MAAM,qBAAqB,gDAAe,CAAC;AAGlD,eAAO,MAAM,sBAAsB;;;;;;;;;EAGjC,CAAC;AAGH,eAAO,MAAM,iBAAiB;;;;;;EAE5B,CAAC;AAEH;;GAEG;AAGH,eAAO,MAAM,aAAa,gDAAe,CAAC;AAE1C;;GAEG;AAGH,eAAO,MAAM,gBAAgB,gDAAe,CAAC;AAE7C;;GAEG;AAGH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS3B,CAAC;AAGH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;EAInC,CAAC;AAGH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAI3B,CAAC;AAGH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;EAKrC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;EAIlC,CAAC;AAGH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;EAItC,CAAC;AAGH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;EAgBjC,CAAC;AAGF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;EAOlC,CAAC;AAEH;;GAEG;AAGH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;EAO5B,CAAC;AAGH,eAAO,MAAM,WAAW;;;;;;;;;;;;EAItB,CAAC;AAGH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKrB,CAAC;AAGH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYrB,CAAC;AAGH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;EAQvB,CAAC;AAEH;;GAEG;AAGH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE7B,CAAC;AAGH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG9B,CAAC;AAGH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAI9B,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACrE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACzE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC3E,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC/D,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC/E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC/D,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACnF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AACrF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACzE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE7E,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC9C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAC9C,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
package/dist/schemas.js
CHANGED
|
@@ -103,6 +103,15 @@ export const updateTaskNotesSchema = z.object({
|
|
|
103
103
|
message: "Exactly one of 'html' or 'markdown' must be provided",
|
|
104
104
|
path: [], // This will show the error at the root level
|
|
105
105
|
});
|
|
106
|
+
// Update task due date parameters
|
|
107
|
+
export const updateTaskDueDateSchema = z.object({
|
|
108
|
+
taskId: z.string().min(1, "Task ID is required").describe("The ID of the task to update due date for"),
|
|
109
|
+
dueDate: z.union([
|
|
110
|
+
z.string().datetime("Must be a valid ISO date-time string"),
|
|
111
|
+
z.null()
|
|
112
|
+
]).describe("Due date in ISO format (YYYY-MM-DDTHH:mm:ssZ) or null to clear the due date"),
|
|
113
|
+
limitResponsePayload: z.boolean().optional().describe("Whether to limit the response payload size"),
|
|
114
|
+
});
|
|
106
115
|
/**
|
|
107
116
|
* Response Type Schemas (for validation and documentation)
|
|
108
117
|
*/
|
package/dist/schemas.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, test, expect } from "bun:test";
|
|
2
|
-
import { completionFilterSchema, getTasksByDaySchema, getTasksBacklogSchema, getArchivedTasksSchema, getUserSchema, getStreamsSchema, createTaskSchema, updateTaskCompleteSchema, deleteTaskSchema, updateTaskSnoozeDateSchema, updateTaskBacklogSchema, updateTaskPlannedTimeSchema, updateTaskNotesSchema, userProfileSchema, groupSchema, userSchema, taskSchema, streamSchema, userResponseSchema, tasksResponseSchema, streamsResponseSchema, errorResponseSchema, } from "./schemas.js";
|
|
2
|
+
import { completionFilterSchema, getTasksByDaySchema, getTasksBacklogSchema, getArchivedTasksSchema, getUserSchema, getStreamsSchema, createTaskSchema, updateTaskCompleteSchema, deleteTaskSchema, updateTaskSnoozeDateSchema, updateTaskBacklogSchema, updateTaskPlannedTimeSchema, updateTaskNotesSchema, updateTaskDueDateSchema, userProfileSchema, groupSchema, userSchema, taskSchema, streamSchema, userResponseSchema, tasksResponseSchema, streamsResponseSchema, errorResponseSchema, } from "./schemas.js";
|
|
3
3
|
describe("Tool Parameter Schemas", () => {
|
|
4
4
|
describe("completionFilterSchema", () => {
|
|
5
5
|
test("should accept valid completion filter values", () => {
|
|
@@ -320,6 +320,107 @@ describe("Tool Parameter Schemas", () => {
|
|
|
320
320
|
})).not.toThrow();
|
|
321
321
|
});
|
|
322
322
|
});
|
|
323
|
+
describe("updateTaskDueDateSchema", () => {
|
|
324
|
+
test("should accept valid ISO date string", () => {
|
|
325
|
+
const validInput = {
|
|
326
|
+
taskId: "task-123",
|
|
327
|
+
dueDate: "2024-06-21T04:00:00.000Z",
|
|
328
|
+
limitResponsePayload: true,
|
|
329
|
+
};
|
|
330
|
+
expect(() => updateTaskDueDateSchema.parse(validInput)).not.toThrow();
|
|
331
|
+
});
|
|
332
|
+
test("should accept valid ISO date-time string with Z timezone", () => {
|
|
333
|
+
const validInput = {
|
|
334
|
+
taskId: "task-123",
|
|
335
|
+
dueDate: "2024-06-21T14:30:00.000Z",
|
|
336
|
+
limitResponsePayload: false,
|
|
337
|
+
};
|
|
338
|
+
expect(() => updateTaskDueDateSchema.parse(validInput)).not.toThrow();
|
|
339
|
+
});
|
|
340
|
+
test("should accept null to clear due date", () => {
|
|
341
|
+
const validInput = {
|
|
342
|
+
taskId: "task-123",
|
|
343
|
+
dueDate: null,
|
|
344
|
+
limitResponsePayload: true,
|
|
345
|
+
};
|
|
346
|
+
expect(() => updateTaskDueDateSchema.parse(validInput)).not.toThrow();
|
|
347
|
+
});
|
|
348
|
+
test("should accept minimal required input with ISO date", () => {
|
|
349
|
+
const minimalInput = {
|
|
350
|
+
taskId: "task-123",
|
|
351
|
+
dueDate: "2024-06-21T09:00:00Z",
|
|
352
|
+
};
|
|
353
|
+
expect(() => updateTaskDueDateSchema.parse(minimalInput)).not.toThrow();
|
|
354
|
+
});
|
|
355
|
+
test("should accept minimal required input with null", () => {
|
|
356
|
+
const minimalInput = {
|
|
357
|
+
taskId: "task-123",
|
|
358
|
+
dueDate: null,
|
|
359
|
+
};
|
|
360
|
+
expect(() => updateTaskDueDateSchema.parse(minimalInput)).not.toThrow();
|
|
361
|
+
});
|
|
362
|
+
test("should reject empty task ID", () => {
|
|
363
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
364
|
+
taskId: "",
|
|
365
|
+
dueDate: "2024-06-21T09:00:00Z",
|
|
366
|
+
})).toThrow();
|
|
367
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
368
|
+
dueDate: "2024-06-21T09:00:00Z",
|
|
369
|
+
})).toThrow();
|
|
370
|
+
});
|
|
371
|
+
test("should reject invalid date formats", () => {
|
|
372
|
+
// Date-only format
|
|
373
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
374
|
+
taskId: "task-123",
|
|
375
|
+
dueDate: "2024-06-21",
|
|
376
|
+
})).toThrow();
|
|
377
|
+
// Non-ISO format
|
|
378
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
379
|
+
taskId: "task-123",
|
|
380
|
+
dueDate: "06/21/2024",
|
|
381
|
+
})).toThrow();
|
|
382
|
+
// Invalid ISO format
|
|
383
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
384
|
+
taskId: "task-123",
|
|
385
|
+
dueDate: "2024-06-21T25:00:00Z",
|
|
386
|
+
})).toThrow();
|
|
387
|
+
// Plain text
|
|
388
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
389
|
+
taskId: "task-123",
|
|
390
|
+
dueDate: "tomorrow",
|
|
391
|
+
})).toThrow();
|
|
392
|
+
// Empty string
|
|
393
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
394
|
+
taskId: "task-123",
|
|
395
|
+
dueDate: "",
|
|
396
|
+
})).toThrow();
|
|
397
|
+
});
|
|
398
|
+
test("should reject undefined due date", () => {
|
|
399
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
400
|
+
taskId: "task-123",
|
|
401
|
+
dueDate: undefined,
|
|
402
|
+
})).toThrow();
|
|
403
|
+
});
|
|
404
|
+
test("should reject missing due date", () => {
|
|
405
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
406
|
+
taskId: "task-123",
|
|
407
|
+
})).toThrow();
|
|
408
|
+
});
|
|
409
|
+
test("should reject non-string, non-null due date values", () => {
|
|
410
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
411
|
+
taskId: "task-123",
|
|
412
|
+
dueDate: new Date(),
|
|
413
|
+
})).toThrow();
|
|
414
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
415
|
+
taskId: "task-123",
|
|
416
|
+
dueDate: 1640995200000, // timestamp
|
|
417
|
+
})).toThrow();
|
|
418
|
+
expect(() => updateTaskDueDateSchema.parse({
|
|
419
|
+
taskId: "task-123",
|
|
420
|
+
dueDate: true,
|
|
421
|
+
})).toThrow();
|
|
422
|
+
});
|
|
423
|
+
});
|
|
323
424
|
});
|
|
324
425
|
describe("Response Schemas", () => {
|
|
325
426
|
describe("userProfileSchema", () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-sunsama",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "MCP server for Sunsama API integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@types/papaparse": "^5.3.16",
|
|
27
27
|
"fastmcp": "3.3.1",
|
|
28
28
|
"papaparse": "^5.5.3",
|
|
29
|
-
"sunsama-api": "0.
|
|
29
|
+
"sunsama-api": "0.9.0",
|
|
30
30
|
"zod": "3.24.4"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
package/src/main.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getUserSchema,
|
|
17
17
|
updateTaskBacklogSchema,
|
|
18
18
|
updateTaskCompleteSchema,
|
|
19
|
+
updateTaskDueDateSchema,
|
|
19
20
|
updateTaskNotesSchema,
|
|
20
21
|
updateTaskPlannedTimeSchema,
|
|
21
22
|
updateTaskSnoozeDateSchema
|
|
@@ -35,7 +36,7 @@ if (transportConfig.transportType === "stdio") {
|
|
|
35
36
|
|
|
36
37
|
const server = new FastMCP({
|
|
37
38
|
name: "Sunsama API Server",
|
|
38
|
-
version: "0.
|
|
39
|
+
version: "0.11.0",
|
|
39
40
|
instructions: `
|
|
40
41
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
41
42
|
|
|
@@ -43,7 +44,7 @@ Available tools:
|
|
|
43
44
|
- Authentication: login, logout, check authentication status
|
|
44
45
|
- User operations: get current user information
|
|
45
46
|
- Task operations: get tasks by day, get backlog tasks, get archived tasks, get task by ID
|
|
46
|
-
- Task mutations: create tasks, mark complete, delete tasks, reschedule tasks, update planned time, update task notes
|
|
47
|
+
- Task mutations: create tasks, mark complete, delete tasks, reschedule tasks, update planned time, update task notes, update task due date
|
|
47
48
|
- Stream operations: get streams/channels for the user's group
|
|
48
49
|
|
|
49
50
|
Authentication is required for all operations. You can either:
|
|
@@ -762,6 +763,64 @@ server.addTool({
|
|
|
762
763
|
}
|
|
763
764
|
});
|
|
764
765
|
|
|
766
|
+
server.addTool({
|
|
767
|
+
name: "update-task-due-date",
|
|
768
|
+
description: "Update the due date for a task",
|
|
769
|
+
parameters: updateTaskDueDateSchema,
|
|
770
|
+
execute: async (args, {session, log}) => {
|
|
771
|
+
try {
|
|
772
|
+
// Extract parameters
|
|
773
|
+
const {taskId, dueDate, limitResponsePayload} = args;
|
|
774
|
+
|
|
775
|
+
log.info("Updating task due date", {
|
|
776
|
+
taskId: taskId,
|
|
777
|
+
dueDate: dueDate,
|
|
778
|
+
limitResponsePayload: limitResponsePayload
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// Get the appropriate client based on transport type
|
|
782
|
+
const sunsamaClient = getSunsamaClient(session as SessionData | null);
|
|
783
|
+
|
|
784
|
+
// Call sunsamaClient.updateTaskDueDate(taskId, dueDate, limitResponsePayload)
|
|
785
|
+
const result = await sunsamaClient.updateTaskDueDate(
|
|
786
|
+
taskId,
|
|
787
|
+
dueDate,
|
|
788
|
+
limitResponsePayload
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
log.info("Successfully updated task due date", {
|
|
792
|
+
taskId: taskId,
|
|
793
|
+
dueDate: dueDate,
|
|
794
|
+
success: result.success
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
return {
|
|
798
|
+
content: [
|
|
799
|
+
{
|
|
800
|
+
type: "text",
|
|
801
|
+
text: JSON.stringify({
|
|
802
|
+
success: result.success,
|
|
803
|
+
taskId: taskId,
|
|
804
|
+
dueDate: dueDate,
|
|
805
|
+
dueDateUpdated: true,
|
|
806
|
+
updatedFields: result.updatedFields
|
|
807
|
+
})
|
|
808
|
+
}
|
|
809
|
+
]
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
} catch (error) {
|
|
813
|
+
log.error("Failed to update task due date", {
|
|
814
|
+
taskId: args.taskId,
|
|
815
|
+
dueDate: args.dueDate,
|
|
816
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
throw new Error(`Failed to update task due date: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
|
|
765
824
|
// Stream Operations
|
|
766
825
|
server.addTool({
|
|
767
826
|
name: "get-streams",
|
|
@@ -907,6 +966,13 @@ Uses HTTP Basic Auth headers (per-request authentication):
|
|
|
907
966
|
- Returns: JSON with update result
|
|
908
967
|
- Note: Exactly one of \`html\` or \`markdown\` must be provided (mutually exclusive)
|
|
909
968
|
|
|
969
|
+
- **update-task-due-date**: Update the due date for a task
|
|
970
|
+
- Parameters:
|
|
971
|
+
- \`taskId\` (required): The ID of the task to update due date for
|
|
972
|
+
- \`dueDate\` (required): Due date in ISO format (YYYY-MM-DDTHH:mm:ssZ) or null to clear the due date
|
|
973
|
+
- \`limitResponsePayload\` (optional): Whether to limit response size
|
|
974
|
+
- Returns: JSON with update result
|
|
975
|
+
|
|
910
976
|
### Stream Operations
|
|
911
977
|
- **get-streams**: Get streams for the user's group
|
|
912
978
|
- Parameters: none
|
package/src/schemas.test.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
updateTaskBacklogSchema,
|
|
14
14
|
updateTaskPlannedTimeSchema,
|
|
15
15
|
updateTaskNotesSchema,
|
|
16
|
+
updateTaskDueDateSchema,
|
|
16
17
|
userProfileSchema,
|
|
17
18
|
groupSchema,
|
|
18
19
|
userSchema,
|
|
@@ -437,6 +438,147 @@ describe("Tool Parameter Schemas", () => {
|
|
|
437
438
|
).not.toThrow();
|
|
438
439
|
});
|
|
439
440
|
});
|
|
441
|
+
|
|
442
|
+
describe("updateTaskDueDateSchema", () => {
|
|
443
|
+
test("should accept valid ISO date string", () => {
|
|
444
|
+
const validInput = {
|
|
445
|
+
taskId: "task-123",
|
|
446
|
+
dueDate: "2024-06-21T04:00:00.000Z",
|
|
447
|
+
limitResponsePayload: true,
|
|
448
|
+
};
|
|
449
|
+
expect(() => updateTaskDueDateSchema.parse(validInput)).not.toThrow();
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test("should accept valid ISO date-time string with Z timezone", () => {
|
|
453
|
+
const validInput = {
|
|
454
|
+
taskId: "task-123",
|
|
455
|
+
dueDate: "2024-06-21T14:30:00.000Z",
|
|
456
|
+
limitResponsePayload: false,
|
|
457
|
+
};
|
|
458
|
+
expect(() => updateTaskDueDateSchema.parse(validInput)).not.toThrow();
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test("should accept null to clear due date", () => {
|
|
462
|
+
const validInput = {
|
|
463
|
+
taskId: "task-123",
|
|
464
|
+
dueDate: null,
|
|
465
|
+
limitResponsePayload: true,
|
|
466
|
+
};
|
|
467
|
+
expect(() => updateTaskDueDateSchema.parse(validInput)).not.toThrow();
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
test("should accept minimal required input with ISO date", () => {
|
|
471
|
+
const minimalInput = {
|
|
472
|
+
taskId: "task-123",
|
|
473
|
+
dueDate: "2024-06-21T09:00:00Z",
|
|
474
|
+
};
|
|
475
|
+
expect(() => updateTaskDueDateSchema.parse(minimalInput)).not.toThrow();
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
test("should accept minimal required input with null", () => {
|
|
479
|
+
const minimalInput = {
|
|
480
|
+
taskId: "task-123",
|
|
481
|
+
dueDate: null,
|
|
482
|
+
};
|
|
483
|
+
expect(() => updateTaskDueDateSchema.parse(minimalInput)).not.toThrow();
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
test("should reject empty task ID", () => {
|
|
487
|
+
expect(() =>
|
|
488
|
+
updateTaskDueDateSchema.parse({
|
|
489
|
+
taskId: "",
|
|
490
|
+
dueDate: "2024-06-21T09:00:00Z",
|
|
491
|
+
})
|
|
492
|
+
).toThrow();
|
|
493
|
+
expect(() =>
|
|
494
|
+
updateTaskDueDateSchema.parse({
|
|
495
|
+
dueDate: "2024-06-21T09:00:00Z",
|
|
496
|
+
})
|
|
497
|
+
).toThrow();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
test("should reject invalid date formats", () => {
|
|
501
|
+
// Date-only format
|
|
502
|
+
expect(() =>
|
|
503
|
+
updateTaskDueDateSchema.parse({
|
|
504
|
+
taskId: "task-123",
|
|
505
|
+
dueDate: "2024-06-21",
|
|
506
|
+
})
|
|
507
|
+
).toThrow();
|
|
508
|
+
|
|
509
|
+
// Non-ISO format
|
|
510
|
+
expect(() =>
|
|
511
|
+
updateTaskDueDateSchema.parse({
|
|
512
|
+
taskId: "task-123",
|
|
513
|
+
dueDate: "06/21/2024",
|
|
514
|
+
})
|
|
515
|
+
).toThrow();
|
|
516
|
+
|
|
517
|
+
// Invalid ISO format
|
|
518
|
+
expect(() =>
|
|
519
|
+
updateTaskDueDateSchema.parse({
|
|
520
|
+
taskId: "task-123",
|
|
521
|
+
dueDate: "2024-06-21T25:00:00Z",
|
|
522
|
+
})
|
|
523
|
+
).toThrow();
|
|
524
|
+
|
|
525
|
+
// Plain text
|
|
526
|
+
expect(() =>
|
|
527
|
+
updateTaskDueDateSchema.parse({
|
|
528
|
+
taskId: "task-123",
|
|
529
|
+
dueDate: "tomorrow",
|
|
530
|
+
})
|
|
531
|
+
).toThrow();
|
|
532
|
+
|
|
533
|
+
// Empty string
|
|
534
|
+
expect(() =>
|
|
535
|
+
updateTaskDueDateSchema.parse({
|
|
536
|
+
taskId: "task-123",
|
|
537
|
+
dueDate: "",
|
|
538
|
+
})
|
|
539
|
+
).toThrow();
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test("should reject undefined due date", () => {
|
|
543
|
+
expect(() =>
|
|
544
|
+
updateTaskDueDateSchema.parse({
|
|
545
|
+
taskId: "task-123",
|
|
546
|
+
dueDate: undefined,
|
|
547
|
+
})
|
|
548
|
+
).toThrow();
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
test("should reject missing due date", () => {
|
|
552
|
+
expect(() =>
|
|
553
|
+
updateTaskDueDateSchema.parse({
|
|
554
|
+
taskId: "task-123",
|
|
555
|
+
})
|
|
556
|
+
).toThrow();
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
test("should reject non-string, non-null due date values", () => {
|
|
560
|
+
expect(() =>
|
|
561
|
+
updateTaskDueDateSchema.parse({
|
|
562
|
+
taskId: "task-123",
|
|
563
|
+
dueDate: new Date(),
|
|
564
|
+
})
|
|
565
|
+
).toThrow();
|
|
566
|
+
|
|
567
|
+
expect(() =>
|
|
568
|
+
updateTaskDueDateSchema.parse({
|
|
569
|
+
taskId: "task-123",
|
|
570
|
+
dueDate: 1640995200000, // timestamp
|
|
571
|
+
})
|
|
572
|
+
).toThrow();
|
|
573
|
+
|
|
574
|
+
expect(() =>
|
|
575
|
+
updateTaskDueDateSchema.parse({
|
|
576
|
+
taskId: "task-123",
|
|
577
|
+
dueDate: true,
|
|
578
|
+
})
|
|
579
|
+
).toThrow();
|
|
580
|
+
});
|
|
581
|
+
});
|
|
440
582
|
});
|
|
441
583
|
|
|
442
584
|
describe("Response Schemas", () => {
|
package/src/schemas.ts
CHANGED
|
@@ -126,6 +126,16 @@ export const updateTaskNotesSchema = z.object({
|
|
|
126
126
|
}
|
|
127
127
|
);
|
|
128
128
|
|
|
129
|
+
// Update task due date parameters
|
|
130
|
+
export const updateTaskDueDateSchema = z.object({
|
|
131
|
+
taskId: z.string().min(1, "Task ID is required").describe("The ID of the task to update due date for"),
|
|
132
|
+
dueDate: z.union([
|
|
133
|
+
z.string().datetime("Must be a valid ISO date-time string"),
|
|
134
|
+
z.null()
|
|
135
|
+
]).describe("Due date in ISO format (YYYY-MM-DDTHH:mm:ssZ) or null to clear the due date"),
|
|
136
|
+
limitResponsePayload: z.boolean().optional().describe("Whether to limit the response payload size"),
|
|
137
|
+
});
|
|
138
|
+
|
|
129
139
|
/**
|
|
130
140
|
* Response Type Schemas (for validation and documentation)
|
|
131
141
|
*/
|
|
@@ -229,6 +239,7 @@ export type DeleteTaskInput = z.infer<typeof deleteTaskSchema>;
|
|
|
229
239
|
export type UpdateTaskSnoozeDateInput = z.infer<typeof updateTaskSnoozeDateSchema>;
|
|
230
240
|
export type UpdateTaskPlannedTimeInput = z.infer<typeof updateTaskPlannedTimeSchema>;
|
|
231
241
|
export type UpdateTaskNotesInput = z.infer<typeof updateTaskNotesSchema>;
|
|
242
|
+
export type UpdateTaskDueDateInput = z.infer<typeof updateTaskDueDateSchema>;
|
|
232
243
|
|
|
233
244
|
export type User = z.infer<typeof userSchema>;
|
|
234
245
|
export type Task = z.infer<typeof taskSchema>;
|