mcp-sunsama 0.4.0 → 0.5.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/.claude/settings.local.json +3 -1
- package/CHANGELOG.md +13 -0
- package/CLAUDE.md +10 -4
- package/Dockerfile +35 -0
- package/README.md +2 -1
- package/TODO-0_5_0.md +108 -0
- package/TODO.md +152 -0
- package/bun.lock +8 -2
- package/dev/prd-get-archived-tasks.md +156 -0
- package/dist/config/transport.d.ts +7 -5
- package/dist/config/transport.d.ts.map +1 -1
- package/dist/config/transport.js +3 -1
- package/dist/main.js +3 -10
- package/dist/utils/task-trimmer.d.ts +5 -2
- package/dist/utils/task-trimmer.d.ts.map +1 -1
- package/dist/utils/task-trimmer.js +10 -1
- package/package.json +2 -2
- package/src/main.ts +160 -77
- package/src/schemas.ts +7 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"includeCoAuthoredBy": false,
|
|
2
3
|
"permissions": {
|
|
3
4
|
"allow": [
|
|
4
5
|
"mcp__context7__resolve-library-id",
|
|
@@ -17,7 +18,8 @@
|
|
|
17
18
|
"Bash(npm ls:*)",
|
|
18
19
|
"Bash(cat:*)",
|
|
19
20
|
"Bash(grep:*)",
|
|
20
|
-
"Bash(mkdir:*)"
|
|
21
|
+
"Bash(mkdir:*)",
|
|
22
|
+
"mcp__fetch__fetch"
|
|
21
23
|
],
|
|
22
24
|
"deny": []
|
|
23
25
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# mcp-sunsama
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8478b69: Add get-archived-tasks tool with enhanced pagination
|
|
8
|
+
|
|
9
|
+
- Implement get-archived-tasks tool to access archived task history
|
|
10
|
+
- Add smart pagination with limit+1 pattern to determine if more results exist
|
|
11
|
+
- Include pagination metadata (hasMore flag, nextOffset, count) for LLM context
|
|
12
|
+
- Default limit set to 100 for optimal performance
|
|
13
|
+
- Response format includes TSV data with pagination header
|
|
14
|
+
- Update documentation in README.md and CLAUDE.md
|
|
15
|
+
|
|
3
16
|
## 0.4.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/CLAUDE.md
CHANGED
|
@@ -52,6 +52,14 @@ Two-tier optimization for large datasets:
|
|
|
52
52
|
|
|
53
53
|
Always apply filtering before trimming for efficiency.
|
|
54
54
|
|
|
55
|
+
### Enhanced Pagination Pattern
|
|
56
|
+
The `get-archived-tasks` tool implements smart pagination:
|
|
57
|
+
|
|
58
|
+
- **Limit+1 Pattern**: Fetches `requestedLimit + 1` to determine if more results exist
|
|
59
|
+
- **Pagination Metadata**: Returns `hasMore` flag, `nextOffset`, and count information
|
|
60
|
+
- **LLM Context**: Provides clear guidance for AI assistants on whether to continue fetching
|
|
61
|
+
- **Response Format**: TSV data with pagination header for optimal processing
|
|
62
|
+
|
|
55
63
|
### Schema Architecture
|
|
56
64
|
All tools use Zod schemas from `schemas.ts`:
|
|
57
65
|
- Type-safe parameter validation
|
|
@@ -118,10 +126,10 @@ Optional:
|
|
|
118
126
|
|
|
119
127
|
### Task Operations
|
|
120
128
|
Full CRUD support:
|
|
121
|
-
- **Read**: `get-tasks-by-day`, `get-tasks-backlog`, `get-streams`
|
|
129
|
+
- **Read**: `get-tasks-by-day`, `get-tasks-backlog`, `get-archived-tasks`, `get-streams`
|
|
122
130
|
- **Write**: `create-task`, `update-task-complete`, `delete-task`
|
|
123
131
|
|
|
124
|
-
|
|
132
|
+
Task read operations support response trimming. `get-tasks-by-day` includes completion filtering. `get-archived-tasks` includes enhanced pagination with hasMore flag for LLM decision-making.
|
|
125
133
|
|
|
126
134
|
### Testing Tools
|
|
127
135
|
Use MCP Inspector for debugging: `bun run inspect`
|
|
@@ -140,6 +148,4 @@ When updating the version:
|
|
|
140
148
|
|
|
141
149
|
**IMPORTANT**: Never commit the `dev/` directory or any of its files to git. This directory contains development data including sample API responses and testing data that should remain local only.
|
|
142
150
|
|
|
143
|
-
**IMPORTANT**: Never include "Claude" in git commit messages. Keep commit messages professional and focused on the actual changes made.
|
|
144
|
-
|
|
145
151
|
**Branch Naming Convention**: Use the format `{type}/{short-name}` where `{type}` follows conventional commit naming convention (feat, fix, chore, refactor, docs, style, test, ci, etc.).
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# ----- Build Stage -----
|
|
2
|
+
FROM oven/bun:1-alpine AS builder
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
# Copy package and configuration files
|
|
6
|
+
COPY package.json bun.lock* tsconfig.json ./
|
|
7
|
+
|
|
8
|
+
# Copy source code
|
|
9
|
+
COPY src ./src
|
|
10
|
+
|
|
11
|
+
# Install dependencies and build
|
|
12
|
+
RUN bun install && bun run build
|
|
13
|
+
|
|
14
|
+
# ----- Production Stage -----
|
|
15
|
+
FROM oven/bun:1-alpine
|
|
16
|
+
WORKDIR /app
|
|
17
|
+
|
|
18
|
+
# Copy built artifacts
|
|
19
|
+
COPY --from=builder /app/dist ./dist
|
|
20
|
+
|
|
21
|
+
# Copy package.json for production install
|
|
22
|
+
COPY package.json ./
|
|
23
|
+
|
|
24
|
+
# Install only production dependencies
|
|
25
|
+
RUN bun install --production --frozen-lockfile
|
|
26
|
+
|
|
27
|
+
# Set environment defaults for containerized deployment
|
|
28
|
+
ENV TRANSPORT_TYPE=httpStream
|
|
29
|
+
ENV PORT=3000
|
|
30
|
+
|
|
31
|
+
# Expose HTTP port
|
|
32
|
+
EXPOSE 3000
|
|
33
|
+
|
|
34
|
+
# Start the application
|
|
35
|
+
CMD ["bun", "dist/main.js"]
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ A Model Context Protocol (MCP) server that provides comprehensive task managemen
|
|
|
6
6
|
|
|
7
7
|
### Task Management
|
|
8
8
|
- **Create Tasks** - Create new tasks with notes, time estimates, due dates, and stream assignments
|
|
9
|
-
- **Read Tasks** - Get tasks by day with completion filtering, access backlog tasks
|
|
9
|
+
- **Read Tasks** - Get tasks by day with completion filtering, access backlog tasks, retrieve archived task history
|
|
10
10
|
- **Update Tasks** - Mark tasks as complete with custom timestamps, reschedule tasks or move to backlog
|
|
11
11
|
- **Delete Tasks** - Permanently remove tasks from your workspace
|
|
12
12
|
|
|
@@ -91,6 +91,7 @@ Add this configuration to your Claude Desktop MCP settings:
|
|
|
91
91
|
- `create-task` - Create new tasks with optional properties
|
|
92
92
|
- `get-tasks-by-day` - Get tasks for a specific day with completion filtering
|
|
93
93
|
- `get-tasks-backlog` - Get backlog tasks
|
|
94
|
+
- `get-archived-tasks` - Get archived tasks with pagination (includes hasMore flag for LLM context)
|
|
94
95
|
- `update-task-complete` - Mark tasks as complete
|
|
95
96
|
- `update-task-snooze-date` - Reschedule tasks to different dates or move to backlog
|
|
96
97
|
- `delete-task` - Delete tasks permanently
|
package/TODO-0_5_0.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Sunsama MCP Server - Implementation Status & Future Plans
|
|
2
|
+
|
|
3
|
+
## Current Status (⚠️ Update Required)
|
|
4
|
+
|
|
5
|
+
**Package Version**: sunsama-api v0.6.0 (updated 2025-06-20)
|
|
6
|
+
|
|
7
|
+
The MCP server currently implements **61.5% coverage** (8/13 methods) of available methods in the sunsama-api package.
|
|
8
|
+
|
|
9
|
+
**NEW METHODS AVAILABLE**: 5 additional methods are now available in sunsama-api v0.6.0 that need MCP tool implementation.
|
|
10
|
+
|
|
11
|
+
### Implemented Tools
|
|
12
|
+
|
|
13
|
+
#### User Operations
|
|
14
|
+
- ✅ `get-user` → `SunsamaClient.getUser()`
|
|
15
|
+
- Returns user profile, timezone, and group information
|
|
16
|
+
|
|
17
|
+
#### Task Operations
|
|
18
|
+
- ✅ `get-tasks-by-day` → `SunsamaClient.getTasksByDay(day, timezone?)`
|
|
19
|
+
- Supports completion filtering (`all`, `incomplete`, `completed`)
|
|
20
|
+
- Includes task trimming for response optimization
|
|
21
|
+
- ✅ `get-tasks-backlog` → `SunsamaClient.getTasksBacklog()`
|
|
22
|
+
- Returns all backlog tasks with trimming optimization
|
|
23
|
+
- ✅ `create-task` → `SunsamaClient.createTask(text, options?)`
|
|
24
|
+
- Full parameter support: notes, timeEstimate, dueDate, streamIds, etc.
|
|
25
|
+
- ✅ `update-task-complete` → `SunsamaClient.updateTaskComplete(taskId, completeOn?, limitResponsePayload?)`
|
|
26
|
+
- Mark tasks as complete with optional timestamp
|
|
27
|
+
- ✅ `delete-task` → `SunsamaClient.deleteTask(taskId, limitResponsePayload?, wasTaskMerged?)`
|
|
28
|
+
- Permanent task deletion
|
|
29
|
+
- ✅ `update-task-snooze-date` → `SunsamaClient.updateTaskSnoozeDate(taskId, newDay, options?)`
|
|
30
|
+
- Reschedule tasks or move to backlog
|
|
31
|
+
|
|
32
|
+
#### Stream Operations
|
|
33
|
+
- ✅ `get-streams` → `SunsamaClient.getStreamsByGroupId()`
|
|
34
|
+
- Returns all available streams (channels) for the user's group
|
|
35
|
+
|
|
36
|
+
## Future Enhancements
|
|
37
|
+
|
|
38
|
+
### 1. Archived Tasks (Priority: Medium)
|
|
39
|
+
**Status**: Research needed - API exists but not in sunsama-api package
|
|
40
|
+
|
|
41
|
+
**Description**: Implement support for retrieving archived tasks
|
|
42
|
+
- **API Endpoint**: `/get-archived-tasks` (confirmed in dev/user-stories/)
|
|
43
|
+
- **Parameters**: `userId`, `groupId`, `offset`, `limit`, optional filters
|
|
44
|
+
- **Returns**: Archived tasks with `archivedAt` timestamps
|
|
45
|
+
|
|
46
|
+
**Implementation Steps**:
|
|
47
|
+
1. **Upstream Work**: Add `getArchivedTasks()` method to sunsama-api package
|
|
48
|
+
2. **MCP Tool**: Implement `get-archived-tasks` tool with:
|
|
49
|
+
- Pagination support (`offset`, `limit`)
|
|
50
|
+
- Date range filtering (`dateFrom`, `dateTo`)
|
|
51
|
+
- Stream filtering
|
|
52
|
+
- Response trimming optimization
|
|
53
|
+
|
|
54
|
+
### 2. Enhanced Task Management (Priority: Low)
|
|
55
|
+
**Potential Extensions**:
|
|
56
|
+
- Task bulk operations (bulk delete, bulk complete)
|
|
57
|
+
- Task search/filtering by content
|
|
58
|
+
- Task time tracking integration
|
|
59
|
+
- Task dependency management
|
|
60
|
+
|
|
61
|
+
### 3. Advanced Stream Operations (Priority: Low)
|
|
62
|
+
**Potential Extensions**:
|
|
63
|
+
- Stream creation/modification (if API supports)
|
|
64
|
+
- Stream-specific task queries
|
|
65
|
+
- Stream statistics/analytics
|
|
66
|
+
|
|
67
|
+
### 4. Performance Optimizations (Priority: Low)
|
|
68
|
+
**Current Optimizations**:
|
|
69
|
+
- ✅ Task filtering before processing
|
|
70
|
+
- ✅ Response payload trimming (60-80% reduction)
|
|
71
|
+
- ✅ Dual transport support (stdio/HTTP)
|
|
72
|
+
|
|
73
|
+
**Future Optimizations**:
|
|
74
|
+
- Response caching for frequently accessed data
|
|
75
|
+
- Batch operations for multiple task updates
|
|
76
|
+
- Streaming responses for large datasets
|
|
77
|
+
|
|
78
|
+
## Development Notes
|
|
79
|
+
|
|
80
|
+
### Architecture Strengths
|
|
81
|
+
- Complete dual transport support (stdio + HTTP stream)
|
|
82
|
+
- Robust authentication handling per transport type
|
|
83
|
+
- Comprehensive error handling and validation
|
|
84
|
+
- Response optimization strategies
|
|
85
|
+
- Type-safe parameter validation with Zod schemas
|
|
86
|
+
|
|
87
|
+
### Maintenance Tasks
|
|
88
|
+
- ✅ Version synchronization (package.json ↔ src/main.ts)
|
|
89
|
+
- Monitor sunsama-api updates for new methods
|
|
90
|
+
- Update dependencies regularly
|
|
91
|
+
- Maintain test coverage
|
|
92
|
+
|
|
93
|
+
### Contributing Guidelines
|
|
94
|
+
- Follow existing patterns in `src/main.ts`
|
|
95
|
+
- Use Zod schemas for parameter validation
|
|
96
|
+
- Implement response trimming for large datasets
|
|
97
|
+
- Support both transport modes
|
|
98
|
+
- Add comprehensive tool descriptions
|
|
99
|
+
|
|
100
|
+
## Conclusion
|
|
101
|
+
|
|
102
|
+
The current implementation provides complete coverage of the sunsama-api package with a robust, well-architected foundation. Future enhancements should focus on:
|
|
103
|
+
|
|
104
|
+
1. **Upstream API Development**: Contributing archived tasks functionality to sunsama-api
|
|
105
|
+
2. **Advanced Features**: Building on the solid foundation for enhanced productivity workflows
|
|
106
|
+
3. **Performance**: Continuous optimization as usage scales
|
|
107
|
+
|
|
108
|
+
The codebase is well-positioned for extension and maintenance with clear patterns and comprehensive documentation.
|
package/TODO.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Sunsama MCP Server - v0.6.0 Implementation Plan
|
|
2
|
+
|
|
3
|
+
## 📊 Status Overview
|
|
4
|
+
- **sunsama-api Version**: 0.6.0 (updated from 0.3.1)
|
|
5
|
+
- **Currently Implemented**: 8/13 methods (61.5% coverage)
|
|
6
|
+
- **New Methods Available**: 5 methods ready for implementation
|
|
7
|
+
|
|
8
|
+
## 🚀 High Priority - Implement First
|
|
9
|
+
|
|
10
|
+
### 1. `get-archived-tasks` Tool
|
|
11
|
+
**API Method**: `getArchivedTasks(offset?, limit?)`
|
|
12
|
+
- **Impact**: High - Access to archived task history
|
|
13
|
+
- **Complexity**: Low - Standard read operation with pagination
|
|
14
|
+
- **Sample Data**: Available at `/dev/sample-data/get-archived-tasks/`
|
|
15
|
+
|
|
16
|
+
**Implementation Tasks**:
|
|
17
|
+
- [ ] Add `getArchivedTasksSchema` to `src/schemas.ts`
|
|
18
|
+
- [ ] Implement tool in `src/main.ts`
|
|
19
|
+
- [ ] Apply task trimming optimization
|
|
20
|
+
- [ ] Use TSV output format
|
|
21
|
+
- [ ] Add pagination support (offset/limit)
|
|
22
|
+
- [ ] Test with MCP Inspector
|
|
23
|
+
|
|
24
|
+
**Schema**:
|
|
25
|
+
```typescript
|
|
26
|
+
export const getArchivedTasksSchema = z.object({
|
|
27
|
+
offset: z.number().min(0).optional(),
|
|
28
|
+
limit: z.number().min(1).max(100).optional()
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. `get-task-by-id` Tool
|
|
33
|
+
**API Method**: `getTaskById(taskId)`
|
|
34
|
+
- **Impact**: High - Essential for task debugging and inspection
|
|
35
|
+
- **Complexity**: Low - Simple lookup operation
|
|
36
|
+
- **Returns**: Single Task object or null
|
|
37
|
+
|
|
38
|
+
**Implementation Tasks**:
|
|
39
|
+
- [ ] Add `getTaskByIdSchema` to `src/schemas.ts`
|
|
40
|
+
- [ ] Implement tool in `src/main.ts`
|
|
41
|
+
- [ ] Use JSON output format (single object)
|
|
42
|
+
- [ ] Handle null responses gracefully
|
|
43
|
+
- [ ] Add comprehensive error handling
|
|
44
|
+
- [ ] Test with valid and invalid task IDs
|
|
45
|
+
|
|
46
|
+
**Schema**:
|
|
47
|
+
```typescript
|
|
48
|
+
export const getTaskByIdSchema = z.object({
|
|
49
|
+
taskId: z.string().min(1).describe("The ID of the task to retrieve")
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 🔧 Medium Priority - Implement After High Priority
|
|
54
|
+
|
|
55
|
+
### 3. `update-task-notes` Tool
|
|
56
|
+
**API Method**: `updateTaskNotes(taskId, notes, notesMarkdown, options?)`
|
|
57
|
+
- **Impact**: Medium - Enhanced task content management
|
|
58
|
+
- **Complexity**: High - Requires CollabSnapshot handling
|
|
59
|
+
- **Research Needed**: CollabSnapshot format and usage
|
|
60
|
+
|
|
61
|
+
**Implementation Tasks**:
|
|
62
|
+
- [ ] Research CollabSnapshot parameter requirements
|
|
63
|
+
- [ ] Add `updateTaskNotesSchema` to `src/schemas.ts`
|
|
64
|
+
- [ ] Implement tool in `src/main.ts`
|
|
65
|
+
- [ ] Handle HTML and Markdown note formats
|
|
66
|
+
- [ ] Test with existing tasks that have notes
|
|
67
|
+
- [ ] Validate collaborative editing scenarios
|
|
68
|
+
|
|
69
|
+
## 🛠️ Low Priority - Utility Functions
|
|
70
|
+
|
|
71
|
+
### 4. `get-user-timezone` Tool
|
|
72
|
+
**API Method**: `getUserTimezone()`
|
|
73
|
+
- **Impact**: Low - Utility function (already used internally)
|
|
74
|
+
- **Complexity**: Low - Simple getter
|
|
75
|
+
- **Note**: Already called internally by `get-tasks-by-day`
|
|
76
|
+
|
|
77
|
+
**Implementation Tasks**:
|
|
78
|
+
- [ ] Add schema (no parameters)
|
|
79
|
+
- [ ] Implement standalone tool
|
|
80
|
+
- [ ] Return timezone string
|
|
81
|
+
- [ ] Test timezone format consistency
|
|
82
|
+
|
|
83
|
+
### 5. `generate-task-id` Tool
|
|
84
|
+
**API Method**: `SunsamaClient.generateTaskId()` (static)
|
|
85
|
+
- **Impact**: Low - Developer convenience
|
|
86
|
+
- **Complexity**: Low - Static method call
|
|
87
|
+
- **Note**: No authentication required
|
|
88
|
+
|
|
89
|
+
**Implementation Tasks**:
|
|
90
|
+
- [ ] Add schema (no parameters)
|
|
91
|
+
- [ ] Implement tool using static method
|
|
92
|
+
- [ ] Return 24-character hex string
|
|
93
|
+
- [ ] Test ID format compatibility
|
|
94
|
+
|
|
95
|
+
## 📋 Implementation Patterns
|
|
96
|
+
|
|
97
|
+
### Standard Tool Structure
|
|
98
|
+
```typescript
|
|
99
|
+
server.addTool({
|
|
100
|
+
name: "tool-name",
|
|
101
|
+
description: "Clear description of functionality",
|
|
102
|
+
parameters: toolSchema,
|
|
103
|
+
execute: async (args, {session, log}) => {
|
|
104
|
+
try {
|
|
105
|
+
log.info("Operation starting", { params });
|
|
106
|
+
|
|
107
|
+
const sunsamaClient = getSunsamaClient(session as SessionData | null);
|
|
108
|
+
const result = await sunsamaClient.methodName(args);
|
|
109
|
+
|
|
110
|
+
// Apply optimizations if needed
|
|
111
|
+
const optimizedResult = optimizeResponse(result);
|
|
112
|
+
|
|
113
|
+
log.info("Operation completed", { resultInfo });
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
content: [{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: formatOutput(optimizedResult)
|
|
119
|
+
}]
|
|
120
|
+
};
|
|
121
|
+
} catch (error) {
|
|
122
|
+
log.error("Operation failed", { error: error.message });
|
|
123
|
+
throw new Error(`Failed to [operation]: ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Response Format Guidelines
|
|
130
|
+
- **Arrays**: Use TSV format with `toTsv()` and apply `trimTasksForResponse()`
|
|
131
|
+
- **Single Objects**: Use JSON format with `JSON.stringify(obj, null, 2)`
|
|
132
|
+
- **Large Datasets**: Always apply trimming optimizations
|
|
133
|
+
|
|
134
|
+
## 🎯 Success Criteria
|
|
135
|
+
- [ ] All 5 new methods have corresponding MCP tools
|
|
136
|
+
- [ ] 100% test coverage with MCP Inspector
|
|
137
|
+
- [ ] Response optimization applied consistently
|
|
138
|
+
- [ ] Error handling follows established patterns
|
|
139
|
+
- [ ] Documentation updated in server instructions
|
|
140
|
+
- [ ] Version bump in `src/main.ts` matches `package.json`
|
|
141
|
+
|
|
142
|
+
## 🔄 Development Workflow
|
|
143
|
+
1. **Implement High Priority tools first** (archived tasks, task by ID)
|
|
144
|
+
2. **Test each tool individually** before proceeding
|
|
145
|
+
3. **Update schemas and imports in batches**
|
|
146
|
+
4. **Apply consistent patterns** from existing tools
|
|
147
|
+
5. **Update server version** and documentation
|
|
148
|
+
6. **Final integration testing** with full tool suite
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
*Target: Complete implementation of all 5 new sunsama-api v0.6.0 methods*
|
|
152
|
+
*Goal: Achieve 100% coverage (13/13 methods implemented)*
|
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.6.1",
|
|
11
11
|
"zod": "3.24.4",
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
@@ -268,12 +268,16 @@
|
|
|
268
268
|
|
|
269
269
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
|
270
270
|
|
|
271
|
+
"isomorphic.js": ["isomorphic.js@0.2.5", "", {}, "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw=="],
|
|
272
|
+
|
|
271
273
|
"js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="],
|
|
272
274
|
|
|
273
275
|
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
|
274
276
|
|
|
275
277
|
"jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
|
276
278
|
|
|
279
|
+
"lib0": ["lib0@0.2.108", "", { "dependencies": { "isomorphic.js": "^0.2.4" }, "bin": { "0gentesthtml": "bin/gentesthtml.js", "0serve": "bin/0serve.js", "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js" } }, "sha512-+3eK/B0SqYoZiQu9fNk4VEc6EX8cb0Li96tPGKgugzoGj/OdRdREtuTLvUW+mtinoB2mFiJjSqOJBIaMkAGhxQ=="],
|
|
280
|
+
|
|
277
281
|
"locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
|
|
278
282
|
|
|
279
283
|
"lodash.startcase": ["lodash.startcase@4.4.0", "", {}, "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg=="],
|
|
@@ -422,7 +426,7 @@
|
|
|
422
426
|
|
|
423
427
|
"strtok3": ["strtok3@10.3.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-3JWEZM6mfix/GCJBBUrkA8p2Id2pBkyTkVCJKto55w080QBKZ+8R171fGrbiSp+yMO/u6F8/yUh7K4V9K+YCnw=="],
|
|
424
428
|
|
|
425
|
-
"sunsama-api": ["sunsama-api@0.
|
|
429
|
+
"sunsama-api": ["sunsama-api@0.6.1", "", { "dependencies": { "graphql": "^16.11.0", "graphql-tag": "^2.12.6", "tough-cookie": "^5.1.2", "tslib": "^2.8.1", "yjs": "^13.6.27", "zod": "^3.25.64" } }, "sha512-4GhOdrAMo99JIXv9GZg7+NQJu1uPRgGbmnKFWTCNzXYiSVicNPNv27vgqHa3kJtPo19x8sBf4gOYZYlw6b1Wgw=="],
|
|
426
430
|
|
|
427
431
|
"term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="],
|
|
428
432
|
|
|
@@ -478,6 +482,8 @@
|
|
|
478
482
|
|
|
479
483
|
"yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="],
|
|
480
484
|
|
|
485
|
+
"yjs": ["yjs@13.6.27", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw=="],
|
|
486
|
+
|
|
481
487
|
"yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
|
|
482
488
|
|
|
483
489
|
"zod": ["zod@3.24.4", "", {}, "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg=="],
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Product Requirements Document: get-archived-tasks Tool
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This document outlines the requirements for implementing the `get-archived-tasks` MCP tool for the Sunsama MCP Server, providing access to archived task history with pagination and filtering capabilities.
|
|
5
|
+
|
|
6
|
+
## Background
|
|
7
|
+
With the update to sunsama-api v0.6.1, the `getArchivedTasks()` method is now available, enabling access to tasks that have been archived in Sunsama. This is a high-priority feature that provides essential access to historical task data for productivity analysis and task retrieval.
|
|
8
|
+
|
|
9
|
+
## Objectives
|
|
10
|
+
- Provide MCP tool access to archived tasks in Sunsama
|
|
11
|
+
- Enable pagination for efficient handling of large archived task datasets
|
|
12
|
+
- Maintain response optimization patterns established in the codebase
|
|
13
|
+
|
|
14
|
+
## Functional Requirements
|
|
15
|
+
|
|
16
|
+
### FR1: Core Functionality
|
|
17
|
+
- **Tool Name**: `get-archived-tasks`
|
|
18
|
+
- **API Method**: `sunsamaClient.getArchivedTasks(offset?, limit?)`
|
|
19
|
+
- **Purpose**: Retrieve archived tasks with optional pagination and completion filtering
|
|
20
|
+
|
|
21
|
+
### FR2: Parameters
|
|
22
|
+
| Parameter | Type | Required | Default | Description |
|
|
23
|
+
|-----------|------|----------|---------|-------------|
|
|
24
|
+
| `offset` | number | No | 0 | Pagination offset for archived tasks |
|
|
25
|
+
| `limit` | number | No | 100 | Maximum number of archived tasks to return (max: 1000) |
|
|
26
|
+
|
|
27
|
+
### FR3: Response Format
|
|
28
|
+
- **Format**: TSV (Tab-Separated Values) with pagination metadata header
|
|
29
|
+
- **Content**: Trimmed Task objects using existing `trimTasksForResponse()` utility
|
|
30
|
+
- **Pagination Metadata**: Include offset, limit, count, hasMore flag, and nextOffset
|
|
31
|
+
- **Optimization**: Apply task trimming for response efficiency
|
|
32
|
+
|
|
33
|
+
### FR4: Enhanced Pagination
|
|
34
|
+
- **Pattern**: Fetch limit+1 to determine if more results are available
|
|
35
|
+
- **Context**: Provide LLM with clear indication of whether to fetch more data
|
|
36
|
+
- **Metadata**: Include pagination information in response header
|
|
37
|
+
|
|
38
|
+
### FR5: Error Handling
|
|
39
|
+
- Authentication errors from client resolver
|
|
40
|
+
- Invalid pagination parameters (negative offset, excessive limit)
|
|
41
|
+
- Network/API errors with descriptive messages
|
|
42
|
+
- Consistent error logging pattern matching existing tools
|
|
43
|
+
|
|
44
|
+
## Technical Requirements
|
|
45
|
+
|
|
46
|
+
### TR1: Schema Definition
|
|
47
|
+
```typescript
|
|
48
|
+
export const getArchivedTasksSchema = z.object({
|
|
49
|
+
offset: z.number().int().min(0).optional().describe("Pagination offset (defaults to 0)"),
|
|
50
|
+
limit: z.number().int().min(1).max(1000).optional().describe("Maximum number of tasks to return (defaults to 300)"),
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### TR2: Tool Implementation Pattern
|
|
55
|
+
- Follow existing tool structure from `get-tasks-by-day` and `get-tasks-backlog`
|
|
56
|
+
- Use `getSunsamaClient()` for transport-agnostic client resolution
|
|
57
|
+
- Apply `trimTasksForResponse()` for response optimization
|
|
58
|
+
- Use `toTsv()` for consistent array output formatting
|
|
59
|
+
|
|
60
|
+
### TR3: Logging Requirements
|
|
61
|
+
- Info logs for operation start with parameters
|
|
62
|
+
- Success logs with task counts and pagination info
|
|
63
|
+
- Error logs with parameter context and error details
|
|
64
|
+
- Consistent log structure matching existing tools
|
|
65
|
+
|
|
66
|
+
### TR4: Authentication
|
|
67
|
+
- Leverage existing dual transport authentication system
|
|
68
|
+
- Support both stdio and HTTP Stream transport modes
|
|
69
|
+
- Use session-based client resolution pattern
|
|
70
|
+
|
|
71
|
+
## Non-Functional Requirements
|
|
72
|
+
|
|
73
|
+
### NFR1: Performance
|
|
74
|
+
- **Response Optimization**: Apply task trimming to reduce payload by 60-80%
|
|
75
|
+
- **Efficient Filtering**: Filter by completion status before trimming
|
|
76
|
+
- **Pagination Support**: Handle large archived task datasets efficiently
|
|
77
|
+
|
|
78
|
+
### NFR2: Consistency
|
|
79
|
+
- **Code Patterns**: Follow established patterns in `src/main.ts`
|
|
80
|
+
- **Error Handling**: Match existing error handling approach
|
|
81
|
+
- **Response Format**: Consistent with other task list endpoints (TSV)
|
|
82
|
+
- **Logging**: Maintain logging pattern consistency
|
|
83
|
+
|
|
84
|
+
### NFR3: Maintainability
|
|
85
|
+
- **Schema Validation**: Use Zod for type-safe parameter validation
|
|
86
|
+
- **Type Safety**: Leverage TypeScript inference from schemas
|
|
87
|
+
- **Documentation**: Clear parameter descriptions and usage notes
|
|
88
|
+
|
|
89
|
+
## Integration Requirements
|
|
90
|
+
|
|
91
|
+
### IR1: Schema Integration
|
|
92
|
+
- Add `getArchivedTasksSchema` to `src/schemas.ts`
|
|
93
|
+
- Include in schema exports
|
|
94
|
+
- Import in `src/main.ts`
|
|
95
|
+
|
|
96
|
+
### IR2: Utility Integration
|
|
97
|
+
- Use existing `filterTasksByCompletion()` from `utils/task-filters.ts`
|
|
98
|
+
- Use existing `trimTasksForResponse()` from `utils/task-trimmer.ts`
|
|
99
|
+
- Use existing `toTsv()` from `utils/to-tsv.ts`
|
|
100
|
+
- Use existing `getSunsamaClient()` from `utils/client-resolver.ts`
|
|
101
|
+
|
|
102
|
+
### IR3: Documentation Updates
|
|
103
|
+
- Update server instructions to include `get-archived-tasks` tool
|
|
104
|
+
- Add tool description to embedded documentation resource
|
|
105
|
+
- Update parameter descriptions and usage examples
|
|
106
|
+
|
|
107
|
+
## Testing Requirements
|
|
108
|
+
|
|
109
|
+
### T1: Functional Testing
|
|
110
|
+
- Test with valid pagination parameters (offset/limit)
|
|
111
|
+
- Test with different completion filters ("all", "incomplete", "completed")
|
|
112
|
+
- Test with edge cases (offset=0, large limits)
|
|
113
|
+
- Verify TSV output format correctness
|
|
114
|
+
|
|
115
|
+
### T2: Error Testing
|
|
116
|
+
- Test with invalid parameters (negative offset, excessive limit)
|
|
117
|
+
- Test authentication failure scenarios
|
|
118
|
+
- Test network error handling
|
|
119
|
+
- Verify error message clarity and consistency
|
|
120
|
+
|
|
121
|
+
### T3: Integration Testing
|
|
122
|
+
- Test with MCP Inspector (`bun run inspect`)
|
|
123
|
+
- Verify compatibility with both stdio and HTTP Stream transports
|
|
124
|
+
- Test response optimization (filtering + trimming)
|
|
125
|
+
- Validate against existing sample data
|
|
126
|
+
|
|
127
|
+
## Success Criteria
|
|
128
|
+
- [ ] Tool successfully retrieves archived tasks via `getArchivedTasks()` API
|
|
129
|
+
- [ ] Pagination works correctly with offset/limit parameters
|
|
130
|
+
- [ ] Completion filtering functions consistently with other task tools
|
|
131
|
+
- [ ] Response optimization reduces payload size by 60-80%
|
|
132
|
+
- [ ] Error handling provides clear, actionable error messages
|
|
133
|
+
- [ ] Integration testing passes with MCP Inspector
|
|
134
|
+
- [ ] Code follows established patterns and maintains consistency
|
|
135
|
+
|
|
136
|
+
## Implementation Priority
|
|
137
|
+
**High Priority** - This tool provides essential access to archived task history and is identified as a critical gap in the current MCP server functionality.
|
|
138
|
+
|
|
139
|
+
## Dependencies
|
|
140
|
+
- sunsama-api v0.6.1+ (already updated)
|
|
141
|
+
- Existing utility functions in `utils/` directory
|
|
142
|
+
- Existing schema patterns in `src/schemas.ts`
|
|
143
|
+
- Existing authentication and transport infrastructure
|
|
144
|
+
|
|
145
|
+
## Risk Assessment
|
|
146
|
+
- **Low Risk**: Implementation follows well-established patterns
|
|
147
|
+
- **API Stability**: Method is available and documented in sunsama-api
|
|
148
|
+
- **Testing Coverage**: Sample data available for validation
|
|
149
|
+
- **Integration**: Minimal impact on existing functionality
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
**Document Version**: 1.0
|
|
154
|
+
**Created**: 2025-06-20
|
|
155
|
+
**Author**: Implementation Team
|
|
156
|
+
**Status**: Ready for Implementation
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
* Supports both stdio and httpStream transports based on environment variables
|
|
4
4
|
*/
|
|
5
5
|
export type TransportType = "stdio" | "httpStream";
|
|
6
|
-
export
|
|
7
|
-
transportType:
|
|
8
|
-
|
|
6
|
+
export type TransportConfig = {
|
|
7
|
+
transportType: "stdio";
|
|
8
|
+
} | {
|
|
9
|
+
transportType: "httpStream";
|
|
10
|
+
httpStream: {
|
|
9
11
|
port: number;
|
|
10
|
-
endpoint: string
|
|
12
|
+
endpoint: `/${string}`;
|
|
11
13
|
};
|
|
12
|
-
}
|
|
14
|
+
};
|
|
13
15
|
/**
|
|
14
16
|
* Gets the transport configuration based on environment variables
|
|
15
17
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/config/transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,YAAY,CAAC;AAEnD,MAAM,
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/config/transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,YAAY,CAAC;AAEnD,MAAM,MAAM,eAAe,GACvB;IACF,aAAa,EAAE,OAAO,CAAC;CACxB,GACG;IACF,aAAa,EAAE,YAAY,CAAC;IAC5B,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAC;KACxB,CAAC;CACH,CAAC;AAgBF;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CA0BpD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
|
package/dist/config/transport.js
CHANGED
|
@@ -12,7 +12,9 @@ const TransportEnvSchema = z.object({
|
|
|
12
12
|
.transform(val => parseInt(val, 10))
|
|
13
13
|
.pipe(z.number().min(1).max(65535))
|
|
14
14
|
.optional(),
|
|
15
|
-
HTTP_ENDPOINT: z.string().
|
|
15
|
+
HTTP_ENDPOINT: z.string().refine(val => val.startsWith("/"), {
|
|
16
|
+
message: "HTTP_ENDPOINT must start with '/'"
|
|
17
|
+
}).transform(val => val).default("/mcp")
|
|
16
18
|
});
|
|
17
19
|
/**
|
|
18
20
|
* Gets the transport configuration based on environment variables
|
package/dist/main.js
CHANGED
|
@@ -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.4.0",
|
|
20
20
|
instructions: `
|
|
21
21
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
22
22
|
|
|
@@ -509,19 +509,12 @@ Required environment variables:
|
|
|
509
509
|
if (transportConfig.transportType === "httpStream") {
|
|
510
510
|
// Log startup information
|
|
511
511
|
console.log(`HTTP Stream configuration: port=${transportConfig.httpStream?.port}, endpoint=${transportConfig.httpStream?.endpoint}`);
|
|
512
|
-
server.start({
|
|
513
|
-
transportType: "httpStream",
|
|
514
|
-
httpStream: {
|
|
515
|
-
port: transportConfig.httpStream.port
|
|
516
|
-
}
|
|
517
|
-
}).then(() => {
|
|
512
|
+
server.start(transportConfig).then(() => {
|
|
518
513
|
console.log(`Sunsama MCP Server running on port ${transportConfig.httpStream.port}`);
|
|
519
514
|
console.log(`HTTP endpoint: ${transportConfig.httpStream.endpoint}`);
|
|
520
515
|
console.log("Authentication: HTTP Basic Auth with Sunsama credentials");
|
|
521
516
|
});
|
|
522
517
|
}
|
|
523
518
|
else {
|
|
524
|
-
server.start(
|
|
525
|
-
transportType: "stdio"
|
|
526
|
-
});
|
|
519
|
+
server.start(transportConfig);
|
|
527
520
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Task } from "sunsama-api";
|
|
1
|
+
import type { Task, TaskIntegration } from "sunsama-api";
|
|
2
2
|
/**
|
|
3
3
|
* Trimmed task type containing only essential properties for API responses.
|
|
4
4
|
* Reduces response size by 60-80% while preserving core task information.
|
|
@@ -9,7 +9,10 @@ import type { Task } from "sunsama-api";
|
|
|
9
9
|
*/
|
|
10
10
|
export type TrimmedTask = Pick<Task, '_id' | 'text' | 'completed' | 'assigneeId' | 'createdAt' | 'lastModified' | 'objectiveId' | 'completeDate' | 'timeEstimate' | 'dueDate' | 'notes' | 'streamIds'> & {
|
|
11
11
|
/** Integration service name (e.g., 'website', 'googleCalendar') or null */
|
|
12
|
-
integration:
|
|
12
|
+
integration: {
|
|
13
|
+
service: TaskIntegration['service'];
|
|
14
|
+
url?: string;
|
|
15
|
+
} | null;
|
|
13
16
|
/** Array of subtask titles only (simplified from full subtask objects) */
|
|
14
17
|
subtasks: string[];
|
|
15
18
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-trimmer.d.ts","sourceRoot":"","sources":["../../src/utils/task-trimmer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"task-trimmer.d.ts","sourceRoot":"","sources":["../../src/utils/task-trimmer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAC/B,KAAK,GACL,MAAM,GACN,WAAW,GACX,YAAY,GACZ,WAAW,GACX,cAAc,GACd,aAAa,GACb,cAAc,GACd,cAAc,GACd,SAAS,GACT,OAAO,GACP,WAAW,CACd,GAAG;IACF,2EAA2E;IAC3E,WAAW,EAAE;QACX,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACpC,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CA4B3D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAEjE"}
|
|
@@ -22,6 +22,15 @@
|
|
|
22
22
|
* @returns Trimmed task object with only essential properties
|
|
23
23
|
*/
|
|
24
24
|
export function trimTaskForResponse(task) {
|
|
25
|
+
let integration = null;
|
|
26
|
+
// Extract minimal integration data: service type and URL if available
|
|
27
|
+
// Integration identifiers vary by service - some have URLs (websites), others have different properties
|
|
28
|
+
if (task.integration) {
|
|
29
|
+
integration = { service: task.integration.service };
|
|
30
|
+
if ("url" in task.integration.identifier) {
|
|
31
|
+
integration.url = task.integration.identifier.url;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
25
34
|
return {
|
|
26
35
|
_id: task._id,
|
|
27
36
|
assigneeId: task.assigneeId,
|
|
@@ -29,7 +38,7 @@ export function trimTaskForResponse(task) {
|
|
|
29
38
|
completed: task.completed,
|
|
30
39
|
createdAt: task.createdAt,
|
|
31
40
|
dueDate: task.dueDate,
|
|
32
|
-
integration:
|
|
41
|
+
integration: integration,
|
|
33
42
|
lastModified: task.lastModified,
|
|
34
43
|
notes: task.notes,
|
|
35
44
|
objectiveId: task.objectiveId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-sunsama",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server for Sunsama API integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@types/papaparse": "^5.3.16",
|
|
26
26
|
"fastmcp": "3.3.1",
|
|
27
27
|
"papaparse": "^5.5.3",
|
|
28
|
-
"sunsama-api": "0.
|
|
28
|
+
"sunsama-api": "0.6.1",
|
|
29
29
|
"zod": "3.24.4"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
package/src/main.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { getTransportConfig } from "./config/transport.js";
|
|
|
8
8
|
import {
|
|
9
9
|
createTaskSchema,
|
|
10
10
|
deleteTaskSchema,
|
|
11
|
+
getArchivedTasksSchema,
|
|
11
12
|
getStreamsSchema,
|
|
12
13
|
getTasksBacklogSchema,
|
|
13
14
|
getTasksByDaySchema,
|
|
@@ -30,14 +31,14 @@ if (transportConfig.transportType === "stdio") {
|
|
|
30
31
|
|
|
31
32
|
const server = new FastMCP({
|
|
32
33
|
name: "Sunsama API Server",
|
|
33
|
-
version: "0.
|
|
34
|
+
version: "0.5.0",
|
|
34
35
|
instructions: `
|
|
35
36
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
36
37
|
|
|
37
38
|
Available tools:
|
|
38
39
|
- Authentication: login, logout, check authentication status
|
|
39
40
|
- User operations: get current user information
|
|
40
|
-
- Task operations: get tasks by day, get backlog tasks
|
|
41
|
+
- Task operations: get tasks by day, get backlog tasks, get archived tasks
|
|
41
42
|
- Stream operations: get streams/channels for the user's group
|
|
42
43
|
|
|
43
44
|
Authentication is required for all operations. You can either:
|
|
@@ -187,6 +188,79 @@ server.addTool({
|
|
|
187
188
|
}
|
|
188
189
|
});
|
|
189
190
|
|
|
191
|
+
server.addTool({
|
|
192
|
+
name: "get-archived-tasks",
|
|
193
|
+
description: "Get archived tasks with optional pagination",
|
|
194
|
+
parameters: getArchivedTasksSchema,
|
|
195
|
+
execute: async (args, {session, log}) => {
|
|
196
|
+
try {
|
|
197
|
+
// Extract and set defaults for parameters
|
|
198
|
+
const offset = args.offset || 0;
|
|
199
|
+
const requestedLimit = args.limit || 100;
|
|
200
|
+
|
|
201
|
+
// Fetch limit + 1 to determine if there are more results
|
|
202
|
+
const fetchLimit = requestedLimit + 1;
|
|
203
|
+
|
|
204
|
+
log.info("Getting archived tasks", {
|
|
205
|
+
offset,
|
|
206
|
+
requestedLimit,
|
|
207
|
+
fetchLimit
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Get the appropriate client based on transport type
|
|
211
|
+
const sunsamaClient = getSunsamaClient(session as SessionData | null);
|
|
212
|
+
|
|
213
|
+
// Get archived tasks (fetch limit + 1 to check for more)
|
|
214
|
+
const allTasks = await sunsamaClient.getArchivedTasks(offset, fetchLimit);
|
|
215
|
+
|
|
216
|
+
// Determine if there are more results and slice to requested limit
|
|
217
|
+
const hasMore = allTasks.length > requestedLimit;
|
|
218
|
+
const tasks = hasMore ? allTasks.slice(0, requestedLimit) : allTasks;
|
|
219
|
+
|
|
220
|
+
// Trim tasks to reduce response size while preserving essential data
|
|
221
|
+
const trimmedTasks = trimTasksForResponse(tasks);
|
|
222
|
+
|
|
223
|
+
// Create pagination metadata
|
|
224
|
+
const paginationInfo = {
|
|
225
|
+
offset,
|
|
226
|
+
limit: requestedLimit,
|
|
227
|
+
count: tasks.length,
|
|
228
|
+
hasMore,
|
|
229
|
+
nextOffset: hasMore ? offset + requestedLimit : null
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
log.info("Successfully retrieved archived tasks", {
|
|
233
|
+
totalReturned: tasks.length,
|
|
234
|
+
hasMore,
|
|
235
|
+
offset,
|
|
236
|
+
requestedLimit
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Create response with pagination metadata header and TSV data
|
|
240
|
+
const responseText = `# Pagination: offset=${paginationInfo.offset}, limit=${paginationInfo.limit}, count=${paginationInfo.count}, hasMore=${paginationInfo.hasMore}, nextOffset=${paginationInfo.nextOffset || 'null'}
|
|
241
|
+
${toTsv(trimmedTasks)}`;
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
content: [
|
|
245
|
+
{
|
|
246
|
+
type: "text",
|
|
247
|
+
text: responseText
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
} catch (error) {
|
|
253
|
+
log.error("Failed to get archived tasks", {
|
|
254
|
+
offset: args.offset,
|
|
255
|
+
limit: args.limit,
|
|
256
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
throw new Error(`Failed to get archived tasks: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
190
264
|
// Task Mutation Operations
|
|
191
265
|
server.addTool({
|
|
192
266
|
name: "create-task",
|
|
@@ -477,15 +551,32 @@ server.addResource({
|
|
|
477
551
|
text: `# Sunsama MCP Server Documentation
|
|
478
552
|
|
|
479
553
|
## Overview
|
|
480
|
-
This MCP server provides access to the Sunsama API for task and project management.
|
|
481
|
-
|
|
554
|
+
This MCP server provides comprehensive access to the Sunsama API for task and project management.
|
|
555
|
+
Supports dual transport modes with different authentication strategies.
|
|
556
|
+
|
|
557
|
+
## Transport Modes
|
|
558
|
+
|
|
559
|
+
### Stdio Transport (Default)
|
|
560
|
+
- Single global authentication using environment variables
|
|
561
|
+
- Session maintained for entire server lifetime
|
|
562
|
+
- Best for single-user local development
|
|
563
|
+
|
|
564
|
+
### HTTP Stream Transport
|
|
565
|
+
- Per-request authentication via HTTP Basic Auth
|
|
566
|
+
- Session-isolated client instances
|
|
567
|
+
- Supports multiple concurrent users
|
|
482
568
|
|
|
483
569
|
## Authentication
|
|
484
|
-
|
|
570
|
+
|
|
571
|
+
### Stdio Transport
|
|
572
|
+
Uses environment variables (authenticated once at startup):
|
|
485
573
|
- \`SUNSAMA_EMAIL\`: Your Sunsama account email
|
|
486
574
|
- \`SUNSAMA_PASSWORD\`: Your Sunsama account password
|
|
487
575
|
|
|
488
|
-
|
|
576
|
+
### HTTP Stream Transport
|
|
577
|
+
Uses HTTP Basic Auth headers (per-request authentication):
|
|
578
|
+
- \`Authorization: Basic <base64(email:password)>\`
|
|
579
|
+
- Credentials provided in each HTTP request
|
|
489
580
|
|
|
490
581
|
## Available Tools
|
|
491
582
|
|
|
@@ -494,93 +585,85 @@ Authentication happens automatically on server startup. No client-side authentic
|
|
|
494
585
|
- Parameters: none
|
|
495
586
|
- Returns: User object with profile, timezone, and primary group details
|
|
496
587
|
|
|
497
|
-
### Task
|
|
588
|
+
### Task Management
|
|
498
589
|
- **get-tasks-by-day**: Get tasks for a specific day with optional filtering
|
|
499
590
|
- Parameters:
|
|
500
591
|
- \`day\` (required): Date in YYYY-MM-DD format
|
|
501
592
|
- \`timezone\` (optional): Timezone string (e.g., "America/New_York")
|
|
502
|
-
- \`completionFilter\` (optional): Filter by completion status
|
|
503
|
-
|
|
504
|
-
- \`"incomplete"\`: Return only incomplete tasks
|
|
505
|
-
- \`"completed"\`: Return only completed tasks
|
|
506
|
-
- Returns: Array of filtered Task objects for the specified day
|
|
593
|
+
- \`completionFilter\` (optional): Filter by completion status ("all", "incomplete", "completed")
|
|
594
|
+
- Returns: TSV of filtered Task objects for the specified day
|
|
507
595
|
|
|
508
596
|
- **get-tasks-backlog**: Get tasks from the backlog
|
|
509
597
|
- Parameters: none
|
|
510
|
-
- Returns:
|
|
598
|
+
- Returns: TSV of Task objects from the backlog
|
|
599
|
+
|
|
600
|
+
- **get-archived-tasks**: Get archived tasks with optional pagination
|
|
601
|
+
- Parameters:
|
|
602
|
+
- \`offset\` (optional): Pagination offset (defaults to 0)
|
|
603
|
+
- \`limit\` (optional): Maximum number of tasks to return (defaults to 100, max: 1000)
|
|
604
|
+
- Returns: TSV of trimmed archived Task objects with pagination metadata header
|
|
605
|
+
- Pagination: Uses limit+1 pattern to determine if more results are available
|
|
606
|
+
|
|
607
|
+
- **create-task**: Create a new task with optional properties
|
|
608
|
+
- Parameters:
|
|
609
|
+
- \`text\` (required): Task title/description
|
|
610
|
+
- \`notes\` (optional): Additional task notes
|
|
611
|
+
- \`streamIds\` (optional): Array of stream IDs to associate with task
|
|
612
|
+
- \`timeEstimate\` (optional): Time estimate in minutes
|
|
613
|
+
- \`dueDate\` (optional): Due date string (ISO format)
|
|
614
|
+
- \`snoozeUntil\` (optional): Snooze until date string (ISO format)
|
|
615
|
+
- \`private\` (optional): Whether the task is private
|
|
616
|
+
- \`taskId\` (optional): Custom task ID
|
|
617
|
+
- Returns: JSON with task creation result
|
|
618
|
+
|
|
619
|
+
- **update-task-complete**: Mark a task as complete
|
|
620
|
+
- Parameters:
|
|
621
|
+
- \`taskId\` (required): The ID of the task to mark as complete
|
|
622
|
+
- \`completeOn\` (optional): Completion timestamp (ISO format)
|
|
623
|
+
- \`limitResponsePayload\` (optional): Whether to limit response size
|
|
624
|
+
- Returns: JSON with completion result
|
|
625
|
+
|
|
626
|
+
- **delete-task**: Delete a task permanently
|
|
627
|
+
- Parameters:
|
|
628
|
+
- \`taskId\` (required): The ID of the task to delete
|
|
629
|
+
- \`limitResponsePayload\` (optional): Whether to limit response size
|
|
630
|
+
- \`wasTaskMerged\` (optional): Whether the task was merged before deletion
|
|
631
|
+
- Returns: JSON with deletion result
|
|
632
|
+
|
|
633
|
+
- **update-task-snooze-date**: Reschedule tasks or move to backlog
|
|
634
|
+
- Parameters:
|
|
635
|
+
- \`taskId\` (required): The ID of the task to reschedule
|
|
636
|
+
- \`newDay\` (required): Target date in YYYY-MM-DD format, or null for backlog
|
|
637
|
+
- \`timezone\` (optional): Timezone string
|
|
638
|
+
- \`limitResponsePayload\` (optional): Whether to limit response size
|
|
639
|
+
- Returns: JSON with update result
|
|
511
640
|
|
|
512
641
|
### Stream Operations
|
|
513
642
|
- **get-streams**: Get streams for the user's group
|
|
514
643
|
- Parameters: none
|
|
515
|
-
- Returns:
|
|
516
|
-
- Note: Streams are called "channels" in the Sunsama UI
|
|
517
|
-
|
|
518
|
-
## Data Types
|
|
519
|
-
|
|
520
|
-
### User Object
|
|
521
|
-
\`\`\`typescript
|
|
522
|
-
{
|
|
523
|
-
_id: string;
|
|
524
|
-
email: string;
|
|
525
|
-
profile: {
|
|
526
|
-
_id: string;
|
|
527
|
-
email: string;
|
|
528
|
-
firstName: string;
|
|
529
|
-
lastName: string;
|
|
530
|
-
timezone: string;
|
|
531
|
-
avatarUrl?: string;
|
|
532
|
-
};
|
|
533
|
-
primaryGroup?: {
|
|
534
|
-
groupId: string;
|
|
535
|
-
name: string;
|
|
536
|
-
role?: string;
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
\`\`\`
|
|
540
|
-
|
|
541
|
-
### Task Object
|
|
542
|
-
\`\`\`typescript
|
|
543
|
-
{
|
|
544
|
-
_id: string;
|
|
545
|
-
title: string;
|
|
546
|
-
description?: string;
|
|
547
|
-
status: string;
|
|
548
|
-
createdAt: string;
|
|
549
|
-
updatedAt: string;
|
|
550
|
-
scheduledDate?: string;
|
|
551
|
-
completedAt?: string;
|
|
552
|
-
streamId?: string;
|
|
553
|
-
userId: string;
|
|
554
|
-
groupId: string;
|
|
555
|
-
}
|
|
556
|
-
\`\`\`
|
|
557
|
-
|
|
558
|
-
### Stream Object
|
|
559
|
-
Note: Streams are called "channels" in the Sunsama UI.
|
|
560
|
-
\`\`\`typescript
|
|
561
|
-
{
|
|
562
|
-
_id: string;
|
|
563
|
-
name: string;
|
|
564
|
-
color?: string;
|
|
565
|
-
groupId: string;
|
|
566
|
-
isActive: boolean;
|
|
567
|
-
createdAt: string;
|
|
568
|
-
updatedAt: string;
|
|
569
|
-
}
|
|
570
|
-
\`\`\`
|
|
644
|
+
- Returns: TSV of Stream objects
|
|
645
|
+
- Note: Streams are called "channels" in the Sunsama UI
|
|
571
646
|
|
|
572
|
-
##
|
|
573
|
-
-
|
|
574
|
-
-
|
|
575
|
-
-
|
|
576
|
-
- Server maintains session state across tool calls
|
|
647
|
+
## Response Optimization
|
|
648
|
+
- **Task Filtering**: Applied before processing for efficiency
|
|
649
|
+
- **Task Trimming**: Removes non-essential fields, reducing payload by 60-80%
|
|
650
|
+
- **TSV Format**: Used for arrays to optimize data processing
|
|
577
651
|
|
|
578
652
|
## Environment Setup
|
|
579
|
-
|
|
580
|
-
|
|
653
|
+
|
|
654
|
+
### Required (Stdio Transport)
|
|
581
655
|
- \`SUNSAMA_EMAIL\`: Sunsama account email
|
|
582
656
|
- \`SUNSAMA_PASSWORD\`: Sunsama account password
|
|
583
|
-
|
|
657
|
+
|
|
658
|
+
### Optional Configuration
|
|
659
|
+
- \`TRANSPORT_TYPE\`: "stdio" (default) | "httpStream"
|
|
660
|
+
- \`PORT\`: Server port for HTTP transport (default: 3002)
|
|
661
|
+
|
|
662
|
+
## Error Handling
|
|
663
|
+
- Comprehensive parameter validation using Zod schemas
|
|
664
|
+
- Graceful handling of network errors with descriptive messages
|
|
665
|
+
- Session-specific error isolation in HTTP transport mode
|
|
666
|
+
- Proper authentication error responses
|
|
584
667
|
`.trim()
|
|
585
668
|
};
|
|
586
669
|
}
|
package/src/schemas.ts
CHANGED
|
@@ -17,6 +17,12 @@ export const getTasksByDaySchema = z.object({
|
|
|
17
17
|
// Get tasks backlog parameters (no parameters needed)
|
|
18
18
|
export const getTasksBacklogSchema = z.object({});
|
|
19
19
|
|
|
20
|
+
// Get archived tasks parameters
|
|
21
|
+
export const getArchivedTasksSchema = z.object({
|
|
22
|
+
offset: z.number().int().min(0).optional().describe("Pagination offset (defaults to 0)"),
|
|
23
|
+
limit: z.number().int().min(1).max(1000).optional().describe("Maximum number of tasks to return (defaults to 100)"),
|
|
24
|
+
});
|
|
25
|
+
|
|
20
26
|
/**
|
|
21
27
|
* User Operation Schemas
|
|
22
28
|
*/
|
|
@@ -161,6 +167,7 @@ export type CompletionFilter = z.infer<typeof completionFilterSchema>;
|
|
|
161
167
|
|
|
162
168
|
export type GetTasksByDayInput = z.infer<typeof getTasksByDaySchema>;
|
|
163
169
|
export type GetTasksBacklogInput = z.infer<typeof getTasksBacklogSchema>;
|
|
170
|
+
export type GetArchivedTasksInput = z.infer<typeof getArchivedTasksSchema>;
|
|
164
171
|
export type GetUserInput = z.infer<typeof getUserSchema>;
|
|
165
172
|
export type GetStreamsInput = z.infer<typeof getStreamsSchema>;
|
|
166
173
|
|