@mcpcn/mcp-notification 1.1.7 → 1.1.9
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/index.js +23 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ async function postJson(path, body, chatSessionId) {
|
|
|
32
32
|
});
|
|
33
33
|
if (!resp.ok) {
|
|
34
34
|
const text = await resp.text().catch(() => '');
|
|
35
|
-
const msg = `HTTP
|
|
35
|
+
const msg = `HTTP error: ${resp.status} ${resp.statusText}${text ? ` | Body: ${text.slice(0, 500)}` : ''}`;
|
|
36
36
|
if (resp.status >= 500 && attempt < 2) {
|
|
37
37
|
await new Promise((r) => setTimeout(r, 300 * (attempt + 1)));
|
|
38
38
|
continue;
|
|
@@ -49,7 +49,7 @@ async function postJson(path, body, chatSessionId) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
throw new Error(
|
|
52
|
+
throw new Error(`Execution failed: ${lastError?.message}`);
|
|
53
53
|
}
|
|
54
54
|
async function getJson(path, chatSessionId) {
|
|
55
55
|
const headers = { Accept: 'application/json' };
|
|
@@ -61,7 +61,7 @@ async function getJson(path, chatSessionId) {
|
|
|
61
61
|
const resp = await fetch(`${API_BASE}${path}`, { headers });
|
|
62
62
|
if (!resp.ok) {
|
|
63
63
|
const text = await resp.text().catch(() => '');
|
|
64
|
-
const msg = `HTTP
|
|
64
|
+
const msg = `HTTP error: ${resp.status} ${resp.statusText}${text ? ` | Body: ${text.slice(0, 500)}` : ''}`;
|
|
65
65
|
if (resp.status >= 500 && attempt < 2) {
|
|
66
66
|
await new Promise((r) => setTimeout(r, 300 * (attempt + 1)));
|
|
67
67
|
continue;
|
|
@@ -78,7 +78,7 @@ async function getJson(path, chatSessionId) {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
throw new Error(
|
|
81
|
+
throw new Error(`Execution failed: ${lastError?.message}`);
|
|
82
82
|
}
|
|
83
83
|
class ReminderServer {
|
|
84
84
|
constructor() {
|
|
@@ -95,16 +95,16 @@ class ReminderServer {
|
|
|
95
95
|
tools: [
|
|
96
96
|
{
|
|
97
97
|
name: 'set_reminder',
|
|
98
|
-
description: '
|
|
98
|
+
description: '设置通知提醒,支持一次性、按间隔循环、每日循环。规则:当用户表述为具体某天/今天/明天/后天/某日期某时间等,请选择repeat=none;优选将具体日期时间直接计算为RFC3339并填入triggerAt,或仅提供timeOfDay让服务端自动推算到最近一次的该时间(若当天已过则推算到明天)。只有当用户明确说“每天/每日/每晚/每早/每隔X时间”时,才使用repeat=daily或repeat=interval。一次性提醒可提供triggerAt或delaySec,或提供timeOfDay用于推算,优先使用delaySec。',
|
|
99
99
|
inputSchema: {
|
|
100
100
|
type: 'object',
|
|
101
101
|
properties: {
|
|
102
102
|
content: { type: 'string', minLength: 1, description: '提醒内容,例如 “开会”。' },
|
|
103
|
-
repeat: { type: 'string', enum: ['none', 'interval', 'daily'], default: 'none', description: '提醒类型:none
|
|
103
|
+
repeat: { type: 'string', enum: ['none', 'interval', 'daily'], default: 'none', description: '提醒类型:none 一次性(包含“今天/明天/某天”的语义)、interval 按间隔、daily 每日(仅当用户明确要求“每天”时使用)。' },
|
|
104
104
|
delaySec: { type: 'number', minimum: 1, description: '一次性提醒相对延迟秒数,例如 300 表示5分钟后触发。与triggerAt二选一。' },
|
|
105
105
|
triggerAt: { type: 'string', description: '一次性提醒绝对时间,RFC3339 格式,例如 2025-11-21T08:00:00+08:00。' },
|
|
106
106
|
intervalSec: { type: 'number', minimum: 1, description: '按间隔循环的间隔秒数,例如 3600 表示每小时提醒一次。仅repeat=interval时必需。' },
|
|
107
|
-
timeOfDay: { type: 'string', pattern: '^\\d{1,2}:\\d{2}(:\\d{2})?$', description: '一天中的时间,格式 HH:mm 或 HH:mm:ss,例如 08:00 或 08:00:00。repeat=daily时必需;repeat=none且未提供triggerAt/delaySec
|
|
107
|
+
timeOfDay: { type: 'string', pattern: '^\\d{1,2}:\\d{2}(:\\d{2})?$', description: '一天中的时间,格式 HH:mm 或 HH:mm:ss,例如 08:00 或 08:00:00。repeat=daily时必需;repeat=none且未提供triggerAt/delaySec时用于推算。典型用法:用户说“明天早上8点”,请选择repeat=none并设置timeOfDay="08:00",服务端会自动推算到最近的08:00。' },
|
|
108
108
|
tzOffsetMin: { type: 'number', description: '时区偏移分钟,例如北京为 480;不提供时默认使用本机时区。' },
|
|
109
109
|
chatSessionId: { type: 'string', minLength: 1, description: '设备会话标识,由宿主环境传入。' },
|
|
110
110
|
},
|
|
@@ -131,6 +131,7 @@ class ReminderServer {
|
|
|
131
131
|
examples: [
|
|
132
132
|
{ content: '开会', repeat: 'none', triggerAt: '2025-11-21T08:00:00+08:00' },
|
|
133
133
|
{ content: '喝水', repeat: 'none', delaySec: 300 },
|
|
134
|
+
{ content: '出发去10号线', repeat: 'none', timeOfDay: '08:00', tzOffsetMin: 480 },
|
|
134
135
|
{ content: '站立休息', repeat: 'interval', intervalSec: 1800 },
|
|
135
136
|
{ content: '打卡', repeat: 'daily', timeOfDay: '09:00', tzOffsetMin: 480 },
|
|
136
137
|
],
|
|
@@ -162,7 +163,7 @@ class ReminderServer {
|
|
|
162
163
|
try {
|
|
163
164
|
console.error('[调试] request.params keys = ' + JSON.stringify(Object.keys(request.params || {})));
|
|
164
165
|
if (!request.params.arguments || typeof request.params.arguments !== 'object') {
|
|
165
|
-
throw new McpError(ErrorCode.InvalidParams, '
|
|
166
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid parameters');
|
|
166
167
|
}
|
|
167
168
|
const name = request.params.name;
|
|
168
169
|
const args = request.params.arguments;
|
|
@@ -170,13 +171,13 @@ class ReminderServer {
|
|
|
170
171
|
const chatSessionId = resolveChatSessionId(request);
|
|
171
172
|
if (!chatSessionId) {
|
|
172
173
|
console.error('通知工具未在请求中检测到 chatSessionId(meta.chatSessionId)');
|
|
173
|
-
const baseMsg = '
|
|
174
|
+
const baseMsg = 'Device parsing failed: chatSessionId is required; notification tool unavailable';
|
|
174
175
|
const errText = name === 'set_reminder'
|
|
175
|
-
?
|
|
176
|
+
? `Set failed: ${baseMsg}`
|
|
176
177
|
: name === 'list_reminders'
|
|
177
|
-
?
|
|
178
|
+
? `Fetch failed: ${baseMsg}`
|
|
178
179
|
: name === 'cancel_reminder'
|
|
179
|
-
?
|
|
180
|
+
? `Cancel failed: ${baseMsg}`
|
|
180
181
|
: baseMsg;
|
|
181
182
|
return { content: [{ type: 'text', text: errText }], isError: true };
|
|
182
183
|
}
|
|
@@ -202,13 +203,13 @@ class ReminderServer {
|
|
|
202
203
|
if (typeof params.timeOfDay === 'string' && params.timeOfDay.trim()) {
|
|
203
204
|
const m = params.timeOfDay.trim().match(/^\s*(\d{1,2}):(\d{2})(?::(\d{2}))?\s*$/);
|
|
204
205
|
if (!m) {
|
|
205
|
-
return { content: [{ type: 'text', text: '
|
|
206
|
+
return { content: [{ type: 'text', text: 'Set failed: timeOfDay must be HH:mm or HH:mm:ss' }], isError: true };
|
|
206
207
|
}
|
|
207
208
|
const hh = parseInt(m[1], 10);
|
|
208
209
|
const mi = parseInt(m[2], 10);
|
|
209
210
|
const ss = m[3] ? parseInt(m[3], 10) : 0;
|
|
210
211
|
if (hh < 0 || hh > 23 || mi < 0 || mi > 59 || ss < 0 || ss > 59) {
|
|
211
|
-
return { content: [{ type: 'text', text: '
|
|
212
|
+
return { content: [{ type: 'text', text: 'Set failed: timeOfDay must be HH:mm or HH:mm:ss' }], isError: true };
|
|
212
213
|
}
|
|
213
214
|
const offsetMin = typeof params.tzOffsetMin === 'number' ? params.tzOffsetMin : -new Date().getTimezoneOffset();
|
|
214
215
|
const nowUtc = Date.now();
|
|
@@ -238,7 +239,7 @@ class ReminderServer {
|
|
|
238
239
|
console.error(`自动计算triggerAt: ${params.triggerAt}`);
|
|
239
240
|
}
|
|
240
241
|
else {
|
|
241
|
-
return { content: [{ type: 'text', text: '
|
|
242
|
+
return { content: [{ type: 'text', text: 'Set failed: provide triggerAt or delaySec, or timeOfDay to derive' }], isError: true };
|
|
242
243
|
}
|
|
243
244
|
}
|
|
244
245
|
if (needSingleTrigger && hasDelay && !hasTrigger) {
|
|
@@ -262,7 +263,7 @@ class ReminderServer {
|
|
|
262
263
|
}
|
|
263
264
|
const resp = await postJson('/reminder/set', params, chatSessionId);
|
|
264
265
|
if (resp.code !== 0) {
|
|
265
|
-
return { content: [{ type: 'text', text:
|
|
266
|
+
return { content: [{ type: 'text', text: `Set failed: ${resp.msg}` }], isError: true };
|
|
266
267
|
}
|
|
267
268
|
const triggerAt = resp.data?.triggerAt;
|
|
268
269
|
const offsetMin = typeof params.tzOffsetMin === 'number' ? params.tzOffsetMin : -new Date().getTimezoneOffset();
|
|
@@ -292,7 +293,7 @@ class ReminderServer {
|
|
|
292
293
|
content: [
|
|
293
294
|
{
|
|
294
295
|
type: 'text',
|
|
295
|
-
text: JSON.stringify({ id: resp.data?.id, triggerAt: resp.data?.triggerAt, triggerAtLocal, msg: resp.msg || '
|
|
296
|
+
text: JSON.stringify({ id: resp.data?.id, triggerAt: resp.data?.triggerAt, triggerAtLocal, msg: resp.msg || 'Set succeeded' }, null, 2),
|
|
296
297
|
},
|
|
297
298
|
],
|
|
298
299
|
isError: false,
|
|
@@ -301,7 +302,7 @@ class ReminderServer {
|
|
|
301
302
|
if (name === 'list_reminders') {
|
|
302
303
|
const resp = await getJson(`/reminder/list`, chatSessionId);
|
|
303
304
|
if (resp.code !== 0) {
|
|
304
|
-
return { content: [{ type: 'text', text:
|
|
305
|
+
return { content: [{ type: 'text', text: `Fetch failed: ${resp.msg}` }], isError: true };
|
|
305
306
|
}
|
|
306
307
|
const offsetMin = typeof args?.tzOffsetMin === 'number' ? args.tzOffsetMin : -new Date().getTimezoneOffset();
|
|
307
308
|
const formatOffset = (min) => {
|
|
@@ -360,16 +361,16 @@ class ReminderServer {
|
|
|
360
361
|
const params = { id: String(args.id || '') };
|
|
361
362
|
const resp = await postJson(`/reminder/cancel`, params, chatSessionId);
|
|
362
363
|
if (resp.code !== 0) {
|
|
363
|
-
return { content: [{ type: 'text', text:
|
|
364
|
+
return { content: [{ type: 'text', text: `Cancel failed: ${resp.msg}` }], isError: true };
|
|
364
365
|
}
|
|
365
|
-
return { content: [{ type: 'text', text: resp.msg || '
|
|
366
|
+
return { content: [{ type: 'text', text: resp.msg || 'Cancel succeeded' }], isError: false };
|
|
366
367
|
}
|
|
367
|
-
throw new McpError(ErrorCode.MethodNotFound,
|
|
368
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
368
369
|
}
|
|
369
370
|
catch (error) {
|
|
370
371
|
if (error instanceof McpError)
|
|
371
372
|
throw error;
|
|
372
|
-
throw new McpError(ErrorCode.InternalError,
|
|
373
|
+
throw new McpError(ErrorCode.InternalError, `Execution failed: ${error.message}`);
|
|
373
374
|
}
|
|
374
375
|
});
|
|
375
376
|
}
|