@shin1ohno/sage 0.3.0 → 0.5.5
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/dist/cli/http-server-with-config.d.ts +38 -0
- package/dist/cli/http-server-with-config.d.ts.map +1 -0
- package/dist/cli/http-server-with-config.js +477 -0
- package/dist/cli/http-server-with-config.js.map +1 -0
- package/dist/cli/http-server.d.ts +74 -0
- package/dist/cli/http-server.d.ts.map +1 -0
- package/dist/cli/http-server.js +407 -0
- package/dist/cli/http-server.js.map +1 -0
- package/dist/cli/jwt-middleware.d.ts +36 -0
- package/dist/cli/jwt-middleware.d.ts.map +1 -0
- package/dist/cli/jwt-middleware.js +99 -0
- package/dist/cli/jwt-middleware.js.map +1 -0
- package/dist/cli/main-entry.d.ts +45 -0
- package/dist/cli/main-entry.d.ts.map +1 -0
- package/dist/cli/main-entry.js +192 -0
- package/dist/cli/main-entry.js.map +1 -0
- package/dist/cli/mcp-handler.d.ts +56 -0
- package/dist/cli/mcp-handler.d.ts.map +1 -0
- package/dist/cli/mcp-handler.js +2189 -0
- package/dist/cli/mcp-handler.js.map +1 -0
- package/dist/cli/parser.d.ts +45 -0
- package/dist/cli/parser.d.ts.map +1 -0
- package/dist/cli/parser.js +172 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/cli/remote-config-loader.d.ts +89 -0
- package/dist/cli/remote-config-loader.d.ts.map +1 -0
- package/dist/cli/remote-config-loader.js +129 -0
- package/dist/cli/remote-config-loader.js.map +1 -0
- package/dist/cli/secret-auth.d.ts +47 -0
- package/dist/cli/secret-auth.d.ts.map +1 -0
- package/dist/cli/secret-auth.js +165 -0
- package/dist/cli/secret-auth.js.map +1 -0
- package/dist/cli/sse-stream-handler.d.ts +45 -0
- package/dist/cli/sse-stream-handler.d.ts.map +1 -0
- package/dist/cli/sse-stream-handler.js +125 -0
- package/dist/cli/sse-stream-handler.js.map +1 -0
- package/dist/index.js +897 -209
- package/dist/index.js.map +1 -1
- package/dist/integrations/calendar-event-creator.d.ts +152 -0
- package/dist/integrations/calendar-event-creator.d.ts.map +1 -0
- package/dist/integrations/calendar-event-creator.js +507 -0
- package/dist/integrations/calendar-event-creator.js.map +1 -0
- package/dist/integrations/calendar-event-deleter.d.ts +137 -0
- package/dist/integrations/calendar-event-deleter.d.ts.map +1 -0
- package/dist/integrations/calendar-event-deleter.js +378 -0
- package/dist/integrations/calendar-event-deleter.js.map +1 -0
- package/dist/integrations/calendar-event-response.d.ts +213 -0
- package/dist/integrations/calendar-event-response.d.ts.map +1 -0
- package/dist/integrations/calendar-event-response.js +560 -0
- package/dist/integrations/calendar-event-response.js.map +1 -0
- package/dist/integrations/calendar-service.d.ts +66 -1
- package/dist/integrations/calendar-service.d.ts.map +1 -1
- package/dist/integrations/calendar-service.js +223 -0
- package/dist/integrations/calendar-service.js.map +1 -1
- package/dist/oauth/client-store.d.ts +36 -0
- package/dist/oauth/client-store.d.ts.map +1 -0
- package/dist/oauth/client-store.js +119 -0
- package/dist/oauth/client-store.js.map +1 -0
- package/dist/oauth/code-store.d.ts +48 -0
- package/dist/oauth/code-store.d.ts.map +1 -0
- package/dist/oauth/code-store.js +89 -0
- package/dist/oauth/code-store.js.map +1 -0
- package/dist/oauth/index.d.ts +13 -0
- package/dist/oauth/index.d.ts.map +1 -0
- package/dist/oauth/index.js +21 -0
- package/dist/oauth/index.js.map +1 -0
- package/dist/oauth/oauth-handler.d.ts +101 -0
- package/dist/oauth/oauth-handler.d.ts.map +1 -0
- package/dist/oauth/oauth-handler.js +577 -0
- package/dist/oauth/oauth-handler.js.map +1 -0
- package/dist/oauth/oauth-server.d.ts +165 -0
- package/dist/oauth/oauth-server.d.ts.map +1 -0
- package/dist/oauth/oauth-server.js +489 -0
- package/dist/oauth/oauth-server.js.map +1 -0
- package/dist/oauth/pkce.d.ts +48 -0
- package/dist/oauth/pkce.d.ts.map +1 -0
- package/dist/oauth/pkce.js +106 -0
- package/dist/oauth/pkce.js.map +1 -0
- package/dist/oauth/refresh-token-store.d.ts +45 -0
- package/dist/oauth/refresh-token-store.d.ts.map +1 -0
- package/dist/oauth/refresh-token-store.js +98 -0
- package/dist/oauth/refresh-token-store.js.map +1 -0
- package/dist/oauth/token-service.d.ts +46 -0
- package/dist/oauth/token-service.d.ts.map +1 -0
- package/dist/oauth/token-service.js +199 -0
- package/dist/oauth/token-service.js.map +1 -0
- package/dist/oauth/types.d.ts +269 -0
- package/dist/oauth/types.d.ts.map +1 -0
- package/dist/oauth/types.js +53 -0
- package/dist/oauth/types.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,20 +5,21 @@
|
|
|
5
5
|
* An MCP server for Claude Desktop and Claude Code that provides
|
|
6
6
|
* task management, prioritization, and reminder integration.
|
|
7
7
|
*/
|
|
8
|
-
import { McpServer } from
|
|
9
|
-
import { StdioServerTransport } from
|
|
10
|
-
import { z } from
|
|
11
|
-
import { ConfigLoader } from
|
|
12
|
-
import { SetupWizard } from
|
|
13
|
-
import { TaskAnalyzer } from
|
|
14
|
-
import { ReminderManager } from
|
|
15
|
-
import { CalendarService } from
|
|
16
|
-
import { NotionMCPService } from
|
|
17
|
-
import { TodoListManager } from
|
|
18
|
-
import { TaskSynchronizer } from
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { ConfigLoader } from "./config/loader.js";
|
|
12
|
+
import { SetupWizard } from "./setup/wizard.js";
|
|
13
|
+
import { TaskAnalyzer } from "./tools/analyze-tasks.js";
|
|
14
|
+
import { ReminderManager } from "./integrations/reminder-manager.js";
|
|
15
|
+
import { CalendarService } from "./integrations/calendar-service.js";
|
|
16
|
+
import { NotionMCPService } from "./integrations/notion-mcp.js";
|
|
17
|
+
import { TodoListManager } from "./integrations/todo-list-manager.js";
|
|
18
|
+
import { TaskSynchronizer } from "./integrations/task-synchronizer.js";
|
|
19
|
+
import { CalendarEventResponseService } from "./integrations/calendar-event-response.js";
|
|
20
|
+
import { CalendarEventCreatorService } from "./integrations/calendar-event-creator.js";
|
|
21
|
+
import { CalendarEventDeleterService } from "./integrations/calendar-event-deleter.js";
|
|
22
|
+
import { VERSION, SERVER_NAME } from "./version.js";
|
|
22
23
|
// Global state
|
|
23
24
|
let config = null;
|
|
24
25
|
let wizardSession = null;
|
|
@@ -27,55 +28,61 @@ let calendarService = null;
|
|
|
27
28
|
let notionService = null;
|
|
28
29
|
let todoListManager = null;
|
|
29
30
|
let taskSynchronizer = null;
|
|
31
|
+
let calendarEventResponseService = null;
|
|
32
|
+
let calendarEventCreatorService = null;
|
|
33
|
+
let calendarEventDeleterService = null;
|
|
30
34
|
/**
|
|
31
35
|
* Validate config updates for a specific section
|
|
32
36
|
*/
|
|
33
37
|
function validateConfigUpdate(section, updates) {
|
|
34
38
|
const invalidFields = [];
|
|
35
39
|
switch (section) {
|
|
36
|
-
case
|
|
37
|
-
if (updates.name !== undefined && typeof updates.name !==
|
|
38
|
-
invalidFields.push(
|
|
40
|
+
case "user":
|
|
41
|
+
if (updates.name !== undefined && typeof updates.name !== "string") {
|
|
42
|
+
invalidFields.push("name");
|
|
39
43
|
}
|
|
40
|
-
if (updates.timezone !== undefined &&
|
|
41
|
-
|
|
44
|
+
if (updates.timezone !== undefined &&
|
|
45
|
+
typeof updates.timezone !== "string") {
|
|
46
|
+
invalidFields.push("timezone");
|
|
42
47
|
}
|
|
43
48
|
break;
|
|
44
|
-
case
|
|
49
|
+
case "calendar":
|
|
45
50
|
if (updates.workingHours !== undefined) {
|
|
46
51
|
const wh = updates.workingHours;
|
|
47
52
|
if (!wh.start || !wh.end) {
|
|
48
|
-
invalidFields.push(
|
|
53
|
+
invalidFields.push("workingHours");
|
|
49
54
|
}
|
|
50
55
|
}
|
|
51
|
-
if (updates.deepWorkDays !== undefined &&
|
|
52
|
-
|
|
56
|
+
if (updates.deepWorkDays !== undefined &&
|
|
57
|
+
!Array.isArray(updates.deepWorkDays)) {
|
|
58
|
+
invalidFields.push("deepWorkDays");
|
|
53
59
|
}
|
|
54
|
-
if (updates.meetingHeavyDays !== undefined &&
|
|
55
|
-
|
|
60
|
+
if (updates.meetingHeavyDays !== undefined &&
|
|
61
|
+
!Array.isArray(updates.meetingHeavyDays)) {
|
|
62
|
+
invalidFields.push("meetingHeavyDays");
|
|
56
63
|
}
|
|
57
64
|
break;
|
|
58
|
-
case
|
|
65
|
+
case "integrations":
|
|
59
66
|
if (updates.notion !== undefined) {
|
|
60
67
|
const notion = updates.notion;
|
|
61
68
|
if (notion.enabled === true && !notion.databaseId) {
|
|
62
|
-
invalidFields.push(
|
|
69
|
+
invalidFields.push("notion.databaseId");
|
|
63
70
|
}
|
|
64
71
|
}
|
|
65
72
|
break;
|
|
66
|
-
case
|
|
73
|
+
case "team":
|
|
67
74
|
if (updates.members !== undefined && !Array.isArray(updates.members)) {
|
|
68
|
-
invalidFields.push(
|
|
75
|
+
invalidFields.push("members");
|
|
69
76
|
}
|
|
70
77
|
if (updates.managers !== undefined && !Array.isArray(updates.managers)) {
|
|
71
|
-
invalidFields.push(
|
|
78
|
+
invalidFields.push("managers");
|
|
72
79
|
}
|
|
73
80
|
break;
|
|
74
81
|
}
|
|
75
82
|
if (invalidFields.length > 0) {
|
|
76
83
|
return {
|
|
77
84
|
valid: false,
|
|
78
|
-
error: `無効なフィールド: ${invalidFields.join(
|
|
85
|
+
error: `無効なフィールド: ${invalidFields.join(", ")}`,
|
|
79
86
|
invalidFields,
|
|
80
87
|
};
|
|
81
88
|
}
|
|
@@ -87,19 +94,22 @@ function validateConfigUpdate(section, updates) {
|
|
|
87
94
|
function applyConfigUpdates(currentConfig, section, updates) {
|
|
88
95
|
const newConfig = { ...currentConfig };
|
|
89
96
|
switch (section) {
|
|
90
|
-
case
|
|
97
|
+
case "user":
|
|
91
98
|
newConfig.user = { ...newConfig.user, ...updates };
|
|
92
99
|
break;
|
|
93
|
-
case
|
|
94
|
-
newConfig.calendar = {
|
|
100
|
+
case "calendar":
|
|
101
|
+
newConfig.calendar = {
|
|
102
|
+
...newConfig.calendar,
|
|
103
|
+
...updates,
|
|
104
|
+
};
|
|
95
105
|
break;
|
|
96
|
-
case
|
|
106
|
+
case "priorityRules":
|
|
97
107
|
newConfig.priorityRules = {
|
|
98
108
|
...newConfig.priorityRules,
|
|
99
109
|
...updates,
|
|
100
110
|
};
|
|
101
111
|
break;
|
|
102
|
-
case
|
|
112
|
+
case "integrations":
|
|
103
113
|
// Deep merge for integrations
|
|
104
114
|
if (updates.appleReminders) {
|
|
105
115
|
newConfig.integrations.appleReminders = {
|
|
@@ -114,11 +124,14 @@ function applyConfigUpdates(currentConfig, section, updates) {
|
|
|
114
124
|
};
|
|
115
125
|
}
|
|
116
126
|
break;
|
|
117
|
-
case
|
|
127
|
+
case "team":
|
|
118
128
|
newConfig.team = { ...newConfig.team, ...updates };
|
|
119
129
|
break;
|
|
120
|
-
case
|
|
121
|
-
newConfig.preferences = {
|
|
130
|
+
case "preferences":
|
|
131
|
+
newConfig.preferences = {
|
|
132
|
+
...newConfig.preferences,
|
|
133
|
+
...updates,
|
|
134
|
+
};
|
|
122
135
|
break;
|
|
123
136
|
}
|
|
124
137
|
return newConfig;
|
|
@@ -137,6 +150,9 @@ function initializeServices(userConfig) {
|
|
|
137
150
|
notionService = new NotionMCPService();
|
|
138
151
|
todoListManager = new TodoListManager();
|
|
139
152
|
taskSynchronizer = new TaskSynchronizer();
|
|
153
|
+
calendarEventResponseService = new CalendarEventResponseService();
|
|
154
|
+
calendarEventCreatorService = new CalendarEventCreatorService();
|
|
155
|
+
calendarEventDeleterService = new CalendarEventDeleterService();
|
|
140
156
|
}
|
|
141
157
|
/**
|
|
142
158
|
* Initialize the MCP server with all tools
|
|
@@ -144,7 +160,7 @@ function initializeServices(userConfig) {
|
|
|
144
160
|
async function createServer() {
|
|
145
161
|
const server = new McpServer({
|
|
146
162
|
name: SERVER_NAME,
|
|
147
|
-
version:
|
|
163
|
+
version: VERSION,
|
|
148
164
|
});
|
|
149
165
|
// Try to load existing config
|
|
150
166
|
try {
|
|
@@ -163,19 +179,19 @@ async function createServer() {
|
|
|
163
179
|
* check_setup_status - Check if initial setup is complete
|
|
164
180
|
* Requirement: 1.1, 1.2
|
|
165
181
|
*/
|
|
166
|
-
server.tool(
|
|
182
|
+
server.tool("check_setup_status", "Check if sage has been configured. Returns setup status and guidance.", {}, async () => {
|
|
167
183
|
const exists = await ConfigLoader.exists();
|
|
168
184
|
const isValid = config !== null;
|
|
169
185
|
if (!exists) {
|
|
170
186
|
return {
|
|
171
187
|
content: [
|
|
172
188
|
{
|
|
173
|
-
type:
|
|
189
|
+
type: "text",
|
|
174
190
|
text: JSON.stringify({
|
|
175
191
|
setupComplete: false,
|
|
176
192
|
configExists: false,
|
|
177
|
-
message:
|
|
178
|
-
nextAction:
|
|
193
|
+
message: "sageの初期設定が必要です。start_setup_wizardを実行してセットアップを開始してください。",
|
|
194
|
+
nextAction: "start_setup_wizard",
|
|
179
195
|
}, null, 2),
|
|
180
196
|
},
|
|
181
197
|
],
|
|
@@ -185,12 +201,12 @@ async function createServer() {
|
|
|
185
201
|
return {
|
|
186
202
|
content: [
|
|
187
203
|
{
|
|
188
|
-
type:
|
|
204
|
+
type: "text",
|
|
189
205
|
text: JSON.stringify({
|
|
190
206
|
setupComplete: false,
|
|
191
207
|
configExists: true,
|
|
192
|
-
message:
|
|
193
|
-
nextAction:
|
|
208
|
+
message: "設定ファイルが見つかりましたが、読み込みに失敗しました。設定を再作成してください。",
|
|
209
|
+
nextAction: "start_setup_wizard",
|
|
194
210
|
}, null, 2),
|
|
195
211
|
},
|
|
196
212
|
],
|
|
@@ -199,18 +215,18 @@ async function createServer() {
|
|
|
199
215
|
return {
|
|
200
216
|
content: [
|
|
201
217
|
{
|
|
202
|
-
type:
|
|
218
|
+
type: "text",
|
|
203
219
|
text: JSON.stringify({
|
|
204
220
|
setupComplete: true,
|
|
205
221
|
configExists: true,
|
|
206
222
|
userName: config?.user.name,
|
|
207
|
-
message:
|
|
223
|
+
message: "sageは設定済みです。タスク分析やリマインド設定を開始できます。",
|
|
208
224
|
availableTools: [
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
225
|
+
"analyze_tasks",
|
|
226
|
+
"set_reminder",
|
|
227
|
+
"find_available_slots",
|
|
228
|
+
"sync_to_notion",
|
|
229
|
+
"update_config",
|
|
214
230
|
],
|
|
215
231
|
}, null, 2),
|
|
216
232
|
},
|
|
@@ -221,18 +237,18 @@ async function createServer() {
|
|
|
221
237
|
* start_setup_wizard - Begin the interactive setup process
|
|
222
238
|
* Requirement: 1.3
|
|
223
239
|
*/
|
|
224
|
-
server.tool(
|
|
240
|
+
server.tool("start_setup_wizard", "Start the interactive setup wizard for sage. Returns the first question.", {
|
|
225
241
|
mode: z
|
|
226
|
-
.enum([
|
|
242
|
+
.enum(["full", "quick"])
|
|
227
243
|
.optional()
|
|
228
|
-
.describe(
|
|
229
|
-
}, async ({ mode =
|
|
244
|
+
.describe("Setup mode: full (all questions) or quick (essential only)"),
|
|
245
|
+
}, async ({ mode = "full" }) => {
|
|
230
246
|
wizardSession = SetupWizard.createSession(mode);
|
|
231
247
|
const question = SetupWizard.getCurrentQuestion(wizardSession);
|
|
232
248
|
return {
|
|
233
249
|
content: [
|
|
234
250
|
{
|
|
235
|
-
type:
|
|
251
|
+
type: "text",
|
|
236
252
|
text: JSON.stringify({
|
|
237
253
|
sessionId: wizardSession.sessionId,
|
|
238
254
|
currentStep: wizardSession.currentStep,
|
|
@@ -246,7 +262,7 @@ async function createServer() {
|
|
|
246
262
|
defaultValue: question.defaultValue,
|
|
247
263
|
helpText: question.helpText,
|
|
248
264
|
},
|
|
249
|
-
message:
|
|
265
|
+
message: "セットアップを開始します。以下の質問に回答してください。",
|
|
250
266
|
}, null, 2),
|
|
251
267
|
},
|
|
252
268
|
],
|
|
@@ -256,18 +272,20 @@ async function createServer() {
|
|
|
256
272
|
* answer_wizard_question - Answer a setup wizard question
|
|
257
273
|
* Requirement: 1.3, 1.4
|
|
258
274
|
*/
|
|
259
|
-
server.tool(
|
|
260
|
-
questionId: z.string().describe(
|
|
261
|
-
answer: z
|
|
275
|
+
server.tool("answer_wizard_question", "Answer a question in the setup wizard and get the next question.", {
|
|
276
|
+
questionId: z.string().describe("The ID of the question being answered"),
|
|
277
|
+
answer: z
|
|
278
|
+
.union([z.string(), z.array(z.string())])
|
|
279
|
+
.describe("The answer to the question"),
|
|
262
280
|
}, async ({ questionId, answer }) => {
|
|
263
281
|
if (!wizardSession) {
|
|
264
282
|
return {
|
|
265
283
|
content: [
|
|
266
284
|
{
|
|
267
|
-
type:
|
|
285
|
+
type: "text",
|
|
268
286
|
text: JSON.stringify({
|
|
269
287
|
error: true,
|
|
270
|
-
message:
|
|
288
|
+
message: "セットアップセッションが見つかりません。start_setup_wizardを実行してください。",
|
|
271
289
|
}, null, 2),
|
|
272
290
|
},
|
|
273
291
|
],
|
|
@@ -278,7 +296,7 @@ async function createServer() {
|
|
|
278
296
|
return {
|
|
279
297
|
content: [
|
|
280
298
|
{
|
|
281
|
-
type:
|
|
299
|
+
type: "text",
|
|
282
300
|
text: JSON.stringify({
|
|
283
301
|
error: true,
|
|
284
302
|
message: result.error,
|
|
@@ -292,13 +310,13 @@ async function createServer() {
|
|
|
292
310
|
return {
|
|
293
311
|
content: [
|
|
294
312
|
{
|
|
295
|
-
type:
|
|
313
|
+
type: "text",
|
|
296
314
|
text: JSON.stringify({
|
|
297
315
|
isComplete: true,
|
|
298
316
|
sessionId: wizardSession.sessionId,
|
|
299
317
|
answers: wizardSession.answers,
|
|
300
|
-
message:
|
|
301
|
-
nextAction:
|
|
318
|
+
message: "すべての質問に回答しました。save_configを実行して設定を保存してください。",
|
|
319
|
+
nextAction: "save_config",
|
|
302
320
|
}, null, 2),
|
|
303
321
|
},
|
|
304
322
|
],
|
|
@@ -308,7 +326,7 @@ async function createServer() {
|
|
|
308
326
|
return {
|
|
309
327
|
content: [
|
|
310
328
|
{
|
|
311
|
-
type:
|
|
329
|
+
type: "text",
|
|
312
330
|
text: JSON.stringify({
|
|
313
331
|
success: true,
|
|
314
332
|
currentStep: wizardSession.currentStep,
|
|
@@ -331,17 +349,17 @@ async function createServer() {
|
|
|
331
349
|
* save_config - Save the configuration from the setup wizard
|
|
332
350
|
* Requirement: 1.4, 1.5, 1.6
|
|
333
351
|
*/
|
|
334
|
-
server.tool(
|
|
335
|
-
confirm: z.boolean().describe(
|
|
352
|
+
server.tool("save_config", "Save the configuration after completing the setup wizard.", {
|
|
353
|
+
confirm: z.boolean().describe("Confirm saving the configuration"),
|
|
336
354
|
}, async ({ confirm }) => {
|
|
337
355
|
if (!confirm) {
|
|
338
356
|
return {
|
|
339
357
|
content: [
|
|
340
358
|
{
|
|
341
|
-
type:
|
|
359
|
+
type: "text",
|
|
342
360
|
text: JSON.stringify({
|
|
343
361
|
saved: false,
|
|
344
|
-
message:
|
|
362
|
+
message: "設定の保存がキャンセルされました。",
|
|
345
363
|
}, null, 2),
|
|
346
364
|
},
|
|
347
365
|
],
|
|
@@ -351,10 +369,10 @@ async function createServer() {
|
|
|
351
369
|
return {
|
|
352
370
|
content: [
|
|
353
371
|
{
|
|
354
|
-
type:
|
|
372
|
+
type: "text",
|
|
355
373
|
text: JSON.stringify({
|
|
356
374
|
error: true,
|
|
357
|
-
message:
|
|
375
|
+
message: "セットアップセッションが見つかりません。start_setup_wizardを実行してください。",
|
|
358
376
|
}, null, 2),
|
|
359
377
|
},
|
|
360
378
|
],
|
|
@@ -368,17 +386,17 @@ async function createServer() {
|
|
|
368
386
|
return {
|
|
369
387
|
content: [
|
|
370
388
|
{
|
|
371
|
-
type:
|
|
389
|
+
type: "text",
|
|
372
390
|
text: JSON.stringify({
|
|
373
391
|
saved: true,
|
|
374
392
|
configPath: ConfigLoader.getConfigPath(),
|
|
375
393
|
userName: newConfig.user.name,
|
|
376
394
|
message: `設定を保存しました。${newConfig.user.name}さん、sageをご利用いただきありがとうございます!`,
|
|
377
395
|
availableTools: [
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
396
|
+
"analyze_tasks",
|
|
397
|
+
"set_reminder",
|
|
398
|
+
"find_available_slots",
|
|
399
|
+
"sync_to_notion",
|
|
382
400
|
],
|
|
383
401
|
}, null, 2),
|
|
384
402
|
},
|
|
@@ -389,10 +407,10 @@ async function createServer() {
|
|
|
389
407
|
return {
|
|
390
408
|
content: [
|
|
391
409
|
{
|
|
392
|
-
type:
|
|
410
|
+
type: "text",
|
|
393
411
|
text: JSON.stringify({
|
|
394
412
|
error: true,
|
|
395
|
-
message: `設定の保存に失敗しました: ${error instanceof Error ? error.message :
|
|
413
|
+
message: `設定の保存に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
396
414
|
}, null, 2),
|
|
397
415
|
},
|
|
398
416
|
],
|
|
@@ -406,23 +424,26 @@ async function createServer() {
|
|
|
406
424
|
* analyze_tasks - Analyze tasks and provide prioritization
|
|
407
425
|
* Requirement: 2.1-2.6, 3.1-3.2, 4.1-4.5
|
|
408
426
|
*/
|
|
409
|
-
server.tool(
|
|
427
|
+
server.tool("analyze_tasks", "Analyze tasks to determine priority, estimate time, and identify stakeholders.", {
|
|
410
428
|
tasks: z
|
|
411
429
|
.array(z.object({
|
|
412
|
-
title: z.string().describe(
|
|
413
|
-
description: z.string().optional().describe(
|
|
414
|
-
deadline: z
|
|
430
|
+
title: z.string().describe("Task title"),
|
|
431
|
+
description: z.string().optional().describe("Task description"),
|
|
432
|
+
deadline: z
|
|
433
|
+
.string()
|
|
434
|
+
.optional()
|
|
435
|
+
.describe("Task deadline (ISO 8601 format)"),
|
|
415
436
|
}))
|
|
416
|
-
.describe(
|
|
437
|
+
.describe("List of tasks to analyze"),
|
|
417
438
|
}, async ({ tasks }) => {
|
|
418
439
|
if (!config) {
|
|
419
440
|
return {
|
|
420
441
|
content: [
|
|
421
442
|
{
|
|
422
|
-
type:
|
|
443
|
+
type: "text",
|
|
423
444
|
text: JSON.stringify({
|
|
424
445
|
error: true,
|
|
425
|
-
message:
|
|
446
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
426
447
|
}, null, 2),
|
|
427
448
|
},
|
|
428
449
|
],
|
|
@@ -433,7 +454,7 @@ async function createServer() {
|
|
|
433
454
|
return {
|
|
434
455
|
content: [
|
|
435
456
|
{
|
|
436
|
-
type:
|
|
457
|
+
type: "text",
|
|
437
458
|
text: JSON.stringify({
|
|
438
459
|
success: true,
|
|
439
460
|
summary: result.summary,
|
|
@@ -457,10 +478,10 @@ async function createServer() {
|
|
|
457
478
|
return {
|
|
458
479
|
content: [
|
|
459
480
|
{
|
|
460
|
-
type:
|
|
481
|
+
type: "text",
|
|
461
482
|
text: JSON.stringify({
|
|
462
483
|
error: true,
|
|
463
|
-
message: `タスク分析に失敗しました: ${error instanceof Error ? error.message :
|
|
484
|
+
message: `タスク分析に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
464
485
|
}, null, 2),
|
|
465
486
|
},
|
|
466
487
|
],
|
|
@@ -471,25 +492,43 @@ async function createServer() {
|
|
|
471
492
|
* set_reminder - Set a reminder for a task
|
|
472
493
|
* Requirement: 5.1-5.6
|
|
473
494
|
*/
|
|
474
|
-
server.tool(
|
|
475
|
-
taskTitle: z.string().describe(
|
|
476
|
-
dueDate: z
|
|
495
|
+
server.tool("set_reminder", "Set a reminder for a task in Apple Reminders or Notion.", {
|
|
496
|
+
taskTitle: z.string().describe("Title of the task"),
|
|
497
|
+
dueDate: z
|
|
498
|
+
.string()
|
|
499
|
+
.optional()
|
|
500
|
+
.describe("Due date for the reminder (ISO 8601 format)"),
|
|
477
501
|
reminderType: z
|
|
478
|
-
.enum([
|
|
502
|
+
.enum([
|
|
503
|
+
"1_hour_before",
|
|
504
|
+
"3_hours_before",
|
|
505
|
+
"1_day_before",
|
|
506
|
+
"3_days_before",
|
|
507
|
+
"1_week_before",
|
|
508
|
+
])
|
|
509
|
+
.optional()
|
|
510
|
+
.describe("Type of reminder"),
|
|
511
|
+
list: z
|
|
512
|
+
.string()
|
|
479
513
|
.optional()
|
|
480
|
-
.describe(
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
514
|
+
.describe("Reminder list name (for Apple Reminders)"),
|
|
515
|
+
priority: z
|
|
516
|
+
.enum(["P0", "P1", "P2", "P3"])
|
|
517
|
+
.optional()
|
|
518
|
+
.describe("Task priority"),
|
|
519
|
+
notes: z
|
|
520
|
+
.string()
|
|
521
|
+
.optional()
|
|
522
|
+
.describe("Additional notes for the reminder"),
|
|
484
523
|
}, async ({ taskTitle, dueDate, reminderType, list, priority, notes }) => {
|
|
485
524
|
if (!config) {
|
|
486
525
|
return {
|
|
487
526
|
content: [
|
|
488
527
|
{
|
|
489
|
-
type:
|
|
528
|
+
type: "text",
|
|
490
529
|
text: JSON.stringify({
|
|
491
530
|
error: true,
|
|
492
|
-
message:
|
|
531
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
493
532
|
}, null, 2),
|
|
494
533
|
},
|
|
495
534
|
],
|
|
@@ -513,16 +552,16 @@ async function createServer() {
|
|
|
513
552
|
return {
|
|
514
553
|
content: [
|
|
515
554
|
{
|
|
516
|
-
type:
|
|
555
|
+
type: "text",
|
|
517
556
|
text: JSON.stringify({
|
|
518
557
|
success: true,
|
|
519
|
-
destination:
|
|
520
|
-
method:
|
|
558
|
+
destination: "notion_mcp",
|
|
559
|
+
method: "delegate",
|
|
521
560
|
delegateToNotion: true,
|
|
522
561
|
notionRequest: result.notionRequest,
|
|
523
562
|
message: `Notionへの追加はClaude Codeが直接notion-create-pagesツールを使用してください。`,
|
|
524
563
|
instruction: `notion-create-pagesツールを以下のパラメータで呼び出してください:
|
|
525
|
-
- parent: { "type": "data_source_id", "data_source_id": "${result.notionRequest.databaseId.replace(/-/g,
|
|
564
|
+
- parent: { "type": "data_source_id", "data_source_id": "${result.notionRequest.databaseId.replace(/-/g, "")}" }
|
|
526
565
|
- pages: [{ "properties": ${JSON.stringify(result.notionRequest.properties)} }]`,
|
|
527
566
|
}, null, 2),
|
|
528
567
|
},
|
|
@@ -532,14 +571,14 @@ async function createServer() {
|
|
|
532
571
|
return {
|
|
533
572
|
content: [
|
|
534
573
|
{
|
|
535
|
-
type:
|
|
574
|
+
type: "text",
|
|
536
575
|
text: JSON.stringify({
|
|
537
576
|
success: true,
|
|
538
577
|
destination: result.destination,
|
|
539
578
|
method: result.method,
|
|
540
579
|
reminderId: result.reminderId,
|
|
541
580
|
reminderUrl: result.reminderUrl ?? result.pageUrl,
|
|
542
|
-
message: result.destination ===
|
|
581
|
+
message: result.destination === "apple_reminders"
|
|
543
582
|
? `Apple Remindersにリマインダーを作成しました: ${taskTitle}`
|
|
544
583
|
: `Notionにタスクを作成しました: ${taskTitle}`,
|
|
545
584
|
}, null, 2),
|
|
@@ -550,14 +589,14 @@ async function createServer() {
|
|
|
550
589
|
return {
|
|
551
590
|
content: [
|
|
552
591
|
{
|
|
553
|
-
type:
|
|
592
|
+
type: "text",
|
|
554
593
|
text: JSON.stringify({
|
|
555
594
|
success: false,
|
|
556
595
|
destination: result.destination,
|
|
557
596
|
error: result.error,
|
|
558
597
|
fallbackText: result.fallbackText,
|
|
559
598
|
message: result.fallbackText
|
|
560
|
-
?
|
|
599
|
+
? "自動作成に失敗しました。以下のテキストを手動でコピーしてください。"
|
|
561
600
|
: `リマインダー作成に失敗しました: ${result.error}`,
|
|
562
601
|
}, null, 2),
|
|
563
602
|
},
|
|
@@ -568,10 +607,10 @@ async function createServer() {
|
|
|
568
607
|
return {
|
|
569
608
|
content: [
|
|
570
609
|
{
|
|
571
|
-
type:
|
|
610
|
+
type: "text",
|
|
572
611
|
text: JSON.stringify({
|
|
573
612
|
error: true,
|
|
574
|
-
message: `リマインダー設定に失敗しました: ${error instanceof Error ? error.message :
|
|
613
|
+
message: `リマインダー設定に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
575
614
|
}, null, 2),
|
|
576
615
|
},
|
|
577
616
|
],
|
|
@@ -582,20 +621,29 @@ async function createServer() {
|
|
|
582
621
|
* find_available_slots - Find available time slots in calendar
|
|
583
622
|
* Requirement: 3.3-3.6, 6.1-6.6
|
|
584
623
|
*/
|
|
585
|
-
server.tool(
|
|
586
|
-
durationMinutes: z.number().describe(
|
|
587
|
-
startDate: z
|
|
588
|
-
|
|
589
|
-
|
|
624
|
+
server.tool("find_available_slots", "Find available time slots in the calendar for scheduling tasks.", {
|
|
625
|
+
durationMinutes: z.number().describe("Required duration in minutes"),
|
|
626
|
+
startDate: z
|
|
627
|
+
.string()
|
|
628
|
+
.optional()
|
|
629
|
+
.describe("Start date for search (ISO 8601 format)"),
|
|
630
|
+
endDate: z
|
|
631
|
+
.string()
|
|
632
|
+
.optional()
|
|
633
|
+
.describe("End date for search (ISO 8601 format)"),
|
|
634
|
+
preferDeepWork: z
|
|
635
|
+
.boolean()
|
|
636
|
+
.optional()
|
|
637
|
+
.describe("Prefer deep work time slots"),
|
|
590
638
|
}, async ({ durationMinutes, startDate, endDate, preferDeepWork }) => {
|
|
591
639
|
if (!config) {
|
|
592
640
|
return {
|
|
593
641
|
content: [
|
|
594
642
|
{
|
|
595
|
-
type:
|
|
643
|
+
type: "text",
|
|
596
644
|
text: JSON.stringify({
|
|
597
645
|
error: true,
|
|
598
|
-
message:
|
|
646
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
599
647
|
}, null, 2),
|
|
600
648
|
},
|
|
601
649
|
],
|
|
@@ -610,16 +658,19 @@ async function createServer() {
|
|
|
610
658
|
const isAvailable = await calendarService.isAvailable();
|
|
611
659
|
if (!isAvailable) {
|
|
612
660
|
// Return manual input prompt for unsupported platforms
|
|
613
|
-
const manualPrompt = calendarService.generateManualInputPrompt(startDate ?? new Date().toISOString().split(
|
|
661
|
+
const manualPrompt = calendarService.generateManualInputPrompt(startDate ?? new Date().toISOString().split("T")[0], endDate ??
|
|
662
|
+
new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
|
|
663
|
+
.toISOString()
|
|
664
|
+
.split("T")[0]);
|
|
614
665
|
return {
|
|
615
666
|
content: [
|
|
616
667
|
{
|
|
617
|
-
type:
|
|
668
|
+
type: "text",
|
|
618
669
|
text: JSON.stringify({
|
|
619
670
|
success: false,
|
|
620
671
|
platform: platformInfo.platform,
|
|
621
672
|
method: platformInfo.recommendedMethod,
|
|
622
|
-
message:
|
|
673
|
+
message: "カレンダー統合がこのプラットフォームで利用できません。手動で予定を入力してください。",
|
|
623
674
|
manualPrompt,
|
|
624
675
|
}, null, 2),
|
|
625
676
|
},
|
|
@@ -627,8 +678,11 @@ async function createServer() {
|
|
|
627
678
|
};
|
|
628
679
|
}
|
|
629
680
|
// Fetch events from calendar
|
|
630
|
-
const searchStart = startDate ?? new Date().toISOString().split(
|
|
631
|
-
const searchEnd = endDate ??
|
|
681
|
+
const searchStart = startDate ?? new Date().toISOString().split("T")[0];
|
|
682
|
+
const searchEnd = endDate ??
|
|
683
|
+
new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
|
|
684
|
+
.toISOString()
|
|
685
|
+
.split("T")[0];
|
|
632
686
|
const events = await calendarService.fetchEvents(searchStart, searchEnd);
|
|
633
687
|
// Find available slots
|
|
634
688
|
const workingHours = {
|
|
@@ -644,7 +698,7 @@ async function createServer() {
|
|
|
644
698
|
const scoredSlots = slots.map((slot) => calendarService.calculateSuitability(slot, suitabilityConfig));
|
|
645
699
|
// Filter for deep work preference if requested
|
|
646
700
|
const filteredSlots = preferDeepWork
|
|
647
|
-
? scoredSlots.filter((s) => s.dayType ===
|
|
701
|
+
? scoredSlots.filter((s) => s.dayType === "deep-work")
|
|
648
702
|
: scoredSlots;
|
|
649
703
|
// Sort by suitability (excellent > good > acceptable)
|
|
650
704
|
const suitabilityOrder = { excellent: 0, good: 1, acceptable: 2 };
|
|
@@ -652,7 +706,7 @@ async function createServer() {
|
|
|
652
706
|
return {
|
|
653
707
|
content: [
|
|
654
708
|
{
|
|
655
|
-
type:
|
|
709
|
+
type: "text",
|
|
656
710
|
text: JSON.stringify({
|
|
657
711
|
success: true,
|
|
658
712
|
platform: platformInfo.platform,
|
|
@@ -669,7 +723,7 @@ async function createServer() {
|
|
|
669
723
|
})),
|
|
670
724
|
message: filteredSlots.length > 0
|
|
671
725
|
? `${filteredSlots.length}件の空き時間が見つかりました。`
|
|
672
|
-
:
|
|
726
|
+
: "指定した条件に合う空き時間が見つかりませんでした。",
|
|
673
727
|
}, null, 2),
|
|
674
728
|
},
|
|
675
729
|
],
|
|
@@ -679,10 +733,586 @@ async function createServer() {
|
|
|
679
733
|
return {
|
|
680
734
|
content: [
|
|
681
735
|
{
|
|
682
|
-
type:
|
|
736
|
+
type: "text",
|
|
683
737
|
text: JSON.stringify({
|
|
684
738
|
error: true,
|
|
685
|
-
message: `カレンダー検索に失敗しました: ${error instanceof Error ? error.message :
|
|
739
|
+
message: `カレンダー検索に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
740
|
+
}, null, 2),
|
|
741
|
+
},
|
|
742
|
+
],
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
/**
|
|
747
|
+
* list_calendar_events - List calendar events for a specified period
|
|
748
|
+
* Requirement: 16.1-16.12
|
|
749
|
+
*/
|
|
750
|
+
server.tool("list_calendar_events", "List calendar events for a specified period. Returns events with details including calendar name and location.", {
|
|
751
|
+
startDate: z
|
|
752
|
+
.string()
|
|
753
|
+
.describe("Start date in ISO 8601 format (e.g., 2025-01-15)"),
|
|
754
|
+
endDate: z
|
|
755
|
+
.string()
|
|
756
|
+
.describe("End date in ISO 8601 format (e.g., 2025-01-20)"),
|
|
757
|
+
calendarName: z
|
|
758
|
+
.string()
|
|
759
|
+
.optional()
|
|
760
|
+
.describe("Optional: filter events by calendar name"),
|
|
761
|
+
}, async ({ startDate, endDate, calendarName }) => {
|
|
762
|
+
if (!config) {
|
|
763
|
+
return {
|
|
764
|
+
content: [
|
|
765
|
+
{
|
|
766
|
+
type: "text",
|
|
767
|
+
text: JSON.stringify({
|
|
768
|
+
error: true,
|
|
769
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
770
|
+
}, null, 2),
|
|
771
|
+
},
|
|
772
|
+
],
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
if (!calendarService) {
|
|
776
|
+
initializeServices(config);
|
|
777
|
+
}
|
|
778
|
+
try {
|
|
779
|
+
// Check platform availability
|
|
780
|
+
const platformInfo = await calendarService.detectPlatform();
|
|
781
|
+
const isAvailable = await calendarService.isAvailable();
|
|
782
|
+
if (!isAvailable) {
|
|
783
|
+
return {
|
|
784
|
+
content: [
|
|
785
|
+
{
|
|
786
|
+
type: "text",
|
|
787
|
+
text: JSON.stringify({
|
|
788
|
+
success: false,
|
|
789
|
+
platform: platformInfo.platform,
|
|
790
|
+
method: platformInfo.recommendedMethod,
|
|
791
|
+
message: "カレンダー統合がこのプラットフォームで利用できません。macOSで実行してください。",
|
|
792
|
+
}, null, 2),
|
|
793
|
+
},
|
|
794
|
+
],
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
// List events
|
|
798
|
+
const result = await calendarService.listEvents({
|
|
799
|
+
startDate,
|
|
800
|
+
endDate,
|
|
801
|
+
calendarName,
|
|
802
|
+
});
|
|
803
|
+
return {
|
|
804
|
+
content: [
|
|
805
|
+
{
|
|
806
|
+
type: "text",
|
|
807
|
+
text: JSON.stringify({
|
|
808
|
+
success: true,
|
|
809
|
+
platform: platformInfo.platform,
|
|
810
|
+
method: platformInfo.recommendedMethod,
|
|
811
|
+
events: result.events.map((event) => ({
|
|
812
|
+
id: event.id,
|
|
813
|
+
title: event.title,
|
|
814
|
+
start: event.start,
|
|
815
|
+
end: event.end,
|
|
816
|
+
isAllDay: event.isAllDay,
|
|
817
|
+
calendar: event.calendar,
|
|
818
|
+
location: event.location,
|
|
819
|
+
})),
|
|
820
|
+
period: result.period,
|
|
821
|
+
totalEvents: result.totalEvents,
|
|
822
|
+
message: result.totalEvents > 0
|
|
823
|
+
? `${result.totalEvents}件のイベントが見つかりました。`
|
|
824
|
+
: "指定した期間にイベントが見つかりませんでした。",
|
|
825
|
+
}, null, 2),
|
|
826
|
+
},
|
|
827
|
+
],
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
catch (error) {
|
|
831
|
+
return {
|
|
832
|
+
content: [
|
|
833
|
+
{
|
|
834
|
+
type: "text",
|
|
835
|
+
text: JSON.stringify({
|
|
836
|
+
error: true,
|
|
837
|
+
message: `カレンダーイベントの取得に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
838
|
+
}, null, 2),
|
|
839
|
+
},
|
|
840
|
+
],
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
/**
|
|
845
|
+
* respond_to_calendar_event - Respond to a single calendar event
|
|
846
|
+
* Requirement: 17.1, 17.2, 17.5-17.11
|
|
847
|
+
*/
|
|
848
|
+
server.tool("respond_to_calendar_event", "Respond to a calendar event with accept, decline, or tentative. Use this to RSVP to meeting invitations.", {
|
|
849
|
+
eventId: z.string().describe("The ID of the calendar event to respond to"),
|
|
850
|
+
response: z
|
|
851
|
+
.enum(["accept", "decline", "tentative"])
|
|
852
|
+
.describe("Response type: accept (承諾), decline (辞退), or tentative (仮承諾)"),
|
|
853
|
+
comment: z
|
|
854
|
+
.string()
|
|
855
|
+
.optional()
|
|
856
|
+
.describe("Optional comment to include with the response (e.g., '年末年始休暇のため')"),
|
|
857
|
+
}, async ({ eventId, response, comment }) => {
|
|
858
|
+
if (!config) {
|
|
859
|
+
return {
|
|
860
|
+
content: [
|
|
861
|
+
{
|
|
862
|
+
type: "text",
|
|
863
|
+
text: JSON.stringify({
|
|
864
|
+
error: true,
|
|
865
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
866
|
+
}, null, 2),
|
|
867
|
+
},
|
|
868
|
+
],
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
if (!calendarEventResponseService) {
|
|
872
|
+
initializeServices(config);
|
|
873
|
+
}
|
|
874
|
+
try {
|
|
875
|
+
// Check platform availability
|
|
876
|
+
const isAvailable = await calendarEventResponseService.isEventKitAvailable();
|
|
877
|
+
if (!isAvailable) {
|
|
878
|
+
return {
|
|
879
|
+
content: [
|
|
880
|
+
{
|
|
881
|
+
type: "text",
|
|
882
|
+
text: JSON.stringify({
|
|
883
|
+
success: false,
|
|
884
|
+
message: "カレンダーイベント返信機能はmacOSでのみ利用可能です。",
|
|
885
|
+
}, null, 2),
|
|
886
|
+
},
|
|
887
|
+
],
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
// Respond to the event
|
|
891
|
+
const result = await calendarEventResponseService.respondToEvent({
|
|
892
|
+
eventId,
|
|
893
|
+
response,
|
|
894
|
+
comment,
|
|
895
|
+
});
|
|
896
|
+
if (result.success) {
|
|
897
|
+
return {
|
|
898
|
+
content: [
|
|
899
|
+
{
|
|
900
|
+
type: "text",
|
|
901
|
+
text: JSON.stringify({
|
|
902
|
+
success: true,
|
|
903
|
+
eventId: result.eventId,
|
|
904
|
+
eventTitle: result.eventTitle,
|
|
905
|
+
newStatus: result.newStatus,
|
|
906
|
+
method: result.method,
|
|
907
|
+
instanceOnly: result.instanceOnly,
|
|
908
|
+
message: result.message,
|
|
909
|
+
}, null, 2),
|
|
910
|
+
},
|
|
911
|
+
],
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
// Handle skipped or failed response
|
|
915
|
+
return {
|
|
916
|
+
content: [
|
|
917
|
+
{
|
|
918
|
+
type: "text",
|
|
919
|
+
text: JSON.stringify({
|
|
920
|
+
success: false,
|
|
921
|
+
eventId: result.eventId,
|
|
922
|
+
eventTitle: result.eventTitle,
|
|
923
|
+
skipped: result.skipped,
|
|
924
|
+
reason: result.reason,
|
|
925
|
+
error: result.error,
|
|
926
|
+
message: result.skipped
|
|
927
|
+
? `イベントをスキップしました: ${result.reason}`
|
|
928
|
+
: `イベント返信に失敗しました: ${result.error}`,
|
|
929
|
+
}, null, 2),
|
|
930
|
+
},
|
|
931
|
+
],
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
return {
|
|
936
|
+
content: [
|
|
937
|
+
{
|
|
938
|
+
type: "text",
|
|
939
|
+
text: JSON.stringify({
|
|
940
|
+
error: true,
|
|
941
|
+
message: `カレンダーイベント返信に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
942
|
+
}, null, 2),
|
|
943
|
+
},
|
|
944
|
+
],
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
/**
|
|
949
|
+
* respond_to_calendar_events_batch - Respond to multiple calendar events
|
|
950
|
+
* Requirement: 17.3, 17.4, 17.12
|
|
951
|
+
*/
|
|
952
|
+
server.tool("respond_to_calendar_events_batch", "Respond to multiple calendar events at once. Useful for declining all events during vacation or leave periods.", {
|
|
953
|
+
eventIds: z
|
|
954
|
+
.array(z.string())
|
|
955
|
+
.describe("Array of event IDs to respond to"),
|
|
956
|
+
response: z
|
|
957
|
+
.enum(["accept", "decline", "tentative"])
|
|
958
|
+
.describe("Response type: accept (承諾), decline (辞退), or tentative (仮承諾)"),
|
|
959
|
+
comment: z
|
|
960
|
+
.string()
|
|
961
|
+
.optional()
|
|
962
|
+
.describe("Optional comment to include with all responses (e.g., '年末年始休暇のため')"),
|
|
963
|
+
}, async ({ eventIds, response, comment }) => {
|
|
964
|
+
if (!config) {
|
|
965
|
+
return {
|
|
966
|
+
content: [
|
|
967
|
+
{
|
|
968
|
+
type: "text",
|
|
969
|
+
text: JSON.stringify({
|
|
970
|
+
error: true,
|
|
971
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
972
|
+
}, null, 2),
|
|
973
|
+
},
|
|
974
|
+
],
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if (!calendarEventResponseService) {
|
|
978
|
+
initializeServices(config);
|
|
979
|
+
}
|
|
980
|
+
try {
|
|
981
|
+
// Check platform availability
|
|
982
|
+
const isAvailable = await calendarEventResponseService.isEventKitAvailable();
|
|
983
|
+
if (!isAvailable) {
|
|
984
|
+
return {
|
|
985
|
+
content: [
|
|
986
|
+
{
|
|
987
|
+
type: "text",
|
|
988
|
+
text: JSON.stringify({
|
|
989
|
+
success: false,
|
|
990
|
+
message: "カレンダーイベント返信機能はmacOSでのみ利用可能です。",
|
|
991
|
+
}, null, 2),
|
|
992
|
+
},
|
|
993
|
+
],
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
// Respond to all events in batch
|
|
997
|
+
const result = await calendarEventResponseService.respondToEventsBatch({
|
|
998
|
+
eventIds,
|
|
999
|
+
response,
|
|
1000
|
+
comment,
|
|
1001
|
+
});
|
|
1002
|
+
return {
|
|
1003
|
+
content: [
|
|
1004
|
+
{
|
|
1005
|
+
type: "text",
|
|
1006
|
+
text: JSON.stringify({
|
|
1007
|
+
success: result.success,
|
|
1008
|
+
summary: result.summary,
|
|
1009
|
+
details: {
|
|
1010
|
+
succeeded: result.details.succeeded,
|
|
1011
|
+
skipped: result.details.skipped,
|
|
1012
|
+
failed: result.details.failed,
|
|
1013
|
+
},
|
|
1014
|
+
message: result.message,
|
|
1015
|
+
}, null, 2),
|
|
1016
|
+
},
|
|
1017
|
+
],
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
catch (error) {
|
|
1021
|
+
return {
|
|
1022
|
+
content: [
|
|
1023
|
+
{
|
|
1024
|
+
type: "text",
|
|
1025
|
+
text: JSON.stringify({
|
|
1026
|
+
error: true,
|
|
1027
|
+
message: `カレンダーイベント一括返信に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1028
|
+
}, null, 2),
|
|
1029
|
+
},
|
|
1030
|
+
],
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
/**
|
|
1035
|
+
* create_calendar_event - Create a new calendar event
|
|
1036
|
+
* Requirement: 18.1-18.11
|
|
1037
|
+
*/
|
|
1038
|
+
server.tool("create_calendar_event", "Create a new calendar event with optional location, notes, and alarms.", {
|
|
1039
|
+
title: z.string().describe("Event title"),
|
|
1040
|
+
startDate: z
|
|
1041
|
+
.string()
|
|
1042
|
+
.describe("Start date/time in ISO 8601 format (e.g., 2025-01-15T10:00:00+09:00)"),
|
|
1043
|
+
endDate: z
|
|
1044
|
+
.string()
|
|
1045
|
+
.describe("End date/time in ISO 8601 format (e.g., 2025-01-15T11:00:00+09:00)"),
|
|
1046
|
+
location: z.string().optional().describe("Event location"),
|
|
1047
|
+
notes: z.string().optional().describe("Event notes/description"),
|
|
1048
|
+
calendarName: z
|
|
1049
|
+
.string()
|
|
1050
|
+
.optional()
|
|
1051
|
+
.describe("Calendar name to create the event in (uses default if not specified)"),
|
|
1052
|
+
alarms: z
|
|
1053
|
+
.array(z.string())
|
|
1054
|
+
.optional()
|
|
1055
|
+
.describe("Optional: Override default alarms with custom settings (e.g., ['-15m', '-1h']). If omitted, calendar's default alarm settings apply."),
|
|
1056
|
+
}, async ({ title, startDate, endDate, location, notes, calendarName, alarms }) => {
|
|
1057
|
+
if (!config) {
|
|
1058
|
+
return {
|
|
1059
|
+
content: [
|
|
1060
|
+
{
|
|
1061
|
+
type: "text",
|
|
1062
|
+
text: JSON.stringify({
|
|
1063
|
+
error: true,
|
|
1064
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
1065
|
+
}, null, 2),
|
|
1066
|
+
},
|
|
1067
|
+
],
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
if (!calendarEventCreatorService) {
|
|
1071
|
+
initializeServices(config);
|
|
1072
|
+
}
|
|
1073
|
+
try {
|
|
1074
|
+
// Check platform availability
|
|
1075
|
+
const isAvailable = await calendarEventCreatorService.isEventKitAvailable();
|
|
1076
|
+
if (!isAvailable) {
|
|
1077
|
+
return {
|
|
1078
|
+
content: [
|
|
1079
|
+
{
|
|
1080
|
+
type: "text",
|
|
1081
|
+
text: JSON.stringify({
|
|
1082
|
+
success: false,
|
|
1083
|
+
message: "カレンダーイベント作成機能はmacOSでのみ利用可能です。",
|
|
1084
|
+
}, null, 2),
|
|
1085
|
+
},
|
|
1086
|
+
],
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
// Create the event
|
|
1090
|
+
const result = await calendarEventCreatorService.createEvent({
|
|
1091
|
+
title,
|
|
1092
|
+
startDate,
|
|
1093
|
+
endDate,
|
|
1094
|
+
location,
|
|
1095
|
+
notes,
|
|
1096
|
+
calendarName,
|
|
1097
|
+
alarms,
|
|
1098
|
+
});
|
|
1099
|
+
if (result.success) {
|
|
1100
|
+
return {
|
|
1101
|
+
content: [
|
|
1102
|
+
{
|
|
1103
|
+
type: "text",
|
|
1104
|
+
text: JSON.stringify({
|
|
1105
|
+
success: true,
|
|
1106
|
+
eventId: result.eventId,
|
|
1107
|
+
title: result.title,
|
|
1108
|
+
startDate: result.startDate,
|
|
1109
|
+
endDate: result.endDate,
|
|
1110
|
+
calendarName: result.calendarName,
|
|
1111
|
+
isAllDay: result.isAllDay,
|
|
1112
|
+
message: result.message,
|
|
1113
|
+
}, null, 2),
|
|
1114
|
+
},
|
|
1115
|
+
],
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
// Handle creation failure
|
|
1119
|
+
return {
|
|
1120
|
+
content: [
|
|
1121
|
+
{
|
|
1122
|
+
type: "text",
|
|
1123
|
+
text: JSON.stringify({
|
|
1124
|
+
success: false,
|
|
1125
|
+
error: result.error,
|
|
1126
|
+
message: result.message,
|
|
1127
|
+
}, null, 2),
|
|
1128
|
+
},
|
|
1129
|
+
],
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
catch (error) {
|
|
1133
|
+
return {
|
|
1134
|
+
content: [
|
|
1135
|
+
{
|
|
1136
|
+
type: "text",
|
|
1137
|
+
text: JSON.stringify({
|
|
1138
|
+
error: true,
|
|
1139
|
+
message: `カレンダーイベント作成に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1140
|
+
}, null, 2),
|
|
1141
|
+
},
|
|
1142
|
+
],
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
/**
|
|
1147
|
+
* delete_calendar_event - Delete a calendar event
|
|
1148
|
+
* Requirement: 19.1-19.9
|
|
1149
|
+
*/
|
|
1150
|
+
server.tool("delete_calendar_event", "Delete a calendar event by its ID.", {
|
|
1151
|
+
eventId: z.string().describe("Event ID (UUID or full ID from list_calendar_events)"),
|
|
1152
|
+
calendarName: z
|
|
1153
|
+
.string()
|
|
1154
|
+
.optional()
|
|
1155
|
+
.describe("Calendar name (searches all calendars if not specified)"),
|
|
1156
|
+
}, async ({ eventId, calendarName }) => {
|
|
1157
|
+
if (!config) {
|
|
1158
|
+
return {
|
|
1159
|
+
content: [
|
|
1160
|
+
{
|
|
1161
|
+
type: "text",
|
|
1162
|
+
text: JSON.stringify({
|
|
1163
|
+
error: true,
|
|
1164
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
1165
|
+
}, null, 2),
|
|
1166
|
+
},
|
|
1167
|
+
],
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
if (!calendarEventDeleterService) {
|
|
1171
|
+
initializeServices(config);
|
|
1172
|
+
}
|
|
1173
|
+
try {
|
|
1174
|
+
// Check platform availability
|
|
1175
|
+
const isAvailable = await calendarEventDeleterService.isEventKitAvailable();
|
|
1176
|
+
if (!isAvailable) {
|
|
1177
|
+
return {
|
|
1178
|
+
content: [
|
|
1179
|
+
{
|
|
1180
|
+
type: "text",
|
|
1181
|
+
text: JSON.stringify({
|
|
1182
|
+
error: true,
|
|
1183
|
+
message: "カレンダー統合がこのプラットフォームで利用できません。macOSで実行してください。",
|
|
1184
|
+
}, null, 2),
|
|
1185
|
+
},
|
|
1186
|
+
],
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
// Delete the event
|
|
1190
|
+
const result = await calendarEventDeleterService.deleteEvent({
|
|
1191
|
+
eventId,
|
|
1192
|
+
calendarName,
|
|
1193
|
+
});
|
|
1194
|
+
if (result.success) {
|
|
1195
|
+
return {
|
|
1196
|
+
content: [
|
|
1197
|
+
{
|
|
1198
|
+
type: "text",
|
|
1199
|
+
text: JSON.stringify({
|
|
1200
|
+
success: true,
|
|
1201
|
+
eventId: result.eventId,
|
|
1202
|
+
title: result.title,
|
|
1203
|
+
calendarName: result.calendarName,
|
|
1204
|
+
message: result.message,
|
|
1205
|
+
}, null, 2),
|
|
1206
|
+
},
|
|
1207
|
+
],
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
// Handle deletion failure
|
|
1211
|
+
return {
|
|
1212
|
+
content: [
|
|
1213
|
+
{
|
|
1214
|
+
type: "text",
|
|
1215
|
+
text: JSON.stringify({
|
|
1216
|
+
success: false,
|
|
1217
|
+
error: result.error,
|
|
1218
|
+
message: result.message,
|
|
1219
|
+
}, null, 2),
|
|
1220
|
+
},
|
|
1221
|
+
],
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
catch (error) {
|
|
1225
|
+
return {
|
|
1226
|
+
content: [
|
|
1227
|
+
{
|
|
1228
|
+
type: "text",
|
|
1229
|
+
text: JSON.stringify({
|
|
1230
|
+
error: true,
|
|
1231
|
+
message: `カレンダーイベント削除に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1232
|
+
}, null, 2),
|
|
1233
|
+
},
|
|
1234
|
+
],
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
/**
|
|
1239
|
+
* delete_calendar_events_batch - Delete multiple calendar events
|
|
1240
|
+
* Requirement: 19.10-19.11
|
|
1241
|
+
*/
|
|
1242
|
+
server.tool("delete_calendar_events_batch", "Delete multiple calendar events by their IDs.", {
|
|
1243
|
+
eventIds: z.array(z.string()).describe("Array of event IDs to delete"),
|
|
1244
|
+
calendarName: z
|
|
1245
|
+
.string()
|
|
1246
|
+
.optional()
|
|
1247
|
+
.describe("Calendar name (searches all calendars if not specified)"),
|
|
1248
|
+
}, async ({ eventIds, calendarName }) => {
|
|
1249
|
+
if (!config) {
|
|
1250
|
+
return {
|
|
1251
|
+
content: [
|
|
1252
|
+
{
|
|
1253
|
+
type: "text",
|
|
1254
|
+
text: JSON.stringify({
|
|
1255
|
+
error: true,
|
|
1256
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
1257
|
+
}, null, 2),
|
|
1258
|
+
},
|
|
1259
|
+
],
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
if (!calendarEventDeleterService) {
|
|
1263
|
+
initializeServices(config);
|
|
1264
|
+
}
|
|
1265
|
+
try {
|
|
1266
|
+
// Check platform availability
|
|
1267
|
+
const isAvailable = await calendarEventDeleterService.isEventKitAvailable();
|
|
1268
|
+
if (!isAvailable) {
|
|
1269
|
+
return {
|
|
1270
|
+
content: [
|
|
1271
|
+
{
|
|
1272
|
+
type: "text",
|
|
1273
|
+
text: JSON.stringify({
|
|
1274
|
+
error: true,
|
|
1275
|
+
message: "カレンダー統合がこのプラットフォームで利用できません。macOSで実行してください。",
|
|
1276
|
+
}, null, 2),
|
|
1277
|
+
},
|
|
1278
|
+
],
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
// Delete events in batch
|
|
1282
|
+
const result = await calendarEventDeleterService.deleteEventsBatch({
|
|
1283
|
+
eventIds,
|
|
1284
|
+
calendarName,
|
|
1285
|
+
});
|
|
1286
|
+
return {
|
|
1287
|
+
content: [
|
|
1288
|
+
{
|
|
1289
|
+
type: "text",
|
|
1290
|
+
text: JSON.stringify({
|
|
1291
|
+
success: result.success,
|
|
1292
|
+
totalCount: result.totalCount,
|
|
1293
|
+
successCount: result.successCount,
|
|
1294
|
+
failedCount: result.failedCount,
|
|
1295
|
+
results: result.results.map((r) => ({
|
|
1296
|
+
eventId: r.eventId,
|
|
1297
|
+
success: r.success,
|
|
1298
|
+
title: r.title,
|
|
1299
|
+
calendarName: r.calendarName,
|
|
1300
|
+
error: r.error,
|
|
1301
|
+
})),
|
|
1302
|
+
message: result.message,
|
|
1303
|
+
}, null, 2),
|
|
1304
|
+
},
|
|
1305
|
+
],
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
catch (error) {
|
|
1309
|
+
return {
|
|
1310
|
+
content: [
|
|
1311
|
+
{
|
|
1312
|
+
type: "text",
|
|
1313
|
+
text: JSON.stringify({
|
|
1314
|
+
error: true,
|
|
1315
|
+
message: `カレンダーイベント一括削除に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
686
1316
|
}, null, 2),
|
|
687
1317
|
},
|
|
688
1318
|
],
|
|
@@ -693,22 +1323,31 @@ async function createServer() {
|
|
|
693
1323
|
* sync_to_notion - Sync a task to Notion
|
|
694
1324
|
* Requirement: 8.1-8.5
|
|
695
1325
|
*/
|
|
696
|
-
server.tool(
|
|
697
|
-
taskTitle: z.string().describe(
|
|
698
|
-
description: z.string().optional().describe(
|
|
699
|
-
priority: z
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
1326
|
+
server.tool("sync_to_notion", "Sync a task to Notion database for long-term tracking.", {
|
|
1327
|
+
taskTitle: z.string().describe("Title of the task"),
|
|
1328
|
+
description: z.string().optional().describe("Task description"),
|
|
1329
|
+
priority: z
|
|
1330
|
+
.enum(["P0", "P1", "P2", "P3"])
|
|
1331
|
+
.optional()
|
|
1332
|
+
.describe("Task priority"),
|
|
1333
|
+
dueDate: z.string().optional().describe("Due date (ISO 8601 format)"),
|
|
1334
|
+
stakeholders: z
|
|
1335
|
+
.array(z.string())
|
|
1336
|
+
.optional()
|
|
1337
|
+
.describe("List of stakeholders"),
|
|
1338
|
+
estimatedMinutes: z
|
|
1339
|
+
.number()
|
|
1340
|
+
.optional()
|
|
1341
|
+
.describe("Estimated duration in minutes"),
|
|
1342
|
+
}, async ({ taskTitle, description, priority, dueDate, stakeholders, estimatedMinutes, }) => {
|
|
704
1343
|
if (!config) {
|
|
705
1344
|
return {
|
|
706
1345
|
content: [
|
|
707
1346
|
{
|
|
708
|
-
type:
|
|
1347
|
+
type: "text",
|
|
709
1348
|
text: JSON.stringify({
|
|
710
1349
|
error: true,
|
|
711
|
-
message:
|
|
1350
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
712
1351
|
}, null, 2),
|
|
713
1352
|
},
|
|
714
1353
|
],
|
|
@@ -718,10 +1357,10 @@ async function createServer() {
|
|
|
718
1357
|
return {
|
|
719
1358
|
content: [
|
|
720
1359
|
{
|
|
721
|
-
type:
|
|
1360
|
+
type: "text",
|
|
722
1361
|
text: JSON.stringify({
|
|
723
1362
|
error: true,
|
|
724
|
-
message:
|
|
1363
|
+
message: "Notion統合が有効になっていません。update_configでNotion設定を更新してください。",
|
|
725
1364
|
}, null, 2),
|
|
726
1365
|
},
|
|
727
1366
|
],
|
|
@@ -755,15 +1394,15 @@ async function createServer() {
|
|
|
755
1394
|
return {
|
|
756
1395
|
content: [
|
|
757
1396
|
{
|
|
758
|
-
type:
|
|
1397
|
+
type: "text",
|
|
759
1398
|
text: JSON.stringify({
|
|
760
1399
|
success: false,
|
|
761
|
-
method:
|
|
762
|
-
message:
|
|
1400
|
+
method: "fallback",
|
|
1401
|
+
message: "Notion MCP統合が利用できません。以下のテンプレートを手動でNotionにコピーしてください。",
|
|
763
1402
|
fallbackText,
|
|
764
1403
|
task: {
|
|
765
1404
|
taskTitle,
|
|
766
|
-
priority: priority ??
|
|
1405
|
+
priority: priority ?? "P3",
|
|
767
1406
|
dueDate,
|
|
768
1407
|
stakeholders: stakeholders ?? [],
|
|
769
1408
|
estimatedMinutes,
|
|
@@ -783,10 +1422,10 @@ async function createServer() {
|
|
|
783
1422
|
return {
|
|
784
1423
|
content: [
|
|
785
1424
|
{
|
|
786
|
-
type:
|
|
1425
|
+
type: "text",
|
|
787
1426
|
text: JSON.stringify({
|
|
788
1427
|
success: true,
|
|
789
|
-
method:
|
|
1428
|
+
method: "mcp",
|
|
790
1429
|
pageId: result.pageId,
|
|
791
1430
|
pageUrl: result.pageUrl,
|
|
792
1431
|
message: `Notionにタスクを同期しました: ${taskTitle}`,
|
|
@@ -807,12 +1446,12 @@ async function createServer() {
|
|
|
807
1446
|
return {
|
|
808
1447
|
content: [
|
|
809
1448
|
{
|
|
810
|
-
type:
|
|
1449
|
+
type: "text",
|
|
811
1450
|
text: JSON.stringify({
|
|
812
1451
|
success: false,
|
|
813
|
-
method:
|
|
1452
|
+
method: "fallback",
|
|
814
1453
|
error: result.error,
|
|
815
|
-
message:
|
|
1454
|
+
message: "Notion MCP呼び出しに失敗しました。以下のテンプレートを手動でコピーしてください。",
|
|
816
1455
|
fallbackText,
|
|
817
1456
|
}, null, 2),
|
|
818
1457
|
},
|
|
@@ -823,10 +1462,10 @@ async function createServer() {
|
|
|
823
1462
|
return {
|
|
824
1463
|
content: [
|
|
825
1464
|
{
|
|
826
|
-
type:
|
|
1465
|
+
type: "text",
|
|
827
1466
|
text: JSON.stringify({
|
|
828
1467
|
error: true,
|
|
829
|
-
message: `Notion同期に失敗しました: ${error instanceof Error ? error.message :
|
|
1468
|
+
message: `Notion同期に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
830
1469
|
}, null, 2),
|
|
831
1470
|
},
|
|
832
1471
|
],
|
|
@@ -837,20 +1476,27 @@ async function createServer() {
|
|
|
837
1476
|
* update_config - Update configuration
|
|
838
1477
|
* Requirement: 10.1-10.6
|
|
839
1478
|
*/
|
|
840
|
-
server.tool(
|
|
1479
|
+
server.tool("update_config", "Update sage configuration settings.", {
|
|
841
1480
|
section: z
|
|
842
|
-
.enum([
|
|
843
|
-
|
|
844
|
-
|
|
1481
|
+
.enum([
|
|
1482
|
+
"user",
|
|
1483
|
+
"calendar",
|
|
1484
|
+
"priorityRules",
|
|
1485
|
+
"integrations",
|
|
1486
|
+
"team",
|
|
1487
|
+
"preferences",
|
|
1488
|
+
])
|
|
1489
|
+
.describe("Configuration section to update"),
|
|
1490
|
+
updates: z.record(z.unknown()).describe("Key-value pairs to update"),
|
|
845
1491
|
}, async ({ section, updates }) => {
|
|
846
1492
|
if (!config) {
|
|
847
1493
|
return {
|
|
848
1494
|
content: [
|
|
849
1495
|
{
|
|
850
|
-
type:
|
|
1496
|
+
type: "text",
|
|
851
1497
|
text: JSON.stringify({
|
|
852
1498
|
error: true,
|
|
853
|
-
message:
|
|
1499
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
854
1500
|
}, null, 2),
|
|
855
1501
|
},
|
|
856
1502
|
],
|
|
@@ -863,7 +1509,7 @@ async function createServer() {
|
|
|
863
1509
|
return {
|
|
864
1510
|
content: [
|
|
865
1511
|
{
|
|
866
|
-
type:
|
|
1512
|
+
type: "text",
|
|
867
1513
|
text: JSON.stringify({
|
|
868
1514
|
error: true,
|
|
869
1515
|
message: `設定の検証に失敗しました: ${validationResult.error}`,
|
|
@@ -879,13 +1525,13 @@ async function createServer() {
|
|
|
879
1525
|
await ConfigLoader.save(updatedConfig);
|
|
880
1526
|
config = updatedConfig;
|
|
881
1527
|
// Re-initialize services if integrations changed
|
|
882
|
-
if (section ===
|
|
1528
|
+
if (section === "integrations") {
|
|
883
1529
|
initializeServices(config);
|
|
884
1530
|
}
|
|
885
1531
|
return {
|
|
886
1532
|
content: [
|
|
887
1533
|
{
|
|
888
|
-
type:
|
|
1534
|
+
type: "text",
|
|
889
1535
|
text: JSON.stringify({
|
|
890
1536
|
success: true,
|
|
891
1537
|
section,
|
|
@@ -900,10 +1546,10 @@ async function createServer() {
|
|
|
900
1546
|
return {
|
|
901
1547
|
content: [
|
|
902
1548
|
{
|
|
903
|
-
type:
|
|
1549
|
+
type: "text",
|
|
904
1550
|
text: JSON.stringify({
|
|
905
1551
|
error: true,
|
|
906
|
-
message: `設定の更新に失敗しました: ${error instanceof Error ? error.message :
|
|
1552
|
+
message: `設定の更新に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
907
1553
|
}, null, 2),
|
|
908
1554
|
},
|
|
909
1555
|
],
|
|
@@ -917,30 +1563,30 @@ async function createServer() {
|
|
|
917
1563
|
* list_todos - List all TODO items with optional filtering
|
|
918
1564
|
* Requirement: 12.1, 12.2, 12.3, 12.4, 12.7, 12.8
|
|
919
1565
|
*/
|
|
920
|
-
server.tool(
|
|
1566
|
+
server.tool("list_todos", "List TODO items from Apple Reminders and Notion with optional filtering.", {
|
|
921
1567
|
priority: z
|
|
922
|
-
.array(z.enum([
|
|
1568
|
+
.array(z.enum(["P0", "P1", "P2", "P3"]))
|
|
923
1569
|
.optional()
|
|
924
|
-
.describe(
|
|
1570
|
+
.describe("Filter by priority levels"),
|
|
925
1571
|
status: z
|
|
926
|
-
.array(z.enum([
|
|
1572
|
+
.array(z.enum(["not_started", "in_progress", "completed", "cancelled"]))
|
|
927
1573
|
.optional()
|
|
928
|
-
.describe(
|
|
1574
|
+
.describe("Filter by status"),
|
|
929
1575
|
source: z
|
|
930
|
-
.array(z.enum([
|
|
1576
|
+
.array(z.enum(["apple_reminders", "notion", "manual"]))
|
|
931
1577
|
.optional()
|
|
932
|
-
.describe(
|
|
933
|
-
todayOnly: z.boolean().optional().describe(
|
|
934
|
-
tags: z.array(z.string()).optional().describe(
|
|
1578
|
+
.describe("Filter by source"),
|
|
1579
|
+
todayOnly: z.boolean().optional().describe("Show only tasks due today"),
|
|
1580
|
+
tags: z.array(z.string()).optional().describe("Filter by tags"),
|
|
935
1581
|
}, async ({ priority, status, source, todayOnly, tags }) => {
|
|
936
1582
|
if (!config) {
|
|
937
1583
|
return {
|
|
938
1584
|
content: [
|
|
939
1585
|
{
|
|
940
|
-
type:
|
|
1586
|
+
type: "text",
|
|
941
1587
|
text: JSON.stringify({
|
|
942
1588
|
error: true,
|
|
943
|
-
message:
|
|
1589
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
944
1590
|
}, null, 2),
|
|
945
1591
|
},
|
|
946
1592
|
],
|
|
@@ -977,14 +1623,14 @@ async function createServer() {
|
|
|
977
1623
|
return {
|
|
978
1624
|
content: [
|
|
979
1625
|
{
|
|
980
|
-
type:
|
|
1626
|
+
type: "text",
|
|
981
1627
|
text: JSON.stringify({
|
|
982
1628
|
success: true,
|
|
983
1629
|
totalCount: todos.length,
|
|
984
1630
|
todos: formattedTodos,
|
|
985
1631
|
message: todos.length > 0
|
|
986
1632
|
? `${todos.length}件のタスクが見つかりました。`
|
|
987
|
-
:
|
|
1633
|
+
: "タスクが見つかりませんでした。",
|
|
988
1634
|
filters: {
|
|
989
1635
|
priority,
|
|
990
1636
|
status,
|
|
@@ -1001,10 +1647,10 @@ async function createServer() {
|
|
|
1001
1647
|
return {
|
|
1002
1648
|
content: [
|
|
1003
1649
|
{
|
|
1004
|
-
type:
|
|
1650
|
+
type: "text",
|
|
1005
1651
|
text: JSON.stringify({
|
|
1006
1652
|
error: true,
|
|
1007
|
-
message: `TODOリストの取得に失敗しました: ${error instanceof Error ? error.message :
|
|
1653
|
+
message: `TODOリストの取得に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1008
1654
|
}, null, 2),
|
|
1009
1655
|
},
|
|
1010
1656
|
],
|
|
@@ -1015,27 +1661,27 @@ async function createServer() {
|
|
|
1015
1661
|
* update_task_status - Update the status of a task
|
|
1016
1662
|
* Requirement: 12.5, 12.6
|
|
1017
1663
|
*/
|
|
1018
|
-
server.tool(
|
|
1019
|
-
taskId: z.string().describe(
|
|
1664
|
+
server.tool("update_task_status", "Update the status of a task in Apple Reminders or Notion.", {
|
|
1665
|
+
taskId: z.string().describe("ID of the task to update"),
|
|
1020
1666
|
status: z
|
|
1021
|
-
.enum([
|
|
1022
|
-
.describe(
|
|
1667
|
+
.enum(["not_started", "in_progress", "completed", "cancelled"])
|
|
1668
|
+
.describe("New status for the task"),
|
|
1023
1669
|
source: z
|
|
1024
|
-
.enum([
|
|
1025
|
-
.describe(
|
|
1670
|
+
.enum(["apple_reminders", "notion", "manual"])
|
|
1671
|
+
.describe("Source of the task"),
|
|
1026
1672
|
syncAcrossSources: z
|
|
1027
1673
|
.boolean()
|
|
1028
1674
|
.optional()
|
|
1029
|
-
.describe(
|
|
1675
|
+
.describe("Whether to sync the status across all sources"),
|
|
1030
1676
|
}, async ({ taskId, status, source, syncAcrossSources }) => {
|
|
1031
1677
|
if (!config) {
|
|
1032
1678
|
return {
|
|
1033
1679
|
content: [
|
|
1034
1680
|
{
|
|
1035
|
-
type:
|
|
1681
|
+
type: "text",
|
|
1036
1682
|
text: JSON.stringify({
|
|
1037
1683
|
error: true,
|
|
1038
|
-
message:
|
|
1684
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
1039
1685
|
}, null, 2),
|
|
1040
1686
|
},
|
|
1041
1687
|
],
|
|
@@ -1051,7 +1697,7 @@ async function createServer() {
|
|
|
1051
1697
|
return {
|
|
1052
1698
|
content: [
|
|
1053
1699
|
{
|
|
1054
|
-
type:
|
|
1700
|
+
type: "text",
|
|
1055
1701
|
text: JSON.stringify({
|
|
1056
1702
|
success: false,
|
|
1057
1703
|
taskId,
|
|
@@ -1070,7 +1716,7 @@ async function createServer() {
|
|
|
1070
1716
|
return {
|
|
1071
1717
|
content: [
|
|
1072
1718
|
{
|
|
1073
|
-
type:
|
|
1719
|
+
type: "text",
|
|
1074
1720
|
text: JSON.stringify({
|
|
1075
1721
|
success: true,
|
|
1076
1722
|
taskId,
|
|
@@ -1088,10 +1734,10 @@ async function createServer() {
|
|
|
1088
1734
|
return {
|
|
1089
1735
|
content: [
|
|
1090
1736
|
{
|
|
1091
|
-
type:
|
|
1737
|
+
type: "text",
|
|
1092
1738
|
text: JSON.stringify({
|
|
1093
1739
|
error: true,
|
|
1094
|
-
message: `タスクステータスの更新に失敗しました: ${error instanceof Error ? error.message :
|
|
1740
|
+
message: `タスクステータスの更新に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1095
1741
|
}, null, 2),
|
|
1096
1742
|
},
|
|
1097
1743
|
],
|
|
@@ -1102,15 +1748,15 @@ async function createServer() {
|
|
|
1102
1748
|
* sync_tasks - Sync tasks across all sources
|
|
1103
1749
|
* Requirement: 12.6
|
|
1104
1750
|
*/
|
|
1105
|
-
server.tool(
|
|
1751
|
+
server.tool("sync_tasks", "Synchronize tasks between Apple Reminders and Notion, detecting and resolving conflicts.", {}, async () => {
|
|
1106
1752
|
if (!config) {
|
|
1107
1753
|
return {
|
|
1108
1754
|
content: [
|
|
1109
1755
|
{
|
|
1110
|
-
type:
|
|
1756
|
+
type: "text",
|
|
1111
1757
|
text: JSON.stringify({
|
|
1112
1758
|
error: true,
|
|
1113
|
-
message:
|
|
1759
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
1114
1760
|
}, null, 2),
|
|
1115
1761
|
},
|
|
1116
1762
|
],
|
|
@@ -1124,7 +1770,7 @@ async function createServer() {
|
|
|
1124
1770
|
return {
|
|
1125
1771
|
content: [
|
|
1126
1772
|
{
|
|
1127
|
-
type:
|
|
1773
|
+
type: "text",
|
|
1128
1774
|
text: JSON.stringify({
|
|
1129
1775
|
success: true,
|
|
1130
1776
|
totalTasks: result.totalTasks,
|
|
@@ -1144,10 +1790,10 @@ async function createServer() {
|
|
|
1144
1790
|
return {
|
|
1145
1791
|
content: [
|
|
1146
1792
|
{
|
|
1147
|
-
type:
|
|
1793
|
+
type: "text",
|
|
1148
1794
|
text: JSON.stringify({
|
|
1149
1795
|
error: true,
|
|
1150
|
-
message: `タスク同期に失敗しました: ${error instanceof Error ? error.message :
|
|
1796
|
+
message: `タスク同期に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1151
1797
|
}, null, 2),
|
|
1152
1798
|
},
|
|
1153
1799
|
],
|
|
@@ -1158,20 +1804,20 @@ async function createServer() {
|
|
|
1158
1804
|
* detect_duplicates - Detect duplicate tasks across sources
|
|
1159
1805
|
* Requirement: 12.5
|
|
1160
1806
|
*/
|
|
1161
|
-
server.tool(
|
|
1807
|
+
server.tool("detect_duplicates", "Detect duplicate tasks between Apple Reminders and Notion.", {
|
|
1162
1808
|
autoMerge: z
|
|
1163
1809
|
.boolean()
|
|
1164
1810
|
.optional()
|
|
1165
|
-
.describe(
|
|
1811
|
+
.describe("Whether to automatically merge high-confidence duplicates"),
|
|
1166
1812
|
}, async ({ autoMerge }) => {
|
|
1167
1813
|
if (!config) {
|
|
1168
1814
|
return {
|
|
1169
1815
|
content: [
|
|
1170
1816
|
{
|
|
1171
|
-
type:
|
|
1817
|
+
type: "text",
|
|
1172
1818
|
text: JSON.stringify({
|
|
1173
1819
|
error: true,
|
|
1174
|
-
message:
|
|
1820
|
+
message: "sageが設定されていません。check_setup_statusを実行してください。",
|
|
1175
1821
|
}, null, 2),
|
|
1176
1822
|
},
|
|
1177
1823
|
],
|
|
@@ -1203,7 +1849,7 @@ async function createServer() {
|
|
|
1203
1849
|
// Auto-merge high-confidence duplicates if requested
|
|
1204
1850
|
let mergeResults;
|
|
1205
1851
|
if (autoMerge) {
|
|
1206
|
-
const highConfidenceDuplicates = duplicates.filter((d) => d.confidence ===
|
|
1852
|
+
const highConfidenceDuplicates = duplicates.filter((d) => d.confidence === "high");
|
|
1207
1853
|
if (highConfidenceDuplicates.length > 0) {
|
|
1208
1854
|
mergeResults = await taskSynchronizer.mergeDuplicates(highConfidenceDuplicates);
|
|
1209
1855
|
}
|
|
@@ -1211,7 +1857,7 @@ async function createServer() {
|
|
|
1211
1857
|
return {
|
|
1212
1858
|
content: [
|
|
1213
1859
|
{
|
|
1214
|
-
type:
|
|
1860
|
+
type: "text",
|
|
1215
1861
|
text: JSON.stringify({
|
|
1216
1862
|
success: true,
|
|
1217
1863
|
duplicatesFound: duplicates.length,
|
|
@@ -1219,7 +1865,7 @@ async function createServer() {
|
|
|
1219
1865
|
mergeResults: autoMerge ? mergeResults : undefined,
|
|
1220
1866
|
message: duplicates.length > 0
|
|
1221
1867
|
? `${duplicates.length}件の重複タスクが検出されました。`
|
|
1222
|
-
:
|
|
1868
|
+
: "重複タスクは見つかりませんでした。",
|
|
1223
1869
|
}, null, 2),
|
|
1224
1870
|
},
|
|
1225
1871
|
],
|
|
@@ -1229,10 +1875,10 @@ async function createServer() {
|
|
|
1229
1875
|
return {
|
|
1230
1876
|
content: [
|
|
1231
1877
|
{
|
|
1232
|
-
type:
|
|
1878
|
+
type: "text",
|
|
1233
1879
|
text: JSON.stringify({
|
|
1234
1880
|
error: true,
|
|
1235
|
-
message: `重複検出に失敗しました: ${error instanceof Error ? error.message :
|
|
1881
|
+
message: `重複検出に失敗しました: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1236
1882
|
}, null, 2),
|
|
1237
1883
|
},
|
|
1238
1884
|
],
|
|
@@ -1245,13 +1891,55 @@ async function createServer() {
|
|
|
1245
1891
|
* Main entry point
|
|
1246
1892
|
*/
|
|
1247
1893
|
async function main() {
|
|
1894
|
+
// Import CLI modules
|
|
1895
|
+
const { parseArgs } = await import("./cli/parser.js");
|
|
1896
|
+
const { startServer } = await import("./cli/main-entry.js");
|
|
1897
|
+
// Parse CLI arguments
|
|
1898
|
+
const options = parseArgs(process.argv.slice(2));
|
|
1899
|
+
// Handle help and version
|
|
1900
|
+
if (options.help || options.version) {
|
|
1901
|
+
const result = await startServer(options);
|
|
1902
|
+
console.log(result.message);
|
|
1903
|
+
process.exit(0);
|
|
1904
|
+
}
|
|
1905
|
+
// Handle token generation
|
|
1906
|
+
if (options.generateToken) {
|
|
1907
|
+
const result = await startServer(options);
|
|
1908
|
+
if (result.success) {
|
|
1909
|
+
console.log(result.message);
|
|
1910
|
+
process.exit(0);
|
|
1911
|
+
}
|
|
1912
|
+
else {
|
|
1913
|
+
console.error(`Token generation failed: ${result.error}`);
|
|
1914
|
+
process.exit(1);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
// Start in HTTP mode if --remote flag is set
|
|
1918
|
+
if (options.remote) {
|
|
1919
|
+
const result = await startServer(options);
|
|
1920
|
+
if (!result.success) {
|
|
1921
|
+
console.error(`Failed to start HTTP server: ${result.error}`);
|
|
1922
|
+
process.exit(1);
|
|
1923
|
+
}
|
|
1924
|
+
console.error(`${SERVER_NAME} v${VERSION} started in HTTP mode on ${result.host}:${result.port}`);
|
|
1925
|
+
// Keep the process running
|
|
1926
|
+
process.on("SIGINT", async () => {
|
|
1927
|
+
console.error("\nShutting down...");
|
|
1928
|
+
if (result.stop) {
|
|
1929
|
+
await result.stop();
|
|
1930
|
+
}
|
|
1931
|
+
process.exit(0);
|
|
1932
|
+
});
|
|
1933
|
+
return;
|
|
1934
|
+
}
|
|
1935
|
+
// Start in Stdio mode (default for MCP)
|
|
1248
1936
|
const server = await createServer();
|
|
1249
1937
|
const transport = new StdioServerTransport();
|
|
1250
1938
|
await server.connect(transport);
|
|
1251
|
-
console.error(`${SERVER_NAME} v${
|
|
1939
|
+
console.error(`${SERVER_NAME} v${VERSION} started in Stdio mode`);
|
|
1252
1940
|
}
|
|
1253
1941
|
main().catch((error) => {
|
|
1254
|
-
console.error(
|
|
1942
|
+
console.error("Failed to start sage server:", error);
|
|
1255
1943
|
process.exit(1);
|
|
1256
1944
|
});
|
|
1257
1945
|
//# sourceMappingURL=index.js.map
|