@shin1ohno/sage 1.0.2 → 1.0.4
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 +110 -0
- package/dist/cli/mcp-handler.d.ts +5 -0
- package/dist/cli/mcp-handler.d.ts.map +1 -1
- package/dist/cli/mcp-handler.js +219 -38
- package/dist/cli/mcp-handler.js.map +1 -1
- package/dist/config/storage/file-storage.d.ts +1 -1
- package/dist/config/storage/file-storage.d.ts.map +1 -1
- package/dist/config/storage/session-storage.d.ts +1 -1
- package/dist/config/storage/session-storage.d.ts.map +1 -1
- package/dist/config/storage/storage-factory.d.ts +1 -1
- package/dist/config/storage/storage-factory.d.ts.map +1 -1
- package/dist/config/validation.d.ts +337 -6
- package/dist/config/validation.d.ts.map +1 -1
- package/dist/config/validation.js +276 -0
- package/dist/config/validation.js.map +1 -1
- package/dist/core/sage-core.d.ts +4 -1
- package/dist/core/sage-core.d.ts.map +1 -1
- package/dist/core/sage-core.js.map +1 -1
- package/dist/index.js +217 -27
- package/dist/index.js.map +1 -1
- package/dist/integrations/calendar-service.d.ts +23 -0
- package/dist/integrations/calendar-service.d.ts.map +1 -1
- package/dist/integrations/calendar-service.js +96 -0
- package/dist/integrations/calendar-service.js.map +1 -1
- package/dist/integrations/calendar-source-manager.d.ts +51 -13
- package/dist/integrations/calendar-source-manager.d.ts.map +1 -1
- package/dist/integrations/calendar-source-manager.js +224 -27
- package/dist/integrations/calendar-source-manager.js.map +1 -1
- package/dist/integrations/google-calendar-room-service.d.ts +140 -0
- package/dist/integrations/google-calendar-room-service.d.ts.map +1 -0
- package/dist/integrations/google-calendar-room-service.js +383 -0
- package/dist/integrations/google-calendar-room-service.js.map +1 -0
- package/dist/integrations/google-calendar-service.d.ts +167 -6
- package/dist/integrations/google-calendar-service.d.ts.map +1 -1
- package/dist/integrations/google-calendar-service.js +1036 -84
- package/dist/integrations/google-calendar-service.js.map +1 -1
- package/dist/integrations/google-people-service.d.ts +57 -0
- package/dist/integrations/google-people-service.d.ts.map +1 -0
- package/dist/integrations/google-people-service.js +207 -0
- package/dist/integrations/google-people-service.js.map +1 -0
- package/dist/oauth/google-oauth-handler.d.ts +2 -1
- package/dist/oauth/google-oauth-handler.d.ts.map +1 -1
- package/dist/oauth/google-oauth-handler.js +3 -1
- package/dist/oauth/google-oauth-handler.js.map +1 -1
- package/dist/services/integration-strategy-manager.d.ts +275 -0
- package/dist/services/integration-strategy-manager.d.ts.map +1 -0
- package/dist/services/integration-strategy-manager.js +362 -0
- package/dist/services/integration-strategy-manager.js.map +1 -0
- package/dist/services/sampling-service.d.ts +191 -0
- package/dist/services/sampling-service.d.ts.map +1 -0
- package/dist/services/sampling-service.js +352 -0
- package/dist/services/sampling-service.js.map +1 -0
- package/dist/tools/calendar/handlers.d.ts +223 -0
- package/dist/tools/calendar/handlers.d.ts.map +1 -1
- package/dist/tools/calendar/handlers.js +725 -8
- package/dist/tools/calendar/handlers.js.map +1 -1
- package/dist/tools/calendar/index.d.ts +3 -2
- package/dist/tools/calendar/index.d.ts.map +1 -1
- package/dist/tools/calendar/index.js +4 -1
- package/dist/tools/calendar/index.js.map +1 -1
- package/dist/tools/directory/handlers.d.ts +43 -0
- package/dist/tools/directory/handlers.d.ts.map +1 -0
- package/dist/tools/directory/handlers.js +74 -0
- package/dist/tools/directory/handlers.js.map +1 -0
- package/dist/tools/directory/index.d.ts +11 -0
- package/dist/tools/directory/index.d.ts.map +1 -0
- package/dist/tools/directory/index.js +10 -0
- package/dist/tools/directory/index.js.map +1 -0
- package/dist/tools/reminders/handlers.d.ts +32 -1
- package/dist/tools/reminders/handlers.d.ts.map +1 -1
- package/dist/tools/reminders/handlers.js +135 -1
- package/dist/tools/reminders/handlers.js.map +1 -1
- package/dist/tools/reminders/index.d.ts +3 -3
- package/dist/tools/reminders/index.d.ts.map +1 -1
- package/dist/tools/reminders/index.js +2 -2
- package/dist/tools/reminders/index.js.map +1 -1
- package/dist/tools/shared/availability-tools.d.ts +87 -0
- package/dist/tools/shared/availability-tools.d.ts.map +1 -0
- package/dist/tools/shared/availability-tools.js +64 -0
- package/dist/tools/shared/availability-tools.js.map +1 -0
- package/dist/tools/shared/calendar-tools.d.ts +142 -0
- package/dist/tools/shared/calendar-tools.d.ts.map +1 -0
- package/dist/tools/shared/calendar-tools.js +98 -0
- package/dist/tools/shared/calendar-tools.js.map +1 -0
- package/dist/tools/shared/directory-tools.d.ts +35 -0
- package/dist/tools/shared/directory-tools.d.ts.map +1 -0
- package/dist/tools/shared/directory-tools.js +31 -0
- package/dist/tools/shared/directory-tools.js.map +1 -0
- package/dist/tools/shared/index.d.ts +32 -0
- package/dist/tools/shared/index.d.ts.map +1 -0
- package/dist/tools/shared/index.js +37 -0
- package/dist/tools/shared/index.js.map +1 -0
- package/dist/tools/shared/room-tools.d.ts +94 -0
- package/dist/tools/shared/room-tools.d.ts.map +1 -0
- package/dist/tools/shared/room-tools.js +67 -0
- package/dist/tools/shared/room-tools.js.map +1 -0
- package/dist/tools/shared/types.d.ts +35 -0
- package/dist/tools/shared/types.d.ts.map +1 -0
- package/dist/tools/shared/types.js +26 -0
- package/dist/tools/shared/types.js.map +1 -0
- package/dist/types/calendar.d.ts +54 -0
- package/dist/types/calendar.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/google-calendar-types.d.ts +210 -2
- package/dist/types/google-calendar-types.d.ts.map +1 -1
- package/dist/types/google-calendar-types.js +33 -1
- package/dist/types/google-calendar-types.js.map +1 -1
- package/dist/types/google-people-types.d.ts +47 -0
- package/dist/types/google-people-types.d.ts.map +1 -0
- package/dist/types/google-people-types.js +8 -0
- package/dist/types/google-people-types.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/platform.d.ts +128 -0
- package/dist/types/platform.d.ts.map +1 -0
- package/dist/types/platform.js +10 -0
- package/dist/types/platform.js.map +1 -0
- package/dist/types/sampling.d.ts +134 -0
- package/dist/types/sampling.d.ts.map +1 -0
- package/dist/types/sampling.js +25 -0
- package/dist/types/sampling.js.map +1 -0
- package/dist/types/storage.d.ts +39 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +7 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/utils/recurrence-validator.d.ts +133 -0
- package/dist/utils/recurrence-validator.d.ts.map +1 -0
- package/dist/utils/recurrence-validator.js +595 -0
- package/dist/utils/recurrence-validator.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/dist/platform/adapter-factory.d.ts +0 -22
- package/dist/platform/adapter-factory.d.ts.map +0 -1
- package/dist/platform/adapter-factory.js +0 -37
- package/dist/platform/adapter-factory.js.map +0 -1
- package/dist/platform/adapters/mcp-adapter.d.ts +0 -32
- package/dist/platform/adapters/mcp-adapter.d.ts.map +0 -1
- package/dist/platform/adapters/mcp-adapter.js +0 -52
- package/dist/platform/adapters/mcp-adapter.js.map +0 -1
- package/dist/platform/adapters/remote-mcp-adapter.d.ts +0 -34
- package/dist/platform/adapters/remote-mcp-adapter.d.ts.map +0 -1
- package/dist/platform/adapters/remote-mcp-adapter.js +0 -54
- package/dist/platform/adapters/remote-mcp-adapter.js.map +0 -1
- package/dist/platform/detector.d.ts +0 -49
- package/dist/platform/detector.d.ts.map +0 -1
- package/dist/platform/detector.js +0 -161
- package/dist/platform/detector.js.map +0 -1
- package/dist/platform/index.d.ts +0 -9
- package/dist/platform/index.d.ts.map +0 -1
- package/dist/platform/index.js +0 -9
- package/dist/platform/index.js.map +0 -1
- package/dist/platform/types.d.ts +0 -163
- package/dist/platform/types.d.ts.map +0 -1
- package/dist/platform/types.js +0 -28
- package/dist/platform/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -142,6 +142,116 @@ From Claude, run the `authenticate_google` tool:
|
|
|
142
142
|
| Session expired | Complete authentication within 10 minutes |
|
|
143
143
|
| 503 from callback | Verify `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` are set |
|
|
144
144
|
|
|
145
|
+
### Platform-Adaptive Integration
|
|
146
|
+
|
|
147
|
+
sage automatically detects your platform and uses the best available integration method for calendar and reminder access. This ensures you get the most seamless experience regardless of where you're using Claude.
|
|
148
|
+
|
|
149
|
+
**How it Works**
|
|
150
|
+
|
|
151
|
+
1. **Platform Detection**: When sage starts, it detects your platform from the MCP client information (iOS, iPadOS, macOS, desktop, or web)
|
|
152
|
+
2. **Strategy Selection**: Based on the detected platform, sage selects the optimal integration strategy for calendar and reminder operations
|
|
153
|
+
3. **MCP Sampling Protocol**: On iOS/iPadOS, sage uses the MCP Sampling protocol to instruct Claude to use native Calendar and Reminders APIs
|
|
154
|
+
4. **Native APIs**: On macOS, sage uses EventKit (calendar) and AppleScript (reminders) for direct system integration
|
|
155
|
+
5. **Fallback**: On web/Linux/Windows, sage uses Google Calendar API for calendar features
|
|
156
|
+
|
|
157
|
+
**Platform Capabilities**
|
|
158
|
+
|
|
159
|
+
| Platform | Calendar | Reminders | Integration Method |
|
|
160
|
+
|----------|----------|-----------|-------------------|
|
|
161
|
+
| iOS/iPadOS | Native Calendar + Google Calendar | Native Reminders | MCP Sampling |
|
|
162
|
+
| macOS | EventKit + Google Calendar | AppleScript | Native APIs |
|
|
163
|
+
| Web/Linux/Windows | Google Calendar only | Not available | Google API |
|
|
164
|
+
|
|
165
|
+
**Key Benefits**
|
|
166
|
+
|
|
167
|
+
- **True multi-platform support**: No need to run a Mac server for iOS/iPadOS access
|
|
168
|
+
- **Multi-source calendar integration**: Access both Google Calendar and Apple Calendar simultaneously on iOS/iPadOS
|
|
169
|
+
- **Transparent UX**: sage automatically selects the best method - you don't need to configure anything
|
|
170
|
+
- **Graceful degradation**: If native access is unavailable, sage falls back to API-based methods
|
|
171
|
+
|
|
172
|
+
**Using `get_platform_info`**
|
|
173
|
+
|
|
174
|
+
Query your current platform and available capabilities:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
User: get_platform_info
|
|
178
|
+
|
|
179
|
+
sage:
|
|
180
|
+
{
|
|
181
|
+
"platform": "ipados",
|
|
182
|
+
"clientName": "Claude iOS",
|
|
183
|
+
"clientVersion": "1.0.0",
|
|
184
|
+
"supportsSampling": true,
|
|
185
|
+
"availableIntegrations": {
|
|
186
|
+
"calendar": {
|
|
187
|
+
"google": true,
|
|
188
|
+
"eventkit": false,
|
|
189
|
+
"native": true
|
|
190
|
+
},
|
|
191
|
+
"reminders": {
|
|
192
|
+
"applescript": false,
|
|
193
|
+
"native": true
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Example: Listing Calendar Events on iOS**
|
|
200
|
+
|
|
201
|
+
When you call `list_calendar_events` on iOS/iPadOS, sage uses Sampling to instruct Claude to:
|
|
202
|
+
1. Fetch Google Calendar events via the MCP tool
|
|
203
|
+
2. Access native iOS Calendar events via the native Calendar API
|
|
204
|
+
3. Merge both sets of events, removing duplicates by iCalUID
|
|
205
|
+
4. Return the combined results
|
|
206
|
+
|
|
207
|
+
This happens automatically - you just call the tool normally:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
User: list_calendar_events with startDate: "2026-01-09", endDate: "2026-01-16"
|
|
211
|
+
|
|
212
|
+
sage: (automatically uses Sampling to access both calendars)
|
|
213
|
+
[Shows merged events from both Google Calendar and Apple Calendar]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Example: Creating Reminders on iOS**
|
|
217
|
+
|
|
218
|
+
When you create a reminder on iOS/iPadOS, sage uses Sampling to access the native Reminders app:
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
User: set_reminder with title: "Review pull requests", dueDate: "2026-01-10T15:00:00"
|
|
222
|
+
|
|
223
|
+
sage: (uses Sampling to create reminder in native iOS Reminders app)
|
|
224
|
+
✓ Reminder created successfully
|
|
225
|
+
ID: reminder-123
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Troubleshooting**
|
|
229
|
+
|
|
230
|
+
**Issue**: "Sampling approval required" message appears
|
|
231
|
+
|
|
232
|
+
**Solution**:
|
|
233
|
+
- This is expected behavior on iOS/iPadOS when sage needs to access native Calendar or Reminders
|
|
234
|
+
- Claude will show a prompt asking for your approval to access these native features
|
|
235
|
+
- Approve the Sampling request to allow sage to access your calendar/reminders
|
|
236
|
+
- Once approved, the operation will complete automatically
|
|
237
|
+
|
|
238
|
+
**Issue**: Platform-adaptive integration not working
|
|
239
|
+
|
|
240
|
+
**Checklist**:
|
|
241
|
+
1. Verify your platform supports Sampling (run `get_platform_info`)
|
|
242
|
+
2. Check that you're using a recent version of Claude iOS/iPadOS app
|
|
243
|
+
3. Ensure you've granted Calendar/Reminders permissions in iOS Settings > Privacy
|
|
244
|
+
4. For Google Calendar: Make sure you've authenticated with `authenticate_google`
|
|
245
|
+
|
|
246
|
+
**Issue**: Calendar events not showing up
|
|
247
|
+
|
|
248
|
+
**Possible causes**:
|
|
249
|
+
1. Google Calendar not authenticated: Run `authenticate_google` tool
|
|
250
|
+
2. iOS Calendar permissions denied: Check Settings > Privacy > Calendars
|
|
251
|
+
3. Network connectivity issues: Verify you have internet access
|
|
252
|
+
|
|
253
|
+
**Note**: Platform-adaptive integration requires Claude clients that support MCP Sampling. This includes Claude iOS, Claude iPadOS, and recent versions of Claude Desktop. If your client doesn't support Sampling, sage will automatically fall back to API-based methods.
|
|
254
|
+
|
|
145
255
|
### Smart Reminder Routing
|
|
146
256
|
|
|
147
257
|
Tasks are automatically routed to the appropriate system:
|
|
@@ -48,6 +48,11 @@ export interface ToolDefinition {
|
|
|
48
48
|
export interface MCPHandler {
|
|
49
49
|
handleRequest(request: MCPRequest): Promise<MCPResponse>;
|
|
50
50
|
listTools(): ToolDefinition[];
|
|
51
|
+
/**
|
|
52
|
+
* Shutdown the handler and release all resources
|
|
53
|
+
* Should be called when the handler is no longer needed (e.g., in tests)
|
|
54
|
+
*/
|
|
55
|
+
shutdown(): Promise<void>;
|
|
51
56
|
}
|
|
52
57
|
/**
|
|
53
58
|
* Create an MCP handler
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-handler.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"mcp-handler.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+GH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AASD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACzD,SAAS,IAAI,cAAc,EAAE,CAAC;IAC9B;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAwgDD;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,UAAU,CAAC,CAI5D"}
|
package/dist/cli/mcp-handler.js
CHANGED
|
@@ -15,6 +15,7 @@ import { CalendarEventResponseService } from '../integrations/calendar-event-res
|
|
|
15
15
|
import { WorkingCadenceService } from '../services/working-cadence.js';
|
|
16
16
|
import { CalendarSourceManager } from '../integrations/calendar-source-manager.js';
|
|
17
17
|
import { GoogleCalendarService } from '../integrations/google-calendar-service.js';
|
|
18
|
+
import { GooglePeopleService } from '../integrations/google-people-service.js';
|
|
18
19
|
import { GoogleOAuthHandler } from '../oauth/google-oauth-handler.js';
|
|
19
20
|
// Hot-reload imports
|
|
20
21
|
import { ServiceRegistry } from '../services/service-registry.js';
|
|
@@ -25,9 +26,12 @@ import { getHotReloadConfig } from '../config/hot-reload-config.js';
|
|
|
25
26
|
// Extracted tool handlers
|
|
26
27
|
import { handleCheckSetupStatus, handleStartSetupWizard, handleAnswerWizardQuestion, handleSaveConfig, } from '../tools/setup/index.js';
|
|
27
28
|
import { handleAnalyzeTasks, handleUpdateTaskStatus, handleSyncTasks, handleDetectDuplicates, } from '../tools/tasks/index.js';
|
|
28
|
-
import { handleSetReminder, handleListTodos, } from '../tools/reminders/index.js';
|
|
29
|
+
import { handleSetReminder, handleListTodos, handleSetReminderWithSampling, } from '../tools/reminders/index.js';
|
|
29
30
|
import { handleSyncToNotion, handleUpdateConfig, } from '../tools/integrations/index.js';
|
|
30
|
-
import { handleListCalendarSources, handleListCalendarEvents, handleFindAvailableSlots, handleCreateCalendarEvent, handleRespondToCalendarEvent, handleRespondToCalendarEventsBatch, handleDeleteCalendarEvent, handleDeleteCalendarEventsBatch, } from '../tools/calendar/handlers.js';
|
|
31
|
+
import { handleListCalendarSources, handleListCalendarResources, handleListCalendarEvents, handleFindAvailableSlots, handleCreateCalendarEvent, handleRespondToCalendarEvent, handleRespondToCalendarEventsBatch, handleDeleteCalendarEvent, handleDeleteCalendarEventsBatch, handleUpdateCalendarEvent, handleSearchRoomAvailability, handleCheckRoomAvailability, handleCheckPeopleAvailability, handleFindCommonAvailability, handleListCalendarEventsWithSampling, } from '../tools/calendar/handlers.js';
|
|
32
|
+
// Shared tool definitions
|
|
33
|
+
import { searchRoomAvailabilityTool, checkRoomAvailabilityTool, updateCalendarEventTool, deleteCalendarEventTool, searchDirectoryPeopleTool, checkPeopleAvailabilityTool, findCommonAvailabilityTool, toJsonSchema, } from '../tools/shared/index.js';
|
|
34
|
+
import { handleSearchDirectoryPeople, } from '../tools/directory/index.js';
|
|
31
35
|
import { handleAuthenticateGoogle, } from '../tools/oauth/index.js';
|
|
32
36
|
// Protocol version
|
|
33
37
|
const PROTOCOL_VERSION = '2024-11-05';
|
|
@@ -37,6 +41,7 @@ const PROTOCOL_VERSION = '2024-11-05';
|
|
|
37
41
|
class MCPHandlerImpl {
|
|
38
42
|
config = null;
|
|
39
43
|
wizardSession = null;
|
|
44
|
+
supportsSampling = false;
|
|
40
45
|
reminderManager = null;
|
|
41
46
|
calendarService = null;
|
|
42
47
|
notionService = null;
|
|
@@ -46,6 +51,7 @@ class MCPHandlerImpl {
|
|
|
46
51
|
workingCadenceService = null;
|
|
47
52
|
calendarSourceManager = null;
|
|
48
53
|
googleCalendarService = null;
|
|
54
|
+
googlePeopleService = null;
|
|
49
55
|
initialized = false;
|
|
50
56
|
// Hot-reload infrastructure
|
|
51
57
|
serviceRegistry = null;
|
|
@@ -194,6 +200,8 @@ class MCPHandlerImpl {
|
|
|
194
200
|
};
|
|
195
201
|
const oauthHandler = new GoogleOAuthHandler(oauthConfig);
|
|
196
202
|
this.googleCalendarService = new GoogleCalendarService(oauthHandler);
|
|
203
|
+
// Initialize Google People service with the same OAuth handler
|
|
204
|
+
this.googlePeopleService = new GooglePeopleService(oauthHandler);
|
|
197
205
|
this.calendarSourceManager = new CalendarSourceManager({
|
|
198
206
|
calendarService: this.calendarService,
|
|
199
207
|
googleCalendarService: this.googleCalendarService,
|
|
@@ -295,6 +303,7 @@ class MCPHandlerImpl {
|
|
|
295
303
|
},
|
|
296
304
|
getCalendarEventResponseService: () => this.calendarEventResponseService,
|
|
297
305
|
getGoogleCalendarService: () => this.googleCalendarService,
|
|
306
|
+
getGooglePeopleService: () => this.googlePeopleService,
|
|
298
307
|
getWorkingCadenceService: () => {
|
|
299
308
|
// Prefer reloadable adapter instance if available
|
|
300
309
|
if (this.workingCadenceAdapter) {
|
|
@@ -335,6 +344,25 @@ class MCPHandlerImpl {
|
|
|
335
344
|
createGoogleOAuthHandler: createHandler,
|
|
336
345
|
};
|
|
337
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Create DirectoryToolsContext for directory tool handlers
|
|
349
|
+
*/
|
|
350
|
+
createDirectoryToolsContext() {
|
|
351
|
+
return {
|
|
352
|
+
getConfig: () => this.config,
|
|
353
|
+
getGooglePeopleService: () => this.googlePeopleService,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Create SamplingContext for Sampling-based tool handlers
|
|
358
|
+
*/
|
|
359
|
+
createSamplingContext() {
|
|
360
|
+
return {
|
|
361
|
+
// TODO: Implement MCP Server instance passing for Sampling requests
|
|
362
|
+
// Currently returns null - Sampling handlers will fall back to non-Sampling behavior
|
|
363
|
+
getMcpServer: () => null,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
338
366
|
/**
|
|
339
367
|
* Handle an MCP request
|
|
340
368
|
*/
|
|
@@ -374,8 +402,24 @@ class MCPHandlerImpl {
|
|
|
374
402
|
}
|
|
375
403
|
/**
|
|
376
404
|
* Handle initialize request
|
|
405
|
+
* Requirements: 1.1, 1.6 (platform-adaptive-integration)
|
|
406
|
+
*
|
|
407
|
+
* Extracts clientInfo and capabilities from the initialize request to detect
|
|
408
|
+
* the platform type and available features.
|
|
377
409
|
*/
|
|
378
|
-
handleInitialize(id,
|
|
410
|
+
handleInitialize(id, params) {
|
|
411
|
+
// Extract clientInfo and capabilities from params
|
|
412
|
+
const clientInfo = params?.clientInfo;
|
|
413
|
+
const capabilities = params?.capabilities;
|
|
414
|
+
// Capability-based: check for Sampling support
|
|
415
|
+
if (clientInfo && capabilities) {
|
|
416
|
+
this.supportsSampling = capabilities.sampling !== undefined;
|
|
417
|
+
console.log(`[sage] MCP client initialized: ${clientInfo.name} v${clientInfo.version}, ` +
|
|
418
|
+
`sampling: ${this.supportsSampling}`);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
console.warn('[sage] No clientInfo available in initialize request');
|
|
422
|
+
}
|
|
379
423
|
return {
|
|
380
424
|
jsonrpc: '2.0',
|
|
381
425
|
id,
|
|
@@ -464,6 +508,17 @@ class MCPHandlerImpl {
|
|
|
464
508
|
listTools() {
|
|
465
509
|
return Array.from(this.tools.values()).map((t) => t.definition);
|
|
466
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* Shutdown the handler and release all resources
|
|
513
|
+
* Stops the ConfigReloadService and ConfigWatcher to prevent resource leaks
|
|
514
|
+
*/
|
|
515
|
+
async shutdown() {
|
|
516
|
+
if (this.configReloadService) {
|
|
517
|
+
this.configReloadService.stop();
|
|
518
|
+
this.configReloadService = null;
|
|
519
|
+
}
|
|
520
|
+
this.initialized = false;
|
|
521
|
+
}
|
|
467
522
|
/**
|
|
468
523
|
* Register all tools
|
|
469
524
|
*/
|
|
@@ -562,10 +617,10 @@ class MCPHandlerImpl {
|
|
|
562
617
|
}, async (args) => handleAnalyzeTasks(this.createTaskToolsContext(), {
|
|
563
618
|
tasks: args.tasks,
|
|
564
619
|
}));
|
|
565
|
-
// set_reminder -
|
|
620
|
+
// set_reminder - with platform-based runtime dispatch
|
|
566
621
|
this.registerTool({
|
|
567
622
|
name: 'set_reminder',
|
|
568
|
-
description: 'Set a reminder for a task
|
|
623
|
+
description: 'Set a reminder for a task. Uses native iOS Reminders on iOS/iPad, or AppleScript/Notion on other platforms.',
|
|
569
624
|
inputSchema: {
|
|
570
625
|
type: 'object',
|
|
571
626
|
properties: {
|
|
@@ -601,14 +656,23 @@ class MCPHandlerImpl {
|
|
|
601
656
|
},
|
|
602
657
|
required: ['taskTitle'],
|
|
603
658
|
},
|
|
604
|
-
}, async (args) =>
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
659
|
+
}, async (args) => {
|
|
660
|
+
const input = {
|
|
661
|
+
taskTitle: args.taskTitle,
|
|
662
|
+
dueDate: args.dueDate,
|
|
663
|
+
reminderType: args.reminderType,
|
|
664
|
+
list: args.list,
|
|
665
|
+
priority: args.priority,
|
|
666
|
+
notes: args.notes,
|
|
667
|
+
};
|
|
668
|
+
// Capability-based routing: Use Sampling when available
|
|
669
|
+
if (this.supportsSampling) {
|
|
670
|
+
return handleSetReminderWithSampling(input, this.createReminderTodoContext(), this.createSamplingContext());
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
return handleSetReminder(this.createReminderTodoContext(), input);
|
|
674
|
+
}
|
|
675
|
+
});
|
|
612
676
|
// find_available_slots - uses extracted handler
|
|
613
677
|
this.registerTool({
|
|
614
678
|
name: 'find_available_slots',
|
|
@@ -641,10 +705,10 @@ class MCPHandlerImpl {
|
|
|
641
705
|
endDate: args.endDate,
|
|
642
706
|
preferDeepWork: args.preferDeepWork,
|
|
643
707
|
}));
|
|
644
|
-
// list_calendar_events -
|
|
708
|
+
// list_calendar_events - with platform-based runtime dispatch
|
|
645
709
|
this.registerTool({
|
|
646
710
|
name: 'list_calendar_events',
|
|
647
|
-
description: 'List calendar events for a specified period. Returns events with details including calendar name and location.',
|
|
711
|
+
description: 'List calendar events for a specified period. Uses native iOS Calendar on iOS/iPad, or EventKit/Google Calendar on other platforms. Returns events with details including calendar name and location.',
|
|
648
712
|
inputSchema: {
|
|
649
713
|
type: 'object',
|
|
650
714
|
properties: {
|
|
@@ -663,11 +727,20 @@ class MCPHandlerImpl {
|
|
|
663
727
|
},
|
|
664
728
|
required: ['startDate', 'endDate'],
|
|
665
729
|
},
|
|
666
|
-
}, async (args) =>
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
730
|
+
}, async (args) => {
|
|
731
|
+
const input = {
|
|
732
|
+
startDate: args.startDate,
|
|
733
|
+
endDate: args.endDate,
|
|
734
|
+
calendarId: args.calendarId,
|
|
735
|
+
};
|
|
736
|
+
// Capability-based routing: Use Sampling when available
|
|
737
|
+
if (this.supportsSampling) {
|
|
738
|
+
return handleListCalendarEventsWithSampling(input, this.createCalendarToolsContext(), this.createSamplingContext());
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
return handleListCalendarEvents(this.createCalendarToolsContext(), input);
|
|
742
|
+
}
|
|
743
|
+
});
|
|
671
744
|
// sync_to_notion - uses extracted handler
|
|
672
745
|
this.registerTool({
|
|
673
746
|
name: 'sync_to_notion',
|
|
@@ -965,7 +1038,7 @@ class MCPHandlerImpl {
|
|
|
965
1038
|
// create_calendar_event
|
|
966
1039
|
this.registerTool({
|
|
967
1040
|
name: 'create_calendar_event',
|
|
968
|
-
description: 'Create a new calendar event with support for Google Calendar event types (OOO, Focus Time, Working Location, etc.).',
|
|
1041
|
+
description: 'Create a new calendar event with support for Google Calendar event types (OOO, Focus Time, Working Location, etc.) and recurring events.',
|
|
969
1042
|
inputSchema: {
|
|
970
1043
|
type: 'object',
|
|
971
1044
|
properties: {
|
|
@@ -989,6 +1062,11 @@ class MCPHandlerImpl {
|
|
|
989
1062
|
items: { type: 'string' },
|
|
990
1063
|
description: "Optional: Override default alarms with custom settings (e.g., ['-15m', '-1h']). If omitted, calendar's default alarm settings apply.",
|
|
991
1064
|
},
|
|
1065
|
+
recurrence: {
|
|
1066
|
+
type: 'array',
|
|
1067
|
+
items: { type: 'string' },
|
|
1068
|
+
description: 'Optional: Array of RRULE strings for recurring events (e.g., ["FREQ=WEEKLY;BYDAY=MO,WE,FR"]). Google Calendar only. Supports DAILY, WEEKLY, MONTHLY, YEARLY frequencies with optional INTERVAL, COUNT, UNTIL, and BYDAY parameters.',
|
|
1069
|
+
},
|
|
992
1070
|
eventType: {
|
|
993
1071
|
type: 'string',
|
|
994
1072
|
enum: ['default', 'outOfOffice', 'focusTime', 'workingLocation', 'birthday'],
|
|
@@ -1022,6 +1100,10 @@ class MCPHandlerImpl {
|
|
|
1022
1100
|
enum: ['birthday', 'anniversary', 'other'],
|
|
1023
1101
|
description: 'For birthday: type of birthday event',
|
|
1024
1102
|
},
|
|
1103
|
+
roomId: {
|
|
1104
|
+
type: 'string',
|
|
1105
|
+
description: 'Room calendar ID to book for this event. Use search_room_availability to find available rooms. Requires Google Calendar.',
|
|
1106
|
+
},
|
|
1025
1107
|
},
|
|
1026
1108
|
required: ['title', 'startDate', 'endDate'],
|
|
1027
1109
|
},
|
|
@@ -1032,6 +1114,7 @@ class MCPHandlerImpl {
|
|
|
1032
1114
|
location: args.location,
|
|
1033
1115
|
notes: args.notes,
|
|
1034
1116
|
calendarName: args.calendarName,
|
|
1117
|
+
recurrence: args.recurrence,
|
|
1035
1118
|
eventType: args.eventType,
|
|
1036
1119
|
autoDeclineMode: args.autoDeclineMode,
|
|
1037
1120
|
declineMessage: args.declineMessage,
|
|
@@ -1039,27 +1122,19 @@ class MCPHandlerImpl {
|
|
|
1039
1122
|
workingLocationType: args.workingLocationType,
|
|
1040
1123
|
workingLocationLabel: args.workingLocationLabel,
|
|
1041
1124
|
birthdayType: args.birthdayType,
|
|
1125
|
+
roomId: args.roomId,
|
|
1042
1126
|
}));
|
|
1043
|
-
// delete_calendar_event
|
|
1127
|
+
// delete_calendar_event - Delete a calendar event
|
|
1128
|
+
// Requirement: recurring-calendar-events 5.1
|
|
1129
|
+
// Uses shared definition from tools/shared/calendar-tools.ts
|
|
1044
1130
|
this.registerTool({
|
|
1045
|
-
name:
|
|
1046
|
-
description:
|
|
1047
|
-
inputSchema:
|
|
1048
|
-
type: 'object',
|
|
1049
|
-
properties: {
|
|
1050
|
-
eventId: {
|
|
1051
|
-
type: 'string',
|
|
1052
|
-
description: 'Event ID (UUID or full ID from list_calendar_events)',
|
|
1053
|
-
},
|
|
1054
|
-
calendarName: {
|
|
1055
|
-
type: 'string',
|
|
1056
|
-
description: 'Calendar name (searches all calendars if not specified)',
|
|
1057
|
-
},
|
|
1058
|
-
},
|
|
1059
|
-
required: ['eventId'],
|
|
1060
|
-
},
|
|
1131
|
+
name: deleteCalendarEventTool.name,
|
|
1132
|
+
description: deleteCalendarEventTool.description,
|
|
1133
|
+
inputSchema: toJsonSchema(deleteCalendarEventTool.schema),
|
|
1061
1134
|
}, async (args) => handleDeleteCalendarEvent(this.createCalendarToolsContext(), {
|
|
1062
1135
|
eventId: args.eventId,
|
|
1136
|
+
deleteScope: args.deleteScope,
|
|
1137
|
+
calendarName: args.calendarName,
|
|
1063
1138
|
}));
|
|
1064
1139
|
// delete_calendar_events_batch
|
|
1065
1140
|
this.registerTool({
|
|
@@ -1083,6 +1158,29 @@ class MCPHandlerImpl {
|
|
|
1083
1158
|
}, async (args) => handleDeleteCalendarEventsBatch(this.createCalendarToolsContext(), {
|
|
1084
1159
|
eventIds: args.eventIds,
|
|
1085
1160
|
}));
|
|
1161
|
+
// update_calendar_event - Update an existing calendar event
|
|
1162
|
+
// Requirement: update-calendar-event 1-8
|
|
1163
|
+
// Uses shared definition from tools/shared/calendar-tools.ts
|
|
1164
|
+
this.registerTool({
|
|
1165
|
+
name: updateCalendarEventTool.name,
|
|
1166
|
+
description: updateCalendarEventTool.description,
|
|
1167
|
+
inputSchema: toJsonSchema(updateCalendarEventTool.schema),
|
|
1168
|
+
}, async (args) => handleUpdateCalendarEvent(this.createCalendarToolsContext(), {
|
|
1169
|
+
eventId: args.eventId,
|
|
1170
|
+
title: args.title,
|
|
1171
|
+
startDate: args.startDate,
|
|
1172
|
+
endDate: args.endDate,
|
|
1173
|
+
location: args.location,
|
|
1174
|
+
notes: args.notes,
|
|
1175
|
+
attendees: args.attendees,
|
|
1176
|
+
alarms: args.alarms,
|
|
1177
|
+
roomId: args.roomId,
|
|
1178
|
+
removeRoom: args.removeRoom,
|
|
1179
|
+
autoDeclineMode: args.autoDeclineMode,
|
|
1180
|
+
declineMessage: args.declineMessage,
|
|
1181
|
+
chatStatus: args.chatStatus,
|
|
1182
|
+
calendarName: args.calendarName,
|
|
1183
|
+
}));
|
|
1086
1184
|
// list_calendar_sources - uses extracted handler
|
|
1087
1185
|
this.registerTool({
|
|
1088
1186
|
name: 'list_calendar_sources',
|
|
@@ -1092,6 +1190,89 @@ class MCPHandlerImpl {
|
|
|
1092
1190
|
properties: {},
|
|
1093
1191
|
},
|
|
1094
1192
|
}, async () => handleListCalendarSources(this.createCalendarToolsContext()));
|
|
1193
|
+
// list_calendar_resources - list individual calendars from all sources
|
|
1194
|
+
// Requirement: multi-calendar-resources 1.1
|
|
1195
|
+
this.registerTool({
|
|
1196
|
+
name: 'list_calendar_resources',
|
|
1197
|
+
description: 'List all available calendar resources (individual calendars) from enabled sources. Returns calendar names, IDs, colors, and write permissions.',
|
|
1198
|
+
inputSchema: {
|
|
1199
|
+
type: 'object',
|
|
1200
|
+
properties: {
|
|
1201
|
+
source: {
|
|
1202
|
+
type: 'string',
|
|
1203
|
+
enum: ['eventkit', 'google', 'all'],
|
|
1204
|
+
description: "Filter by source type: 'eventkit', 'google', or 'all' (default: 'all')",
|
|
1205
|
+
},
|
|
1206
|
+
},
|
|
1207
|
+
},
|
|
1208
|
+
}, async (args) => handleListCalendarResources(this.createCalendarToolsContext(), {
|
|
1209
|
+
source: args.source,
|
|
1210
|
+
}));
|
|
1211
|
+
// search_room_availability - Search for available meeting rooms
|
|
1212
|
+
// Requirement: room-availability-search 1
|
|
1213
|
+
// Uses shared definition from tools/shared/room-tools.ts
|
|
1214
|
+
this.registerTool({
|
|
1215
|
+
name: searchRoomAvailabilityTool.name,
|
|
1216
|
+
description: searchRoomAvailabilityTool.description,
|
|
1217
|
+
inputSchema: toJsonSchema(searchRoomAvailabilityTool.schema),
|
|
1218
|
+
}, async (args) => handleSearchRoomAvailability(this.createCalendarToolsContext(), {
|
|
1219
|
+
startTime: args.startTime,
|
|
1220
|
+
endTime: args.endTime,
|
|
1221
|
+
durationMinutes: args.durationMinutes,
|
|
1222
|
+
minCapacity: args.minCapacity,
|
|
1223
|
+
building: args.building,
|
|
1224
|
+
floor: args.floor,
|
|
1225
|
+
features: args.features,
|
|
1226
|
+
}));
|
|
1227
|
+
// check_room_availability - Check availability of a specific room
|
|
1228
|
+
// Requirement: room-availability-search 2
|
|
1229
|
+
// Uses shared definition from tools/shared/room-tools.ts
|
|
1230
|
+
this.registerTool({
|
|
1231
|
+
name: checkRoomAvailabilityTool.name,
|
|
1232
|
+
description: checkRoomAvailabilityTool.description,
|
|
1233
|
+
inputSchema: toJsonSchema(checkRoomAvailabilityTool.schema),
|
|
1234
|
+
}, async (args) => handleCheckRoomAvailability(this.createCalendarToolsContext(), {
|
|
1235
|
+
roomId: args.roomId,
|
|
1236
|
+
startTime: args.startTime,
|
|
1237
|
+
endTime: args.endTime,
|
|
1238
|
+
}));
|
|
1239
|
+
// search_directory_people - Search organization directory for people
|
|
1240
|
+
// Requirement: directory-people-search 1
|
|
1241
|
+
// Uses shared definition from tools/shared/directory-tools.ts
|
|
1242
|
+
this.registerTool({
|
|
1243
|
+
name: searchDirectoryPeopleTool.name,
|
|
1244
|
+
description: searchDirectoryPeopleTool.description,
|
|
1245
|
+
inputSchema: toJsonSchema(searchDirectoryPeopleTool.schema),
|
|
1246
|
+
}, async (args) => handleSearchDirectoryPeople(this.createDirectoryToolsContext(), {
|
|
1247
|
+
query: args.query,
|
|
1248
|
+
pageSize: args.pageSize,
|
|
1249
|
+
}));
|
|
1250
|
+
// check_people_availability - Check availability of people by email
|
|
1251
|
+
// Requirement: check-others-availability 1
|
|
1252
|
+
// Uses shared definition from tools/shared/availability-tools.ts
|
|
1253
|
+
this.registerTool({
|
|
1254
|
+
name: checkPeopleAvailabilityTool.name,
|
|
1255
|
+
description: checkPeopleAvailabilityTool.description,
|
|
1256
|
+
inputSchema: toJsonSchema(checkPeopleAvailabilityTool.schema),
|
|
1257
|
+
}, async (args) => handleCheckPeopleAvailability(this.createCalendarToolsContext(), {
|
|
1258
|
+
emails: args.emails,
|
|
1259
|
+
startTime: args.startTime,
|
|
1260
|
+
endTime: args.endTime,
|
|
1261
|
+
}));
|
|
1262
|
+
// find_common_availability - Find common free time among people
|
|
1263
|
+
// Requirement: check-others-availability 2, 4
|
|
1264
|
+
// Uses shared definition from tools/shared/availability-tools.ts
|
|
1265
|
+
this.registerTool({
|
|
1266
|
+
name: findCommonAvailabilityTool.name,
|
|
1267
|
+
description: findCommonAvailabilityTool.description,
|
|
1268
|
+
inputSchema: toJsonSchema(findCommonAvailabilityTool.schema),
|
|
1269
|
+
}, async (args) => handleFindCommonAvailability(this.createCalendarToolsContext(), {
|
|
1270
|
+
participants: args.participants,
|
|
1271
|
+
startTime: args.startTime,
|
|
1272
|
+
endTime: args.endTime,
|
|
1273
|
+
minDurationMinutes: args.minDurationMinutes,
|
|
1274
|
+
includeMyCalendar: args.includeMyCalendar,
|
|
1275
|
+
}));
|
|
1095
1276
|
// authenticate_google - Complete Google OAuth flow automatically
|
|
1096
1277
|
this.registerTool({
|
|
1097
1278
|
name: 'authenticate_google',
|