@vibe-lark/larkpal 0.1.82 → 0.1.84

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.
@@ -231,15 +231,22 @@ function log$1(level, message, meta) {
231
231
  };
232
232
  process.stderr.write(JSON.stringify(entry) + "\n");
233
233
  }
234
+ function readDisabledToolsFromEnv() {
235
+ return (process.env["LARKPAL_MCP_DISABLED_TOOLS"] ?? "").split(",").map((tool) => tool.trim()).filter(Boolean);
236
+ }
237
+ function isToolDisabled(disabledTools, tool) {
238
+ return disabledTools.has(tool) || disabledTools.has(`mcp__larkpal__${tool}`);
239
+ }
234
240
  /**
235
241
  * 注册所有 tool 到 MCP Server
236
242
  */
237
- function registerTools(server) {
238
- server.tool("ask_user", "向用户提问,等待用户回答。支持多阶段提问,每个阶段可包含选项或自由文本输入。", {
243
+ function registerTools(server, options = {}) {
244
+ const disabledTools = new Set(options.disabledTools ?? readDisabledToolsFromEnv());
245
+ if (!isToolDisabled(disabledTools, "ask_user")) server.tool("ask_user", "向用户提问,等待用户回答。支持多阶段提问,每个阶段可包含选项或自由文本输入;每个独立决策维度应拆成一个 phase,不要把多个问题塞进同一个选项列表。", {
239
246
  question: z.string().describe("主问题描述"),
240
247
  phases: z.array(z.object({
241
248
  id: z.string().describe("阶段唯一标识"),
242
- title: z.string().describe("阶段标题"),
249
+ title: z.string().describe("自然语义化的阶段提问主题,例如\"要看的具体是什么?\"、\"按照什么视角来查?\";不要使用\"确认问题\"或\"请选择\"这类泛标题"),
243
250
  description: z.string().optional().describe("阶段详细描述"),
244
251
  options: z.array(z.object({
245
252
  label: z.string().describe("选项显示文本"),
@@ -283,9 +290,13 @@ function registerTools(server) {
283
290
  };
284
291
  }
285
292
  });
286
- server.tool("request_permission", "请求飞书 API 权限。发送权限申请后等待用户授权。", {
293
+ if (!isToolDisabled(disabledTools, "request_permission")) server.tool("request_permission", "请求飞书 API 权限。发送权限申请后等待用户授权。", {
287
294
  scopes: z.array(z.string()).describe("需要的权限列表(如 \"contact:user.base:readonly\")"),
288
- reason: z.string().optional().describe("申请权限的原因说明")
295
+ reason: z.string().optional().describe("申请权限的原因说明"),
296
+ grantUrl: z.string().optional().describe("可直接打开的权限申请链接"),
297
+ grant_url: z.string().optional().describe("可直接打开的权限申请链接(snake_case 兼容字段)"),
298
+ consoleUrl: z.string().optional().describe("开放平台权限配置页链接"),
299
+ console_url: z.string().optional().describe("开放平台权限配置页链接(snake_case 兼容字段)")
289
300
  }, async (params) => {
290
301
  log$1("info", `request_permission 被调用`, {
291
302
  scopes: params.scopes,
@@ -294,7 +305,11 @@ function registerTools(server) {
294
305
  try {
295
306
  const toolParams = {
296
307
  scopes: params.scopes,
297
- reason: params.reason
308
+ reason: params.reason,
309
+ grantUrl: params.grantUrl,
310
+ grant_url: params.grant_url,
311
+ consoleUrl: params.consoleUrl,
312
+ console_url: params.console_url
298
313
  };
299
314
  const requestId = await hostBridge.sendCallback("request_permission", toolParams);
300
315
  log$1("info", `等待权限审批`, { requestId });
@@ -319,7 +334,7 @@ function registerTools(server) {
319
334
  };
320
335
  }
321
336
  });
322
- server.tool("signal_no_reply", "标记本次不需要回复用户。仅用于通知宿主层,立即返回。", { reason: z.string().describe("不回复的原因(仅用于日志记录)") }, async (params) => {
337
+ if (!isToolDisabled(disabledTools, "signal_no_reply")) server.tool("signal_no_reply", "标记本次不需要回复用户。仅用于通知宿主层,立即返回。", { reason: z.string().describe("不回复的原因(仅用于日志记录)") }, async (params) => {
323
338
  log$1("info", `signal_no_reply 被调用`, { reason: params.reason });
324
339
  hostBridge.sendNotification("signal_no_reply", { reason: params.reason }).catch((err) => {
325
340
  log$1("warn", `signal_no_reply 通知发送失败(已忽略)`, { error: err instanceof Error ? err.message : String(err) });
@@ -396,6 +411,48 @@ function registerTools(server) {
396
411
  };
397
412
  }
398
413
  });
414
+ server.tool("scheduled_task_list", "列出当前 Gateway 中已配置的定时 Agent Run。返回脱敏后的紧凑 JSON。", {}, async () => runScheduledTaskTool("scheduled_task_list", {}));
415
+ server.tool("scheduled_task_get", "按 ID 查看一个定时 Agent Run 的脱敏详情。", { id: z.string().describe("定时任务 ID") }, async (params) => runScheduledTaskTool("scheduled_task_get", params));
416
+ server.tool("scheduled_task_create", "创建定时 Agent Run。使用 Gateway scheduler 的标准运行语义,需要 name、cron、session_id、cwd、prompt 和 owner identity。", {
417
+ name: z.string().describe("定时任务名称"),
418
+ cron: z.string().describe("node-cron 表达式,如 \"0 9 * * *\""),
419
+ session_id: z.string().describe("运行会话 ID"),
420
+ conversation_id: z.string().optional().describe("对话 ID;默认可与 session_id 相同"),
421
+ cwd: z.string().describe("运行工作目录"),
422
+ prompt: z.string().describe("定时触发时执行的 prompt"),
423
+ identity: z.record(z.string(), z.unknown()).optional().describe("owner identity,至少包含 tenantKey 和 userId/openId"),
424
+ auth_headers: z.record(z.string(), z.string()).optional().describe("运行时认证头;宿主层会在返回时脱敏"),
425
+ runtime_instructions: z.unknown().optional().describe("运行时指令注入"),
426
+ runtime_skills: z.unknown().optional().describe("运行时技能注入"),
427
+ policy: z.record(z.string(), z.unknown()).optional().describe("执行策略"),
428
+ scenario_id: z.string().optional().describe("场景 ID"),
429
+ metadata: z.record(z.string(), z.unknown()).optional().describe("元数据")
430
+ }, async (params) => runScheduledTaskTool("scheduled_task_create", params));
431
+ server.tool("scheduled_task_update", "更新定时 Agent Run。updates 支持 Gateway scheduler 的可更新字段,如 name、cron、prompt、enabled、policy。", {
432
+ id: z.string().describe("定时任务 ID"),
433
+ updates: z.record(z.string(), z.unknown()).describe("要更新的字段")
434
+ }, async (params) => runScheduledTaskTool("scheduled_task_update", params));
435
+ server.tool("scheduled_task_delete", "删除定时 Agent Run。", { id: z.string().describe("定时任务 ID") }, async (params) => runScheduledTaskTool("scheduled_task_delete", params));
436
+ server.tool("scheduled_task_run_now", "立即执行一个定时 Agent Run,用于测试或手动触发。执行仍使用标准 scheduled-task runtime entrypoint。", { id: z.string().describe("定时任务 ID") }, async (params) => runScheduledTaskTool("scheduled_task_run_now", params));
437
+ }
438
+ async function runScheduledTaskTool(tool, params) {
439
+ try {
440
+ const result = await hostBridge.sendSyncRequest(tool, params);
441
+ return { content: [{
442
+ type: "text",
443
+ text: JSON.stringify(result)
444
+ }] };
445
+ } catch (err) {
446
+ const errorMsg = err instanceof Error ? err.message : String(err);
447
+ log$1("error", `${tool} 执行失败`, { error: errorMsg });
448
+ return {
449
+ content: [{
450
+ type: "text",
451
+ text: JSON.stringify({ error: errorMsg })
452
+ }],
453
+ isError: true
454
+ };
455
+ }
399
456
  }
400
457
  //#endregion
401
458
  //#region src/mcp-server/index.ts
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-lark/larkpal",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "description": "LarkPal - Lark/Feishu bot service",
5
5
  "type": "module",
6
6
  "main": "./dist/main.mjs",
@@ -47,7 +47,9 @@
47
47
  "image-size": "^2.0.2",
48
48
  "node-cron": "^4.0.8",
49
49
  "openclaw": "^2026.4.9",
50
+ "qrcode-terminal": "^0.12.0",
50
51
  "uuid": "^11.1.0",
52
+ "ws": "^8.21.0",
51
53
  "zod": "^4.3.6"
52
54
  },
53
55
  "optionalDependencies": {
@@ -59,7 +61,9 @@
59
61
  "@types/express": "^5.0.2",
60
62
  "@types/node": "^25.2.3",
61
63
  "@types/node-cron": "^3.0.11",
64
+ "@types/qrcode-terminal": "^0.12.2",
62
65
  "@types/uuid": "^10.0.0",
66
+ "@types/ws": "^8.18.1",
63
67
  "eslint": "^9.39.3",
64
68
  "eslint-plugin-import-x": "^4.16.2",
65
69
  "eslint-plugin-n": "^17.24.0",