dav-mcp 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +260 -0
- package/package.json +80 -0
- package/src/error-handler.js +215 -0
- package/src/formatters.js +754 -0
- package/src/logger.js +144 -0
- package/src/server-http.js +402 -0
- package/src/server-stdio.js +225 -0
- package/src/tool-call-logger.js +148 -0
- package/src/tools/calendar/calendar-multi-get.js +38 -0
- package/src/tools/calendar/calendar-query.js +98 -0
- package/src/tools/calendar/create-event.js +79 -0
- package/src/tools/calendar/delete-calendar.js +36 -0
- package/src/tools/calendar/delete-event.js +38 -0
- package/src/tools/calendar/index.js +16 -0
- package/src/tools/calendar/list-calendars.js +21 -0
- package/src/tools/calendar/list-events.js +43 -0
- package/src/tools/calendar/make-calendar.js +80 -0
- package/src/tools/calendar/update-calendar.js +106 -0
- package/src/tools/calendar/update-event-fields.js +119 -0
- package/src/tools/calendar/update-event-raw.js +45 -0
- package/src/tools/contacts/addressbook-multi-get.js +38 -0
- package/src/tools/contacts/addressbook-query.js +85 -0
- package/src/tools/contacts/create-contact.js +84 -0
- package/src/tools/contacts/delete-contact.js +38 -0
- package/src/tools/contacts/index.js +13 -0
- package/src/tools/contacts/list-addressbooks.js +21 -0
- package/src/tools/contacts/list-contacts.js +32 -0
- package/src/tools/contacts/update-contact-fields.js +135 -0
- package/src/tools/contacts/update-contact-raw.js +45 -0
- package/src/tools/index.js +57 -0
- package/src/tools/shared/helpers.js +132 -0
- package/src/tools/todos/create-todo.js +101 -0
- package/src/tools/todos/delete-todo.js +38 -0
- package/src/tools/todos/index.js +12 -0
- package/src/tools/todos/list-todos.js +30 -0
- package/src/tools/todos/todo-multi-get.js +37 -0
- package/src/tools/todos/todo-query.js +112 -0
- package/src/tools/todos/update-todo-fields.js +119 -0
- package/src/tools/todos/update-todo-raw.js +46 -0
- package/src/tsdav-client.js +199 -0
- package/src/utils/tool-helpers.js +388 -0
- package/src/validation.js +245 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [2.7.0] - 2025-10-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **OAuth2 Authentication Support**: Full OAuth2 support for Google Calendar and other OAuth2-enabled CalDAV servers
|
|
14
|
+
- New `AUTH_METHOD` environment variable to switch between Basic Auth and OAuth2
|
|
15
|
+
- Support for Google Calendar via OAuth2 with automatic token refresh
|
|
16
|
+
- CalDAV discovery via RFC 4791 (no Google Calendar API required)
|
|
17
|
+
- Tested with Google Calendar (5 calendars discovered and fully functional)
|
|
18
|
+
- All CRUD operations (Create, Read, Update, Delete) working with OAuth2
|
|
19
|
+
- OAuth2 test suite with 10 comprehensive test cases
|
|
20
|
+
- OAuth2 configuration in `.env.example` with detailed setup instructions
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **Field-agnostic updates**: Integrated tsdav-utils for universal field update support
|
|
24
|
+
- `update_event` now supports all RFC 5545 iCalendar properties (SUMMARY, DESCRIPTION, LOCATION, DTSTART, DTEND, STATUS, etc.)
|
|
25
|
+
- `update_todo` now supports all RFC 5545 VTODO properties (SUMMARY, DESCRIPTION, STATUS, PRIORITY, DUE, PERCENT-COMPLETE, etc.)
|
|
26
|
+
- `update_contact` now supports all RFC 6350 vCard properties (FN, N, EMAIL, TEL, ORG, TITLE, NOTE, URL, ADR, BDAY, etc.)
|
|
27
|
+
- All update tools now accept custom X-* properties for extensions (e.g., X-ZOOM-LINK, X-MEETING-ROOM)
|
|
28
|
+
- Replaced manual iCal/vCard string manipulation with structured field updates via tsdav-utils
|
|
29
|
+
- Simplified update tool implementations (reduced code by 40-45% per tool)
|
|
30
|
+
- Updated input schemas to accept any RFC property name (field-agnostic validation)
|
|
31
|
+
- Enhanced `tsdav-client.js` to support both Basic Auth and OAuth2 authentication methods
|
|
32
|
+
- Updated `index.js` initialization logic to auto-detect authentication method
|
|
33
|
+
|
|
34
|
+
### Dependencies
|
|
35
|
+
- Added: tsdav-utils (v0.1.0) - Field-agnostic utility layer for RFC-compliant updates
|
|
36
|
+
|
|
37
|
+
### Compatibility
|
|
38
|
+
- Fully backward compatible with existing Basic Auth setup
|
|
39
|
+
- No breaking changes - existing configurations continue to work
|
|
40
|
+
- Google Calendar tested and verified with OAuth2
|
|
41
|
+
|
|
42
|
+
## [2.6.0] - Previous Release
|
|
43
|
+
|
|
44
|
+
Initial release with 26 MCP tools for CalDAV, CardDAV, and VTODO operations.
|
|
45
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 tsdav-mcp-server contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# dav-mcp
|
|
2
|
+
|
|
3
|
+
**Give your AI agents the power of organization** — Transform them into orchestrating assistants managing calendars, contacts, and tasks.
|
|
4
|
+
|
|
5
|
+
Built on 26 production-ready tools spanning CalDAV, CardDAV, and VTODO protocols.
|
|
6
|
+
|
|
7
|
+
Built for n8n, Claude Desktop, and any MCP client.
|
|
8
|
+
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://www.npmjs.com/package/dav-mcp)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
### The Orchestration
|
|
15
|
+
|
|
16
|
+
When partial tools force your AI to improvise, complete tools let it **execute precise operations across all components**.
|
|
17
|
+
|
|
18
|
+
| Capability | dav-mcp | Most MCPs |
|
|
19
|
+
|------------|---------|-------------------|
|
|
20
|
+
| **Calendar Management** | ✅ Full CRUD (11 tools) | ⚠️ Create + list only (2-3 tools) |
|
|
21
|
+
| **Contact Management** | ✅ Complete CardDAV (8 tools) | ❌ Often missing entirely |
|
|
22
|
+
| **Task Management** | ✅ Full VTODO support (7 tools) | ❌ Rarely included |
|
|
23
|
+
| **Field-Based Updates** | ✅ All RFC properties + custom fields | ❌ Rarely available |
|
|
24
|
+
| **Server-Side Filtering** | ✅ Efficient queries | ❌ Dumps all data |
|
|
25
|
+
| **Multi-Provider** | ✅ Any CalDAV/CardDAV server | ⚠️ Limited provider support |
|
|
26
|
+
| **Total Tools** | **26 tools** | **2-6 tools** |
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🚀 Full Feature Set
|
|
32
|
+
|
|
33
|
+
### Protocol Support
|
|
34
|
+
- **26 MCP Tools**: Full CRUD operations for calendars, contacts, and tasks
|
|
35
|
+
- **CalDAV Integration**: ~88% tsdav coverage (11 tools)
|
|
36
|
+
- **CardDAV Integration**: 100% tsdav coverage (8 tools)
|
|
37
|
+
- **VTODO Support**: Full task management with status, priorities, due dates (7 tools)
|
|
38
|
+
- **Field-Based Updates**: Field-agnostic updates via tsdav-utils - supports all RFC 5545/6350 properties + custom X-* fields
|
|
39
|
+
- **RFC-Compliant**: ical.js for RFC 5545 (iCalendar) and RFC 6350 (vCard) support
|
|
40
|
+
|
|
41
|
+
### Production-Ready Infrastructure
|
|
42
|
+
- **MCP Protocol**: STDIO transport for local clients, Stateless HTTP for remote
|
|
43
|
+
- **Multi-Server Tested**: Works with Radicale, Baikal, Nextcloud, iCloud
|
|
44
|
+
- **Bearer Auth**: Token authentication for HTTP transport
|
|
45
|
+
- **Structured Logging**: Custom JSON logger with millisecond precision
|
|
46
|
+
|
|
47
|
+
### Efficiency Features
|
|
48
|
+
- **Server-Side Filtering**: calendar_query, addressbook_query, todo_query with smart filters reduce data transfer
|
|
49
|
+
- **LLM-Optimized Tool Design**: PREFERRED/WARNING labels guide AI to efficient choices
|
|
50
|
+
- **Batch Operations**: multi_get tools fetch multiple specific items without loading entire collections
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 📋 Available Tools (26 Total)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### CalDAV Tools (11 tools)
|
|
58
|
+
|
|
59
|
+
1. **list_calendars** - List all available calendars
|
|
60
|
+
2. **list_events** - List ALL events (⚠️ WARNING: use calendar_query for filtered searches)
|
|
61
|
+
3. **create_event** - Create a new calendar event
|
|
62
|
+
4. **update_event** - ⭐ PREFERRED: Update any event field (SUMMARY, LOCATION, DTSTART, STATUS, custom X-* properties)
|
|
63
|
+
5. **update_event_raw** - Update event with raw iCal data (advanced)
|
|
64
|
+
6. **delete_event** - Delete an event permanently
|
|
65
|
+
7. **calendar_query** - ⭐ PREFERRED: Search and filter events efficiently by text, date range, or location
|
|
66
|
+
8. **make_calendar** - Create a new calendar collection
|
|
67
|
+
9. **update_calendar** - Update calendar properties (display name, description, color, timezone)
|
|
68
|
+
10. **delete_calendar** - Permanently delete a calendar and all its events
|
|
69
|
+
11. **calendar_multi_get** - Batch fetch multiple specific events by URLs
|
|
70
|
+
|
|
71
|
+
### CardDAV Tools (8 tools)
|
|
72
|
+
|
|
73
|
+
12. **list_addressbooks** - List all available address books
|
|
74
|
+
13. **list_contacts** - List ALL contacts (⚠️ WARNING: use addressbook_query for filtered searches)
|
|
75
|
+
14. **create_contact** - Create a new contact (vCard)
|
|
76
|
+
15. **update_contact** - ⭐ PREFERRED: Update any contact field (FN, EMAIL, TEL, ORG, ADR, custom X-* properties)
|
|
77
|
+
16. **update_contact_raw** - Update contact with raw vCard data (advanced)
|
|
78
|
+
17. **delete_contact** - Delete a contact permanently
|
|
79
|
+
18. **addressbook_query** - ⭐ PREFERRED: Search and filter contacts efficiently by name, email, or organization
|
|
80
|
+
19. **addressbook_multi_get** - Batch fetch multiple specific contacts by URLs
|
|
81
|
+
|
|
82
|
+
### VTODO Tools (7 tools)
|
|
83
|
+
|
|
84
|
+
20. **list_todos** - List ALL todos/tasks (⚠️ WARNING: use todo_query for filtered searches)
|
|
85
|
+
21. **create_todo** - Create a new todo/task with optional due date, priority, status
|
|
86
|
+
22. **update_todo** - ⭐ PREFERRED: Update any todo field (SUMMARY, STATUS, PRIORITY, DUE, PERCENT-COMPLETE, custom X-* properties)
|
|
87
|
+
23. **update_todo_raw** - Update todo with raw VTODO iCal data (advanced)
|
|
88
|
+
24. **delete_todo** - Delete a todo/task permanently
|
|
89
|
+
25. **todo_query** - ⭐ PREFERRED: Search and filter todos efficiently by status/due date
|
|
90
|
+
26. **todo_multi_get** - Batch fetch multiple specific todos by URLs
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 💡 Real-World Applications
|
|
95
|
+
|
|
96
|
+
See how complete tool coverage transforms basic operations into powerful workflows.
|
|
97
|
+
|
|
98
|
+
### n8n Automation Workflows
|
|
99
|
+
- **Meeting Management**: "Show me all Friday meetings" → calendar_query with date filter returns only relevant events
|
|
100
|
+
- **Contact Search**: "Find everyone at Google" → addressbook_query with org filter finds matches efficiently
|
|
101
|
+
- **Task Reporting**: "Show overdue high-priority tasks" → todo_query with filters returns specific results
|
|
102
|
+
- **Scheduled Cleanup**: Daily cron job deletes completed tasks using targeted queries
|
|
103
|
+
|
|
104
|
+
### Claude Desktop Integration
|
|
105
|
+
- **Quick Event Creation**: "Create team meeting tomorrow 2 PM" → create_event executes immediately
|
|
106
|
+
- **Contact Lookup**: "What's Sarah's email?" → addressbook_query with name filter finds contact
|
|
107
|
+
- **Calendar Overview**: "What's on my calendar next week?" → calendar_query with date range shows events
|
|
108
|
+
- **Calendar Management**: "Create a new calendar called Project Luna" → make_calendar creates collection
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 🛠️ Start Orchestrating in 5 Minutes
|
|
113
|
+
|
|
114
|
+
### Installation
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
git clone https://github.com/PhilflowIO/dav-mcp.git
|
|
118
|
+
cd dav-mcp
|
|
119
|
+
npm install
|
|
120
|
+
cp .env.example .env
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Configuration
|
|
124
|
+
|
|
125
|
+
Edit `.env`:
|
|
126
|
+
|
|
127
|
+
```env
|
|
128
|
+
# CalDAV/CardDAV Server
|
|
129
|
+
CALDAV_SERVER_URL=https://dav.example.com
|
|
130
|
+
CALDAV_USERNAME=your_username
|
|
131
|
+
CALDAV_PASSWORD=your_password
|
|
132
|
+
|
|
133
|
+
# MCP Server
|
|
134
|
+
PORT=3000
|
|
135
|
+
MCP_SERVER_NAME=dav-mcp
|
|
136
|
+
MCP_SERVER_VERSION=2.6.0
|
|
137
|
+
|
|
138
|
+
# Authentication (optional)
|
|
139
|
+
BEARER_TOKEN=your-secure-token-here
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Start Server
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npm start
|
|
146
|
+
# Server runs on: http://localhost:3000
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🔗 Integration
|
|
152
|
+
|
|
153
|
+
### n8n Workflow
|
|
154
|
+
|
|
155
|
+
1. **Start HTTP server**: `BEARER_TOKEN=your-token npm run start:http`
|
|
156
|
+
2. **Add "AI Agent" node**
|
|
157
|
+
3. **Add "MCP Client Tool" node** and connect to AI Agent
|
|
158
|
+
4. **Configure the connection:**
|
|
159
|
+
- **MCP Endpoint**: `http://localhost:3000/mcp`
|
|
160
|
+
- **Authentication Method**: `Bearer`
|
|
161
|
+
- **Bearer Token**: Your token
|
|
162
|
+
|
|
163
|
+
5. **Example prompts:**
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
"List all my calendars"
|
|
167
|
+
"Create a meeting tomorrow at 2 PM"
|
|
168
|
+
"Show me all events in October"
|
|
169
|
+
"Find all contacts at Google"
|
|
170
|
+
"Create a new contact for Jane Smith"
|
|
171
|
+
"Show overdue tasks with high priority"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Claude Desktop
|
|
175
|
+
|
|
176
|
+
Add to `claude_desktop_config.json`:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"mcpServers": {
|
|
181
|
+
"dav-mcp": {
|
|
182
|
+
"command": "node",
|
|
183
|
+
"args": ["/absolute/path/to/dav-mcp/src/server-stdio.js"],
|
|
184
|
+
"env": {
|
|
185
|
+
"CALDAV_SERVER_URL": "https://dav.example.com",
|
|
186
|
+
"CALDAV_USERNAME": "your_username",
|
|
187
|
+
"CALDAV_PASSWORD": "your_password"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Config file locations:**
|
|
195
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
196
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
197
|
+
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
198
|
+
|
|
199
|
+
**Restart Claude Desktop** after adding the configuration.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 🌐 Works Across All Major Providers
|
|
204
|
+
|
|
205
|
+
Works with any CalDAV/CardDAV server that follows RFC 4791 and RFC 6352:
|
|
206
|
+
|
|
207
|
+
- ✅ **Nextcloud** - Full support
|
|
208
|
+
- ✅ **Baikal** - Full support
|
|
209
|
+
- ✅ **Radicale** - Full support
|
|
210
|
+
- ✅ **iCloud** - Works with app-specific password
|
|
211
|
+
- ✅ **Any RFC-compliant server** - Standard protocol support
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
## 🔒 Security
|
|
215
|
+
|
|
216
|
+
- **Input Validation**: All inputs validated with Zod schemas before execution
|
|
217
|
+
- **Rate Limiting**: 100 requests/minute per session
|
|
218
|
+
- **Bearer Auth**: Optional token authentication
|
|
219
|
+
- **No Credential Storage**: Pass-through only, never logged or cached
|
|
220
|
+
- **Structured Logging**: Audit trail with request IDs, no PII exposure
|
|
221
|
+
- **CORS Protection**: Whitelist origins, block cross-site attacks
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
## 📚 Documentation
|
|
226
|
+
|
|
227
|
+
- **[MCP Specification](https://modelcontextprotocol.io/specification/2025-03-26)** - Model Context Protocol docs
|
|
228
|
+
- **[tsdav Docs](https://tsdav.vercel.app/docs/intro)** - CalDAV/CardDAV library reference
|
|
229
|
+
- **[CalDAV RFC 4791](https://datatracker.ietf.org/doc/html/rfc4791)** - CalDAV protocol specification
|
|
230
|
+
- **[CardDAV RFC 6352](https://datatracker.ietf.org/doc/html/rfc6352)** - CardDAV protocol specification
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 🤝 Contributing
|
|
235
|
+
|
|
236
|
+
Pull requests are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 📄 License
|
|
241
|
+
|
|
242
|
+
MIT License - see [LICENSE](LICENSE) for details
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 🙏 Acknowledgments
|
|
247
|
+
|
|
248
|
+
Built with:
|
|
249
|
+
- **[tsdav](https://github.com/natelindev/tsdav)** - Excellent TypeScript CalDAV/CardDAV library
|
|
250
|
+
- **[tsdav-utils](https://github.com/PhilflowIO/tsdav-utils)** - Field-agnostic utility layer for RFC-compliant field updates
|
|
251
|
+
- **[MCP SDK](https://modelcontextprotocol.io)** - Model Context Protocol by Anthropic
|
|
252
|
+
- **[ical.js](https://github.com/kewisch/ical.js)** - RFC-compliant iCalendar parser
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
**Questions? Issues?** Create a [GitHub issue](https://github.com/PhilflowIO/dav-mcp/issues)
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
*Built for AI agents managing calendars, contacts, and tasks*
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dav-mcp",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Complete DAV integration for AI - Calendar (CalDAV), Contacts (CardDAV), and Tasks (VTODO) management via MCP protocol",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/server-stdio.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"dav-mcp": "src/server-stdio.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "MCP_TRANSPORT=stdio node src/server-stdio.js",
|
|
12
|
+
"start:stdio": "MCP_TRANSPORT=stdio node src/server-stdio.js",
|
|
13
|
+
"start:http": "node src/server-http.js",
|
|
14
|
+
"dev": "MCP_TRANSPORT=stdio node --watch src/server-stdio.js",
|
|
15
|
+
"dev:http": "node --watch src/server-http.js",
|
|
16
|
+
"install:fresh": "rm -rf node_modules package-lock.json && npm cache clean --force && npm install",
|
|
17
|
+
"update:tsdav": "npm cache clean --force && npm install tsdav@github:PhilflowIO/tsdav#master",
|
|
18
|
+
"test": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules' jest",
|
|
19
|
+
"test:watch": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules' jest --watch",
|
|
20
|
+
"test:coverage": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules' jest --coverage",
|
|
21
|
+
"test:integration": "node tests/integration/mcp-test-runner.js",
|
|
22
|
+
"test:setup-data": "node tests/integration/setup-test-data.js"
|
|
23
|
+
},
|
|
24
|
+
"author": "dav-mcp contributors",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/PhilflowIO/dav-mcp.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/PhilflowIO/dav-mcp/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/PhilflowIO/dav-mcp#readme",
|
|
34
|
+
"keywords": [
|
|
35
|
+
"mcp",
|
|
36
|
+
"model-context-protocol",
|
|
37
|
+
"caldav",
|
|
38
|
+
"carddav",
|
|
39
|
+
"vtodo",
|
|
40
|
+
"dav",
|
|
41
|
+
"calendar",
|
|
42
|
+
"contacts",
|
|
43
|
+
"tasks",
|
|
44
|
+
"todos",
|
|
45
|
+
"n8n",
|
|
46
|
+
"ai",
|
|
47
|
+
"llm",
|
|
48
|
+
"automation",
|
|
49
|
+
"nextcloud",
|
|
50
|
+
"baikal",
|
|
51
|
+
"radicale"
|
|
52
|
+
],
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"src/**/*",
|
|
58
|
+
"README.md",
|
|
59
|
+
"LICENSE",
|
|
60
|
+
"CHANGELOG.md"
|
|
61
|
+
],
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.18.2",
|
|
64
|
+
"cors": "^2.8.5",
|
|
65
|
+
"dotenv": "^16.4.7",
|
|
66
|
+
"express": "^4.21.2",
|
|
67
|
+
"express-rate-limit": "^8.1.0",
|
|
68
|
+
"ical.js": "^2.2.1",
|
|
69
|
+
"tsdav": "github:PhilflowIO/tsdav#master",
|
|
70
|
+
"tsdav-utils": "github:PhilflowIO/tsdav-utils#main",
|
|
71
|
+
"zod": "^3.25.76"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@types/cors": "^2.8.17",
|
|
75
|
+
"@types/express": "^5.0.0",
|
|
76
|
+
"@types/jest": "^30.0.0",
|
|
77
|
+
"jest": "^30.2.0",
|
|
78
|
+
"pnpm": "^10.19.0"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Standard Error Codes
|
|
3
|
+
* Following JSON-RPC 2.0 error code specification
|
|
4
|
+
*/
|
|
5
|
+
export const MCP_ERROR_CODES = {
|
|
6
|
+
// JSON-RPC standard errors
|
|
7
|
+
PARSE_ERROR: -32700,
|
|
8
|
+
INVALID_REQUEST: -32600,
|
|
9
|
+
METHOD_NOT_FOUND: -32601,
|
|
10
|
+
INVALID_PARAMS: -32602,
|
|
11
|
+
INTERNAL_ERROR: -32603,
|
|
12
|
+
|
|
13
|
+
// Custom application errors (range -32000 to -32099)
|
|
14
|
+
CALDAV_ERROR: -32000,
|
|
15
|
+
CARDDAV_ERROR: -32001,
|
|
16
|
+
VALIDATION_ERROR: -32002,
|
|
17
|
+
AUTH_ERROR: -32003,
|
|
18
|
+
NETWORK_ERROR: -32004,
|
|
19
|
+
TIMEOUT_ERROR: -32005,
|
|
20
|
+
NOT_FOUND_ERROR: -32006,
|
|
21
|
+
CONFLICT_ERROR: -32007,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Error type to code mapping
|
|
26
|
+
*/
|
|
27
|
+
const ERROR_TYPE_MAP = {
|
|
28
|
+
'TypeError': MCP_ERROR_CODES.INVALID_PARAMS,
|
|
29
|
+
'ValidationError': MCP_ERROR_CODES.VALIDATION_ERROR,
|
|
30
|
+
'AuthenticationError': MCP_ERROR_CODES.AUTH_ERROR,
|
|
31
|
+
'NetworkError': MCP_ERROR_CODES.NETWORK_ERROR,
|
|
32
|
+
'TimeoutError': MCP_ERROR_CODES.TIMEOUT_ERROR,
|
|
33
|
+
'NotFoundError': MCP_ERROR_CODES.NOT_FOUND_ERROR,
|
|
34
|
+
'ConflictError': MCP_ERROR_CODES.CONFLICT_ERROR,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get error code based on error type or message
|
|
39
|
+
*/
|
|
40
|
+
function getErrorCode(error) {
|
|
41
|
+
// Check if error has explicit code
|
|
42
|
+
if (error.code && typeof error.code === 'number') {
|
|
43
|
+
return error.code;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Map by error type
|
|
47
|
+
if (error.name && ERROR_TYPE_MAP[error.name]) {
|
|
48
|
+
return ERROR_TYPE_MAP[error.name];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check error message for CalDAV/CardDAV specific errors
|
|
52
|
+
const message = error.message?.toLowerCase() || '';
|
|
53
|
+
if (message.includes('caldav')) {
|
|
54
|
+
return MCP_ERROR_CODES.CALDAV_ERROR;
|
|
55
|
+
}
|
|
56
|
+
if (message.includes('carddav')) {
|
|
57
|
+
return MCP_ERROR_CODES.CARDDAV_ERROR;
|
|
58
|
+
}
|
|
59
|
+
if (message.includes('auth') || message.includes('unauthorized') || message.includes('forbidden')) {
|
|
60
|
+
return MCP_ERROR_CODES.AUTH_ERROR;
|
|
61
|
+
}
|
|
62
|
+
if (message.includes('not found') || message.includes('404')) {
|
|
63
|
+
return MCP_ERROR_CODES.NOT_FOUND_ERROR;
|
|
64
|
+
}
|
|
65
|
+
if (message.includes('timeout')) {
|
|
66
|
+
return MCP_ERROR_CODES.TIMEOUT_ERROR;
|
|
67
|
+
}
|
|
68
|
+
if (message.includes('network') || message.includes('connection')) {
|
|
69
|
+
return MCP_ERROR_CODES.NETWORK_ERROR;
|
|
70
|
+
}
|
|
71
|
+
if (message.includes('validation') || message.includes('invalid')) {
|
|
72
|
+
return MCP_ERROR_CODES.VALIDATION_ERROR;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Default to internal error
|
|
76
|
+
return MCP_ERROR_CODES.INTERNAL_ERROR;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Format error into MCP-compliant structure
|
|
81
|
+
*/
|
|
82
|
+
export function formatMCPError(error, includeStack = false) {
|
|
83
|
+
const code = getErrorCode(error);
|
|
84
|
+
|
|
85
|
+
const errorResponse = {
|
|
86
|
+
code,
|
|
87
|
+
message: error.message || 'An error occurred',
|
|
88
|
+
data: {
|
|
89
|
+
type: error.name || 'Error',
|
|
90
|
+
...(error.details && { details: error.details }),
|
|
91
|
+
...(includeStack && error.stack && { stack: error.stack }),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return errorResponse;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create MCP tool error response
|
|
100
|
+
*/
|
|
101
|
+
export function createToolErrorResponse(error, includeStack = false) {
|
|
102
|
+
const mcpError = formatMCPError(error, includeStack);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: 'text',
|
|
108
|
+
text: JSON.stringify(mcpError, null, 2),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create HTTP error response
|
|
117
|
+
*/
|
|
118
|
+
export function createHTTPErrorResponse(error, statusCode = null) {
|
|
119
|
+
const mcpError = formatMCPError(error, process.env.NODE_ENV === 'development');
|
|
120
|
+
|
|
121
|
+
// Map MCP error codes to HTTP status codes
|
|
122
|
+
const defaultStatusCode = statusCode || mapMCPCodeToHTTPStatus(mcpError.code);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
statusCode: defaultStatusCode,
|
|
126
|
+
body: {
|
|
127
|
+
error: mcpError.message,
|
|
128
|
+
code: mcpError.code,
|
|
129
|
+
...mcpError.data,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Map MCP error codes to HTTP status codes
|
|
136
|
+
*/
|
|
137
|
+
function mapMCPCodeToHTTPStatus(code) {
|
|
138
|
+
switch (code) {
|
|
139
|
+
case MCP_ERROR_CODES.PARSE_ERROR:
|
|
140
|
+
case MCP_ERROR_CODES.INVALID_REQUEST:
|
|
141
|
+
case MCP_ERROR_CODES.INVALID_PARAMS:
|
|
142
|
+
case MCP_ERROR_CODES.VALIDATION_ERROR:
|
|
143
|
+
return 400; // Bad Request
|
|
144
|
+
|
|
145
|
+
case MCP_ERROR_CODES.METHOD_NOT_FOUND:
|
|
146
|
+
case MCP_ERROR_CODES.NOT_FOUND_ERROR:
|
|
147
|
+
return 404; // Not Found
|
|
148
|
+
|
|
149
|
+
case MCP_ERROR_CODES.AUTH_ERROR:
|
|
150
|
+
return 401; // Unauthorized
|
|
151
|
+
|
|
152
|
+
case MCP_ERROR_CODES.CONFLICT_ERROR:
|
|
153
|
+
return 409; // Conflict
|
|
154
|
+
|
|
155
|
+
case MCP_ERROR_CODES.TIMEOUT_ERROR:
|
|
156
|
+
return 408; // Request Timeout
|
|
157
|
+
|
|
158
|
+
case MCP_ERROR_CODES.NETWORK_ERROR:
|
|
159
|
+
return 502; // Bad Gateway
|
|
160
|
+
|
|
161
|
+
case MCP_ERROR_CODES.CALDAV_ERROR:
|
|
162
|
+
case MCP_ERROR_CODES.CARDDAV_ERROR:
|
|
163
|
+
case MCP_ERROR_CODES.INTERNAL_ERROR:
|
|
164
|
+
default:
|
|
165
|
+
return 500; // Internal Server Error
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Custom error classes
|
|
171
|
+
*/
|
|
172
|
+
export class ValidationError extends Error {
|
|
173
|
+
constructor(message, details = null) {
|
|
174
|
+
super(message);
|
|
175
|
+
this.name = 'ValidationError';
|
|
176
|
+
this.code = MCP_ERROR_CODES.VALIDATION_ERROR;
|
|
177
|
+
this.details = details;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export class AuthenticationError extends Error {
|
|
182
|
+
constructor(message, details = null) {
|
|
183
|
+
super(message);
|
|
184
|
+
this.name = 'AuthenticationError';
|
|
185
|
+
this.code = MCP_ERROR_CODES.AUTH_ERROR;
|
|
186
|
+
this.details = details;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export class NotFoundError extends Error {
|
|
191
|
+
constructor(message, details = null) {
|
|
192
|
+
super(message);
|
|
193
|
+
this.name = 'NotFoundError';
|
|
194
|
+
this.code = MCP_ERROR_CODES.NOT_FOUND_ERROR;
|
|
195
|
+
this.details = details;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export class CalDAVError extends Error {
|
|
200
|
+
constructor(message, details = null) {
|
|
201
|
+
super(message);
|
|
202
|
+
this.name = 'CalDAVError';
|
|
203
|
+
this.code = MCP_ERROR_CODES.CALDAV_ERROR;
|
|
204
|
+
this.details = details;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export class CardDAVError extends Error {
|
|
209
|
+
constructor(message, details = null) {
|
|
210
|
+
super(message);
|
|
211
|
+
this.name = 'CardDAVError';
|
|
212
|
+
this.code = MCP_ERROR_CODES.CARDDAV_ERROR;
|
|
213
|
+
this.details = details;
|
|
214
|
+
}
|
|
215
|
+
}
|