@open-sunsama/mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +374 -0
- package/build/index.d.ts +13 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +71 -0
- package/build/index.js.map +1 -0
- package/build/lib/api-client.d.ts +177 -0
- package/build/lib/api-client.d.ts.map +1 -0
- package/build/lib/api-client.js +126 -0
- package/build/lib/api-client.js.map +1 -0
- package/build/tools/subtasks.d.ts +11 -0
- package/build/tools/subtasks.d.ts.map +1 -0
- package/build/tools/subtasks.js +194 -0
- package/build/tools/subtasks.js.map +1 -0
- package/build/tools/tasks.d.ts +11 -0
- package/build/tools/tasks.d.ts.map +1 -0
- package/build/tools/tasks.js +426 -0
- package/build/tools/tasks.js.map +1 -0
- package/build/tools/time-blocks.d.ts +13 -0
- package/build/tools/time-blocks.d.ts.map +1 -0
- package/build/tools/time-blocks.js +456 -0
- package/build/tools/time-blocks.js.map +1 -0
- package/build/tools/user.d.ts +11 -0
- package/build/tools/user.d.ts.map +1 -0
- package/build/tools/user.js +147 -0
- package/build/tools/user.js.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# Open Sunsama MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that enables AI agents like Claude, Cursor, and other AI assistants to manage your tasks, time blocks, and calendar through the Open Sunsama API.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Task Management**: Create, update, complete, delete, and schedule tasks
|
|
8
|
+
- **Time Blocking**: Schedule focused work sessions on your calendar
|
|
9
|
+
- **Subtasks**: Break down tasks into smaller actionable items
|
|
10
|
+
- **User Profile**: Access and update user preferences
|
|
11
|
+
- **Full CRUD Operations**: Complete API coverage for AI-assisted productivity
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
1. An Open Sunsama account (cloud: [opensunsama.com](https://opensunsama.com) or self-hosted)
|
|
16
|
+
2. An API key from your Open Sunsama account
|
|
17
|
+
3. Node.js 18+ or Bun runtime
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
### Quick Start (Recommended)
|
|
22
|
+
|
|
23
|
+
No installation required! Use `npx` to run directly:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"open-sunsama": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@open-sunsama/mcp"],
|
|
31
|
+
"env": {
|
|
32
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key-here"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### From Source (Development)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Clone the repository
|
|
43
|
+
git clone https://github.com/ShadowWalker2014/open-sunsama.git
|
|
44
|
+
cd open-sunsama/mcp
|
|
45
|
+
|
|
46
|
+
# Install dependencies
|
|
47
|
+
bun install
|
|
48
|
+
|
|
49
|
+
# Build
|
|
50
|
+
bun run build
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Getting an API Key
|
|
54
|
+
|
|
55
|
+
1. Open the Open Sunsama web app
|
|
56
|
+
2. Go to **Settings** → **API Keys**
|
|
57
|
+
3. Click **"Generate New Key"**
|
|
58
|
+
4. Select scopes:
|
|
59
|
+
- `tasks:read` and `tasks:write` for task management
|
|
60
|
+
- `time-blocks:read` and `time-blocks:write` for calendar
|
|
61
|
+
- `user:read` and `user:write` for profile access
|
|
62
|
+
5. Copy the key (it's only shown once!)
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
### Environment Variables
|
|
67
|
+
|
|
68
|
+
| Variable | Required | Default | Description |
|
|
69
|
+
|----------|----------|---------|-------------|
|
|
70
|
+
| `OPENSUNSAMA_API_KEY` | Yes | - | Your API key starting with `os_` |
|
|
71
|
+
| `OPENSUNSAMA_API_URL` | No | `https://api.opensunsama.com` | API server URL |
|
|
72
|
+
|
|
73
|
+
### Self-Hosted / Local Development
|
|
74
|
+
|
|
75
|
+
If you're running the API locally or self-hosting, set `OPENSUNSAMA_API_URL` to your API URL:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"env": {
|
|
80
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key",
|
|
81
|
+
"OPENSUNSAMA_API_URL": "http://localhost:3001"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Note:** If you're using the official cloud version at [opensunsama.com](https://opensunsama.com), you can omit `OPENSUNSAMA_API_URL` (defaults to `https://api.opensunsama.com`).
|
|
87
|
+
|
|
88
|
+
## Usage with AI Assistants
|
|
89
|
+
|
|
90
|
+
### Claude Desktop
|
|
91
|
+
|
|
92
|
+
Add to your Claude Desktop configuration file:
|
|
93
|
+
|
|
94
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
95
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"mcpServers": {
|
|
100
|
+
"open-sunsama": {
|
|
101
|
+
"command": "npx",
|
|
102
|
+
"args": ["-y", "@open-sunsama/mcp"],
|
|
103
|
+
"env": {
|
|
104
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key-here"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> **Self-hosted/Local**: Add `"OPENSUNSAMA_API_URL": "http://localhost:3001"` to the env object
|
|
112
|
+
|
|
113
|
+
### Cursor
|
|
114
|
+
|
|
115
|
+
Create `.cursor/mcp.json` in your project root or configure in **Cursor Settings → MCP**:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"mcpServers": {
|
|
120
|
+
"open-sunsama": {
|
|
121
|
+
"command": "npx",
|
|
122
|
+
"args": ["-y", "@open-sunsama/mcp"],
|
|
123
|
+
"env": {
|
|
124
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key-here"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
> **Self-hosted/Local**: Add `"OPENSUNSAMA_API_URL": "http://localhost:3001"` to the env object
|
|
132
|
+
|
|
133
|
+
### VS Code with Continue Extension
|
|
134
|
+
|
|
135
|
+
Add to `~/.continue/config.json`:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"mcpServers": [
|
|
140
|
+
{
|
|
141
|
+
"name": "open-sunsama",
|
|
142
|
+
"command": "npx",
|
|
143
|
+
"args": ["-y", "@open-sunsama/mcp"],
|
|
144
|
+
"env": {
|
|
145
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key-here"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Windsurf / Cline / Other MCP-Compatible Tools
|
|
153
|
+
|
|
154
|
+
Most tools use a similar configuration format:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"mcpServers": {
|
|
159
|
+
"open-sunsama": {
|
|
160
|
+
"command": "npx",
|
|
161
|
+
"args": ["-y", "@open-sunsama/mcp"],
|
|
162
|
+
"env": {
|
|
163
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key-here"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Running with Bunx
|
|
171
|
+
|
|
172
|
+
If you prefer Bun over Node.js:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"mcpServers": {
|
|
177
|
+
"open-sunsama": {
|
|
178
|
+
"command": "bunx",
|
|
179
|
+
"args": ["@open-sunsama/mcp"],
|
|
180
|
+
"env": {
|
|
181
|
+
"OPENSUNSAMA_API_KEY": "os_your-api-key-here"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Available Tools
|
|
189
|
+
|
|
190
|
+
### Task Management
|
|
191
|
+
|
|
192
|
+
| Tool | Description |
|
|
193
|
+
|------|-------------|
|
|
194
|
+
| `list_tasks` | List tasks with filters (date, range, completion status, backlog) |
|
|
195
|
+
| `get_task` | Get detailed information about a specific task |
|
|
196
|
+
| `create_task` | Create a new task with title, notes, priority, schedule |
|
|
197
|
+
| `update_task` | Update task fields (title, notes, priority, schedule) |
|
|
198
|
+
| `complete_task` | Mark a task as complete |
|
|
199
|
+
| `uncomplete_task` | Reopen a completed task |
|
|
200
|
+
| `delete_task` | Permanently delete a task |
|
|
201
|
+
| `schedule_task` | Move a task to a specific date or backlog |
|
|
202
|
+
| `reorder_tasks` | Reorder tasks within a date |
|
|
203
|
+
|
|
204
|
+
### Subtask Management
|
|
205
|
+
|
|
206
|
+
| Tool | Description |
|
|
207
|
+
|------|-------------|
|
|
208
|
+
| `list_subtasks` | List all subtasks for a task |
|
|
209
|
+
| `create_subtask` | Add a subtask to a task |
|
|
210
|
+
| `toggle_subtask` | Toggle subtask completion |
|
|
211
|
+
| `update_subtask` | Update subtask title/position |
|
|
212
|
+
| `delete_subtask` | Delete a subtask |
|
|
213
|
+
|
|
214
|
+
### Time Block Management
|
|
215
|
+
|
|
216
|
+
| Tool | Description |
|
|
217
|
+
|------|-------------|
|
|
218
|
+
| `list_time_blocks` | List time blocks with filters |
|
|
219
|
+
| `get_time_block` | Get details of a time block |
|
|
220
|
+
| `create_time_block` | Schedule a new time block |
|
|
221
|
+
| `update_time_block` | Update time block details |
|
|
222
|
+
| `delete_time_block` | Remove a time block |
|
|
223
|
+
| `link_task_to_time_block` | Link/unlink a task to a time block |
|
|
224
|
+
| `get_schedule_for_day` | Get formatted daily schedule |
|
|
225
|
+
|
|
226
|
+
### User Profile
|
|
227
|
+
|
|
228
|
+
| Tool | Description |
|
|
229
|
+
|------|-------------|
|
|
230
|
+
| `get_user_profile` | Get current user's profile |
|
|
231
|
+
| `update_user_profile` | Update name, timezone, preferences |
|
|
232
|
+
|
|
233
|
+
## Example Interactions
|
|
234
|
+
|
|
235
|
+
Once configured, you can ask your AI assistant things like:
|
|
236
|
+
|
|
237
|
+
### Task Management
|
|
238
|
+
- "What tasks do I have scheduled for today?"
|
|
239
|
+
- "Create a task to review the quarterly report with high priority"
|
|
240
|
+
- "Mark my 'Send emails' task as complete"
|
|
241
|
+
- "Move the 'Research competitors' task to next Monday"
|
|
242
|
+
- "Show me all my backlog tasks"
|
|
243
|
+
|
|
244
|
+
### Time Blocking
|
|
245
|
+
- "Block 2 hours tomorrow morning for deep work starting at 9 AM"
|
|
246
|
+
- "What does my schedule look like for Friday?"
|
|
247
|
+
- "Link my 'Write documentation' task to my 2 PM time block"
|
|
248
|
+
- "Delete the meeting block I created for today"
|
|
249
|
+
|
|
250
|
+
### Subtasks
|
|
251
|
+
- "Add subtasks to my 'Prepare presentation' task: create slides, add charts, practice delivery"
|
|
252
|
+
- "Check off the 'create slides' subtask"
|
|
253
|
+
- "What subtasks are left on my project task?"
|
|
254
|
+
|
|
255
|
+
### Planning
|
|
256
|
+
- "Help me plan my day - I need to do code review, write docs, and have a team meeting"
|
|
257
|
+
- "Schedule my tasks for this week based on priority"
|
|
258
|
+
|
|
259
|
+
## Testing
|
|
260
|
+
|
|
261
|
+
Run the test suite to verify your setup:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# Set your API key
|
|
265
|
+
export OPENSUNSAMA_API_KEY=os_your-api-key-here
|
|
266
|
+
|
|
267
|
+
# Run all tests
|
|
268
|
+
bun run test
|
|
269
|
+
|
|
270
|
+
# Or run individual test suites
|
|
271
|
+
bun run test:tasks
|
|
272
|
+
bun run test:time-blocks
|
|
273
|
+
bun run test:subtasks
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Using MCP Inspector
|
|
277
|
+
|
|
278
|
+
For interactive testing and debugging:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
export OPENSUNSAMA_API_KEY=os_your-api-key-here
|
|
282
|
+
bun run inspector
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
This opens a web UI where you can test each tool manually.
|
|
286
|
+
|
|
287
|
+
## Troubleshooting
|
|
288
|
+
|
|
289
|
+
### "OPENSUNSAMA_API_KEY environment variable is required"
|
|
290
|
+
|
|
291
|
+
Make sure you've set the API key in your MCP configuration:
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"env": {
|
|
296
|
+
"OPENSUNSAMA_API_KEY": "os_your-actual-key"
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### "Network request failed" or Connection Errors
|
|
302
|
+
|
|
303
|
+
1. Verify the API is reachable: `curl https://api.opensunsama.com/health`
|
|
304
|
+
2. If self-hosted/local, check `OPENSUNSAMA_API_URL` is correct
|
|
305
|
+
3. Ensure your API key has the required scopes
|
|
306
|
+
|
|
307
|
+
### Tools Not Appearing in AI Assistant
|
|
308
|
+
|
|
309
|
+
1. Restart your AI assistant after changing the configuration
|
|
310
|
+
2. Check the configuration file path is correct
|
|
311
|
+
3. Verify the path to `build/index.js` is absolute
|
|
312
|
+
|
|
313
|
+
### "Authentication required" or 401 Errors
|
|
314
|
+
|
|
315
|
+
1. Verify your API key is valid and not expired
|
|
316
|
+
2. Check that your key has the required scopes for the operation
|
|
317
|
+
3. Generate a new API key if needed
|
|
318
|
+
|
|
319
|
+
## Development
|
|
320
|
+
|
|
321
|
+
### Project Structure
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
mcp/
|
|
325
|
+
├── src/
|
|
326
|
+
│ ├── index.ts # Main entry point
|
|
327
|
+
│ ├── lib/
|
|
328
|
+
│ │ └── api-client.ts # HTTP client for Open Sunsama API
|
|
329
|
+
│ └── tools/
|
|
330
|
+
│ ├── tasks.ts # Task management tools
|
|
331
|
+
│ ├── time-blocks.ts# Time block tools
|
|
332
|
+
│ ├── subtasks.ts # Subtask tools
|
|
333
|
+
│ └── user.ts # User profile tools
|
|
334
|
+
├── tests/
|
|
335
|
+
│ └── test-all.ts # Comprehensive test suite
|
|
336
|
+
├── build/ # Compiled JavaScript
|
|
337
|
+
├── package.json
|
|
338
|
+
├── tsconfig.json
|
|
339
|
+
└── README.md
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Building
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
bun run build # Compile TypeScript
|
|
346
|
+
bun run dev # Watch mode for development
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Adding New Tools
|
|
350
|
+
|
|
351
|
+
1. Create or edit a file in `src/tools/`
|
|
352
|
+
2. Use the `server.tool()` pattern with Zod schemas for validation
|
|
353
|
+
3. Register your tools in `src/index.ts`
|
|
354
|
+
4. Rebuild and test
|
|
355
|
+
|
|
356
|
+
## API Key Scopes
|
|
357
|
+
|
|
358
|
+
| Scope | Permissions |
|
|
359
|
+
|-------|-------------|
|
|
360
|
+
| `tasks:read` | List and view tasks |
|
|
361
|
+
| `tasks:write` | Create, update, delete tasks |
|
|
362
|
+
| `time-blocks:read` | List and view time blocks |
|
|
363
|
+
| `time-blocks:write` | Create, update, delete time blocks |
|
|
364
|
+
| `user:read` | View user profile |
|
|
365
|
+
| `user:write` | Update user profile |
|
|
366
|
+
|
|
367
|
+
## License
|
|
368
|
+
|
|
369
|
+
This MCP server is part of the Open Sunsama project and follows the same license terms. See the main repository LICENSE file for details.
|
|
370
|
+
|
|
371
|
+
## Support
|
|
372
|
+
|
|
373
|
+
- **Issues**: [GitHub Issues](https://github.com/ShadowWalker2014/open-sunsama/issues)
|
|
374
|
+
- **Documentation**: [Open Sunsama Docs](https://github.com/ShadowWalker2014/open-sunsama)
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Open Sunsama MCP Server
|
|
4
|
+
*
|
|
5
|
+
* A Model Context Protocol server that enables AI agents to manage tasks,
|
|
6
|
+
* time blocks, and calendars through the Open Sunsama API.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* OPENSUNSAMA_API_KEY=os_xxx open-sunsama-mcp
|
|
10
|
+
* OPENSUNSAMA_API_KEY=os_xxx OPENSUNSAMA_API_URL=http://localhost:3001 open-sunsama-mcp (for self-hosted/local)
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Open Sunsama MCP Server
|
|
4
|
+
*
|
|
5
|
+
* A Model Context Protocol server that enables AI agents to manage tasks,
|
|
6
|
+
* time blocks, and calendars through the Open Sunsama API.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* OPENSUNSAMA_API_KEY=os_xxx open-sunsama-mcp
|
|
10
|
+
* OPENSUNSAMA_API_KEY=os_xxx OPENSUNSAMA_API_URL=http://localhost:3001 open-sunsama-mcp (for self-hosted/local)
|
|
11
|
+
*/
|
|
12
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
14
|
+
import { ApiClient } from "./lib/api-client.js";
|
|
15
|
+
import { registerTaskTools } from "./tools/tasks.js";
|
|
16
|
+
import { registerTimeBlockTools } from "./tools/time-blocks.js";
|
|
17
|
+
import { registerSubtaskTools } from "./tools/subtasks.js";
|
|
18
|
+
import { registerUserTools } from "./tools/user.js";
|
|
19
|
+
// Configuration from environment variables
|
|
20
|
+
const API_KEY = process.env.OPENSUNSAMA_API_KEY;
|
|
21
|
+
const API_URL = process.env.OPENSUNSAMA_API_URL || "https://api.opensunsama.com";
|
|
22
|
+
// Validate required configuration
|
|
23
|
+
if (!API_KEY) {
|
|
24
|
+
console.error("Error: OPENSUNSAMA_API_KEY environment variable is required");
|
|
25
|
+
console.error("");
|
|
26
|
+
console.error("Usage:");
|
|
27
|
+
console.error(" OPENSUNSAMA_API_KEY=os_xxx open-sunsama-mcp");
|
|
28
|
+
console.error("");
|
|
29
|
+
console.error("You can get an API key from the Open Sunsama web app:");
|
|
30
|
+
console.error(" Settings → API Keys → Generate New Key");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
// Create the MCP server
|
|
34
|
+
const server = new McpServer({
|
|
35
|
+
name: "open-sunsama",
|
|
36
|
+
version: "1.0.0",
|
|
37
|
+
});
|
|
38
|
+
// Create the API client
|
|
39
|
+
const apiClient = new ApiClient({
|
|
40
|
+
baseUrl: API_URL,
|
|
41
|
+
apiKey: API_KEY,
|
|
42
|
+
});
|
|
43
|
+
// Register all tools
|
|
44
|
+
registerTaskTools(server, apiClient);
|
|
45
|
+
registerTimeBlockTools(server, apiClient);
|
|
46
|
+
registerSubtaskTools(server, apiClient);
|
|
47
|
+
registerUserTools(server, apiClient);
|
|
48
|
+
// Log to stderr (safe for stdio transport)
|
|
49
|
+
console.error(`Open Sunsama MCP Server starting...`);
|
|
50
|
+
console.error(`API URL: ${API_URL}`);
|
|
51
|
+
console.error(`API Key: ${API_KEY.substring(0, 10)}...`);
|
|
52
|
+
// Start the server
|
|
53
|
+
async function main() {
|
|
54
|
+
const transport = new StdioServerTransport();
|
|
55
|
+
await server.connect(transport);
|
|
56
|
+
console.error("Open Sunsama MCP Server running on stdio");
|
|
57
|
+
}
|
|
58
|
+
main().catch((error) => {
|
|
59
|
+
console.error("Fatal error:", error);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
});
|
|
62
|
+
// Handle graceful shutdown
|
|
63
|
+
process.on("SIGINT", () => {
|
|
64
|
+
console.error("Shutting down...");
|
|
65
|
+
process.exit(0);
|
|
66
|
+
});
|
|
67
|
+
process.on("SIGTERM", () => {
|
|
68
|
+
console.error("Shutting down...");
|
|
69
|
+
process.exit(0);
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,2CAA2C;AAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AAChD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,6BAA6B,CAAC;AAEjF,kCAAkC;AAClC,IAAI,CAAC,OAAO,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC7E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC/D,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,wBAAwB;AACxB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,wBAAwB;AACxB,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;IAC9B,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,OAAO;CAChB,CAAC,CAAC;AAEH,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACrC,sBAAsB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC1C,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACxC,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAErC,2CAA2C;AAC3C,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACrD,OAAO,CAAC,KAAK,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;AACrC,OAAO,CAAC,KAAK,CAAC,YAAY,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAEzD,mBAAmB;AACnB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,2BAA2B;AAC3B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API client for Open Sunsama REST API
|
|
3
|
+
* Handles authentication and HTTP requests
|
|
4
|
+
*/
|
|
5
|
+
export interface ApiClientConfig {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ApiResponse<T> {
|
|
10
|
+
success: boolean;
|
|
11
|
+
data?: T;
|
|
12
|
+
error?: {
|
|
13
|
+
code: string;
|
|
14
|
+
message: string;
|
|
15
|
+
statusCode: number;
|
|
16
|
+
errors?: Record<string, string[]>;
|
|
17
|
+
};
|
|
18
|
+
meta?: {
|
|
19
|
+
page: number;
|
|
20
|
+
limit: number;
|
|
21
|
+
total: number;
|
|
22
|
+
totalPages: number;
|
|
23
|
+
};
|
|
24
|
+
message?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class ApiClient {
|
|
27
|
+
private baseUrl;
|
|
28
|
+
private apiKey;
|
|
29
|
+
constructor(config: ApiClientConfig);
|
|
30
|
+
private request;
|
|
31
|
+
listTasks(params?: {
|
|
32
|
+
date?: string;
|
|
33
|
+
from?: string;
|
|
34
|
+
to?: string;
|
|
35
|
+
completed?: boolean;
|
|
36
|
+
backlog?: boolean;
|
|
37
|
+
sortBy?: "priority" | "position" | "createdAt";
|
|
38
|
+
page?: number;
|
|
39
|
+
limit?: number;
|
|
40
|
+
}): Promise<ApiResponse<Task[]>>;
|
|
41
|
+
getTask(id: string): Promise<ApiResponse<Task>>;
|
|
42
|
+
createTask(data: CreateTaskInput): Promise<ApiResponse<Task>>;
|
|
43
|
+
updateTask(id: string, data: UpdateTaskInput): Promise<ApiResponse<Task>>;
|
|
44
|
+
deleteTask(id: string): Promise<ApiResponse<{
|
|
45
|
+
message: string;
|
|
46
|
+
}>>;
|
|
47
|
+
reorderTasks(date: string | "backlog", taskIds: string[]): Promise<ApiResponse<Task[]>>;
|
|
48
|
+
listSubtasks(taskId: string): Promise<ApiResponse<Subtask[]>>;
|
|
49
|
+
createSubtask(taskId: string, data: CreateSubtaskInput): Promise<ApiResponse<Subtask>>;
|
|
50
|
+
updateSubtask(taskId: string, subtaskId: string, data: UpdateSubtaskInput): Promise<ApiResponse<Subtask>>;
|
|
51
|
+
deleteSubtask(taskId: string, subtaskId: string): Promise<ApiResponse<{
|
|
52
|
+
message: string;
|
|
53
|
+
}>>;
|
|
54
|
+
listTimeBlocks(params?: {
|
|
55
|
+
date?: string;
|
|
56
|
+
from?: string;
|
|
57
|
+
to?: string;
|
|
58
|
+
taskId?: string;
|
|
59
|
+
page?: number;
|
|
60
|
+
limit?: number;
|
|
61
|
+
}): Promise<ApiResponse<TimeBlock[]>>;
|
|
62
|
+
getTimeBlock(id: string): Promise<ApiResponse<TimeBlock>>;
|
|
63
|
+
createTimeBlock(data: CreateTimeBlockInput): Promise<ApiResponse<TimeBlock>>;
|
|
64
|
+
updateTimeBlock(id: string, data: UpdateTimeBlockInput): Promise<ApiResponse<TimeBlock>>;
|
|
65
|
+
deleteTimeBlock(id: string): Promise<ApiResponse<{
|
|
66
|
+
message: string;
|
|
67
|
+
}>>;
|
|
68
|
+
getMe(): Promise<ApiResponse<User>>;
|
|
69
|
+
updateMe(data: UpdateUserInput): Promise<ApiResponse<User>>;
|
|
70
|
+
}
|
|
71
|
+
export type TaskPriority = "P0" | "P1" | "P2" | "P3";
|
|
72
|
+
export interface Task {
|
|
73
|
+
id: string;
|
|
74
|
+
userId: string;
|
|
75
|
+
title: string;
|
|
76
|
+
notes: string | null;
|
|
77
|
+
scheduledDate: string | null;
|
|
78
|
+
estimatedMins: number | null;
|
|
79
|
+
priority: TaskPriority;
|
|
80
|
+
completedAt: string | null;
|
|
81
|
+
position: number;
|
|
82
|
+
createdAt: string;
|
|
83
|
+
updatedAt: string;
|
|
84
|
+
}
|
|
85
|
+
export interface CreateTaskInput {
|
|
86
|
+
title: string;
|
|
87
|
+
notes?: string;
|
|
88
|
+
scheduledDate?: string;
|
|
89
|
+
estimatedMins?: number;
|
|
90
|
+
priority?: TaskPriority;
|
|
91
|
+
position?: number;
|
|
92
|
+
}
|
|
93
|
+
export interface UpdateTaskInput {
|
|
94
|
+
title?: string;
|
|
95
|
+
notes?: string | null;
|
|
96
|
+
scheduledDate?: string | null;
|
|
97
|
+
estimatedMins?: number | null;
|
|
98
|
+
priority?: TaskPriority;
|
|
99
|
+
completedAt?: string | null;
|
|
100
|
+
position?: number;
|
|
101
|
+
}
|
|
102
|
+
export interface Subtask {
|
|
103
|
+
id: string;
|
|
104
|
+
taskId: string;
|
|
105
|
+
title: string;
|
|
106
|
+
completed: boolean;
|
|
107
|
+
position: number;
|
|
108
|
+
createdAt: string;
|
|
109
|
+
updatedAt: string;
|
|
110
|
+
}
|
|
111
|
+
export interface CreateSubtaskInput {
|
|
112
|
+
title: string;
|
|
113
|
+
position?: number;
|
|
114
|
+
}
|
|
115
|
+
export interface UpdateSubtaskInput {
|
|
116
|
+
title?: string;
|
|
117
|
+
completed?: boolean;
|
|
118
|
+
position?: number;
|
|
119
|
+
}
|
|
120
|
+
export interface TimeBlock {
|
|
121
|
+
id: string;
|
|
122
|
+
userId: string;
|
|
123
|
+
taskId: string | null;
|
|
124
|
+
title: string;
|
|
125
|
+
description: string | null;
|
|
126
|
+
date: string;
|
|
127
|
+
startTime: string;
|
|
128
|
+
endTime: string;
|
|
129
|
+
durationMins: number;
|
|
130
|
+
color: string | null;
|
|
131
|
+
position: number;
|
|
132
|
+
createdAt: string;
|
|
133
|
+
updatedAt: string;
|
|
134
|
+
task?: Task | null;
|
|
135
|
+
}
|
|
136
|
+
export interface CreateTimeBlockInput {
|
|
137
|
+
title: string;
|
|
138
|
+
date: string;
|
|
139
|
+
startTime: string;
|
|
140
|
+
endTime: string;
|
|
141
|
+
taskId?: string;
|
|
142
|
+
description?: string;
|
|
143
|
+
color?: string;
|
|
144
|
+
position?: number;
|
|
145
|
+
}
|
|
146
|
+
export interface UpdateTimeBlockInput {
|
|
147
|
+
title?: string;
|
|
148
|
+
date?: string;
|
|
149
|
+
startTime?: string;
|
|
150
|
+
endTime?: string;
|
|
151
|
+
taskId?: string | null;
|
|
152
|
+
description?: string | null;
|
|
153
|
+
color?: string | null;
|
|
154
|
+
position?: number;
|
|
155
|
+
}
|
|
156
|
+
export interface User {
|
|
157
|
+
id: string;
|
|
158
|
+
email: string;
|
|
159
|
+
name: string | null;
|
|
160
|
+
avatarUrl: string | null;
|
|
161
|
+
timezone: string;
|
|
162
|
+
createdAt: string;
|
|
163
|
+
updatedAt: string;
|
|
164
|
+
preferences: UserPreferences | null;
|
|
165
|
+
}
|
|
166
|
+
export interface UserPreferences {
|
|
167
|
+
themeMode: "light" | "dark" | "system";
|
|
168
|
+
colorTheme: string;
|
|
169
|
+
fontFamily: string;
|
|
170
|
+
}
|
|
171
|
+
export interface UpdateUserInput {
|
|
172
|
+
name?: string;
|
|
173
|
+
avatarUrl?: string | null;
|
|
174
|
+
timezone?: string;
|
|
175
|
+
preferences?: Partial<UserPreferences>;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"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"}
|