@lemonbeijing/lemonclaw-mcp-service 0.1.2 → 0.1.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 CHANGED
@@ -1,38 +1,50 @@
1
1
  # LemonClaw MCP Service
2
2
 
3
- Local STDIO MCP service for the LemonClaw portable Runtime. The MCP package embeds the shared Runtime manager and starts Runtime Python directly; it does not install, resolve, or execute the WorkBuddy Launcher package.
4
-
5
- Requires Node.js 20 or newer. Runtime is installed or periodically updated on the first relevant tool call. The MCP service and WorkBuddy Launcher share `~/.lemonclaw-cli`, including the runtime pointer, installation lock, authentication, account context, documents, downloads, and invoice files.
6
-
7
- ## Run from this repository
8
-
9
- ```text
10
- npm install
11
- npm run build
12
- node dist/lemonclaw-mcp.cjs
13
- ```
14
-
15
- Example MCP host configuration:
16
-
17
- ```json
18
- {
19
- "mcpServers": {
20
- "lemonclaw": {
21
- "type": "stdio",
22
- "command": "node",
23
- "args": ["D:/VSProject/lemonscmskills/mcp-service/dist/lemonclaw-mcp.cjs"]
3
+ 面向柠檬云的本地 STDIO MCP 服务,支持 ACC 财务、SCM 进销存、ERP 业财和独立开票。可查询客户、供应商、商品、仓库等基础资料,以及采购、销售、库存、收付款、往来、凭证、账簿、发票和经营或财务报表;对于 Action 文档明确支持的写操作,会在用户确认后执行。
4
+
5
+ MCP 包内嵌 Runtime 管理组件并直接启动 Runtime Python。要求 Node.js 20 或更高版本;首次相关 Tool 调用时自动安装 Runtime,之后按策略检查更新。Runtime、认证、账套上下文、文档、下载和开票文件统一保存在 `~/.lemonclaw-cli` 目录中。
6
+
7
+ 必须在 MCP 服务环境中配置 `LEMONCLAW_API_KEY`,该凭据不会作为 Tool 参数暴露。每次 Tool 执行前,MCP 会先解析或安装 Runtime,再通过 Runtime 认证模块同步发生变化的 API Key,最后调用目标业务操作;API Key 未变化时不会重复写入。
8
+
9
+ ## MCP Host 配置
10
+
11
+ 推荐通过已发布的 npm 包启动:
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "lemonclaw": {
17
+ "type": "stdio",
18
+ "command": "npx",
19
+ "args": [
20
+ "--yes",
21
+ "--prefer-online",
22
+ "@lemonbeijing/lemonclaw-mcp-service@latest"
23
+ ],
24
+ "env": {
25
+ "LEMONCLAW_API_KEY": "<在 MCP Host 中配置为密钥>"
26
+ }
24
27
  }
25
28
  }
26
- }
27
- ```
28
-
29
- After publication, use `npx --yes --prefer-online @lemonbeijing/lemonclaw-mcp-service@latest`. `npx` refreshes the MCP service when the host reconnects or restarts it; Runtime updates remain independent.
30
-
31
- ## Tool groups
32
-
33
- - Authentication: `lemon_auth_status`, `lemon_auth_save_api_key`, `lemon_auth_clear`
34
- - Account context: `lemon_account_current`, `lemon_account_list`, `lemon_account_switch`, `lemon_account_select`, `lemon_account_clear`
35
- - ACC/SCM/ERP actions: `lemon_action_search`, `lemon_action_show`, `lemon_action_read_doc`, `lemon_action_run`
36
- - Independent invoicing: `lemon_invoice_read_doc`, `lemon_invoice_api`, `lemon_invoice_run_helper`
37
-
38
- `stdout` is reserved for MCP JSON-RPC. CLI and Runtime output is captured and returned as MCP Tool content; service diagnostics use `stderr` only.
29
+ }
30
+ ```
31
+
32
+ MCP Host 重连或重启服务时,`npx` 会刷新 MCP 包;Runtime 更新与 MCP 包更新相互独立。
33
+
34
+ ## 从源码运行
35
+
36
+ ```text
37
+ npm install
38
+ npm run build
39
+ node dist/lemonclaw-mcp.cjs
40
+ ```
41
+
42
+ ## Tool 分组
43
+
44
+ - 账套上下文:`lemon_account_current`、`lemon_account_list`、`lemon_account_switch`、`lemon_account_select`、`lemon_account_clear`
45
+ - ACC/SCM/ERP 业务:`lemon_action_search`、`lemon_action_show`、`lemon_action_read_doc`、`lemon_action_run`
46
+ - 独立开票:`lemon_invoice_read_doc`、`lemon_invoice_api`、`lemon_invoice_run_helper`
47
+
48
+ `stdout` 仅用于 MCP JSON-RPC。CLI 和 Runtime 输出会被捕获并作为 MCP Tool 内容返回;服务诊断只使用 `stderr`。
49
+
50
+ 认证是 Tool 的内部前置条件。不要通过提示词或 Tool 输入发送 API Key;需要更换凭据时,应更新 MCP Host 中的 `LEMONCLAW_API_KEY` 并重新连接。
@@ -3279,8 +3279,8 @@ var require_package = __commonJS({
3279
3279
  "package.json"(exports2, module2) {
3280
3280
  module2.exports = {
3281
3281
  name: "@lemonbeijing/lemonclaw-mcp-service",
3282
- version: "0.1.2",
3283
- description: "Local stdio MCP service for LemonClaw portable Runtime.",
3282
+ version: "0.1.4",
3283
+ description: "\u7528\u4E8E\u67E5\u8BE2\u548C\u64CD\u4F5C\u67E0\u6AAC\u4E91 Lemon Cloud \u4E1A\u52A1\u6570\u636E\u7684 MCP \u670D\u52A1\uFF0C\u8986\u76D6\u8D26\u5957\u3001\u8FDB\u9500\u5B58 SCM\u3001\u4E1A\u8D22 ERP\u3001\u8D22\u52A1 ACC \u548C\u72EC\u7ACB\u5F00\u7968\uFF1B\u652F\u6301\u5BA2\u6237\u3001\u4F9B\u5E94\u5546\u3001\u5546\u54C1\u3001\u4ED3\u5E93\u3001\u91C7\u8D2D\u3001\u9500\u552E\u3001\u5E93\u5B58\u3001\u6536\u4ED8\u6B3E\u3001\u5F80\u6765\u3001\u51ED\u8BC1\u3001\u8D26\u7C3F\u3001\u53D1\u7968\u53CA\u7ECF\u8425\u4E0E\u8D22\u52A1\u62A5\u8868\uFF0C\u5E76\u652F\u6301\u7ACB\u5373\u5F00\u7968\u3001\u6279\u91CF\u5F00\u7968\u548C\u95EE\u9898\u53CD\u9988\u3002",
3284
3284
  license: "UNLICENSED",
3285
3285
  type: "module",
3286
3286
  engines: {
@@ -5168,6 +5168,7 @@ var require_runtime_core = __commonJS({
5168
5168
  });
5169
5169
  module2.exports = {
5170
5170
  UPDATER_COMPATIBILITY_VERSION,
5171
+ packageVersion: packageJson.version,
5171
5172
  errors: require_errors(),
5172
5173
  install: require_install(),
5173
5174
  runtime: require_runtime()
@@ -5293,6 +5294,7 @@ async function resolveRuntimeEnvironment(descriptor, baseEnv = process.env) {
5293
5294
  }
5294
5295
 
5295
5296
  // src/invoice-runtime.js
5297
+ var MCP_CREDENTIAL_NOTICE = "> MCP \u51ED\u636E\u8986\u76D6\u89C4\u5219\uFF1AAPI Key \u5DF2\u7531 MCP \u73AF\u5883\u53D8\u91CF\u63D0\u4F9B\uFF0C\u5E76\u5728\u8C03\u7528\u672C Tool \u524D\u5B8C\u6210\u5185\u90E8\u540C\u6B65\u3002\u4E0D\u5F97\u5411\u7528\u6237\u7D22\u53D6\u3001\u5C55\u793A\u6216\u901A\u8FC7 Tool \u53C2\u6570\u4F20\u9012 API Key\uFF1B\u4E0B\u65B9 Runtime \u6587\u6863\u4E2D\u4EFB\u4F55\u6536\u96C6\u6216\u4FDD\u5B58 API Key \u7684\u65E7\u6307\u5F15\u5747\u4E0D\u9002\u7528\u4E8E MCP\u3002";
5296
5298
  var INVOICE_HELPERS = Object.freeze({
5297
5299
  customer_service_link: "scripts/customer_service_link.py",
5298
5300
  preview_server: "scripts/preview_http_server.py",
@@ -5311,7 +5313,6 @@ var API_ARGUMENT_FLAGS = Object.freeze({
5311
5313
  uscic: "--uscic",
5312
5314
  auth_company_id: "--auth-company-id",
5313
5315
  company_detail_id: "--company-detail-id",
5314
- api_key_last_four: "--api-key-last-four",
5315
5316
  ai_tool: "--ai-tool",
5316
5317
  model: "--model",
5317
5318
  feedback_contact: "--feedback-contact",
@@ -5351,7 +5352,9 @@ async function readInvoiceDocument(runtimeProvider, relativePath) {
5351
5352
  throw new Error("Invoice document path escapes the invoice directory.");
5352
5353
  }
5353
5354
  const content = await (0, import_promises2.readFile)(targetReal, "utf8");
5354
- return content.replace(/^\uFEFF/, "");
5355
+ return `${MCP_CREDENTIAL_NOTICE}
5356
+
5357
+ ${content.replace(/^\uFEFF/, "")}`;
5355
5358
  }
5356
5359
  function requireValue(args, key, operation) {
5357
5360
  const value = args[key];
@@ -5390,9 +5393,12 @@ async function runInvoiceApi(runtimeProvider, args) {
5390
5393
  if (args.user_confirmed !== true) {
5391
5394
  throw new Error("SkillInvoiceIssue requires explicit user confirmation.");
5392
5395
  }
5393
- for (const key of ["eiscid", "api_key_last_four", "ai_tool", "model"]) {
5396
+ for (const key of ["eiscid", "ai_tool", "model"]) {
5394
5397
  requireValue(args, key, operation);
5395
5398
  }
5399
+ if (!String(runtime.apiKeyLastFour || "").trim()) {
5400
+ throw new Error("SkillInvoiceIssue requires the configured MCP API Key.");
5401
+ }
5396
5402
  if (args.payload === void 0 && !args.payload_path) {
5397
5403
  throw new Error("SkillInvoiceIssue requires payload or payload_path.");
5398
5404
  }
@@ -5401,7 +5407,9 @@ async function runInvoiceApi(runtimeProvider, args) {
5401
5407
  const command = [script, "--action", operation];
5402
5408
  appendApiArguments(command, args);
5403
5409
  if (payloadPath) command.push("--payload-path", String(payloadPath));
5404
- if (operation === "SkillInvoiceIssue") command.push("--issue-confirm", "1");
5410
+ if (operation === "SkillInvoiceIssue") {
5411
+ command.push("--api-key-last-four", runtime.apiKeyLastFour, "--issue-confirm", "1");
5412
+ }
5405
5413
  return runProcess(runtime.python, command, {
5406
5414
  cwd: runtime.runtimeRoot,
5407
5415
  env: runtime.env,
@@ -5425,8 +5433,160 @@ async function runInvoiceHelper(runtimeProvider, args) {
5425
5433
  }
5426
5434
  var invoiceHelperNames = Object.freeze(Object.keys(INVOICE_HELPERS));
5427
5435
 
5436
+ // src/server.js
5437
+ var import_runtime_core3 = __toESM(require_runtime_core(), 1);
5438
+
5428
5439
  // src/runtime-manager.js
5429
5440
  var import_runtime_core2 = __toESM(require_runtime_core(), 1);
5441
+
5442
+ // src/runtime-auth.js
5443
+ var API_KEY_ENVIRONMENT_VARIABLE = "LEMONCLAW_API_KEY";
5444
+ var ENSURE_API_KEY_PROGRAM = String.raw`
5445
+ import base64
5446
+ import ctypes
5447
+ import hmac
5448
+ import json
5449
+ import os
5450
+ import sys
5451
+ from pathlib import Path
5452
+
5453
+ skill_root = sys.argv[1]
5454
+ sys.path.insert(0, skill_root)
5455
+ from auth import auth as lemon_auth
5456
+
5457
+
5458
+ def credential_path():
5459
+ if os.name == "nt":
5460
+ appdata = os.environ.get("APPDATA")
5461
+ return Path(appdata) / "LemonAuthAgent" / "api-key.dat" if appdata else None
5462
+ config_root = os.environ.get("XDG_CONFIG_HOME")
5463
+ root = Path(config_root) if config_root else Path.home() / ".config"
5464
+ return root / "lemon-auth-agent" / "api-key.dat"
5465
+
5466
+
5467
+ def unprotect_windows(value):
5468
+ try:
5469
+ from ctypes import wintypes
5470
+
5471
+ encrypted = base64.b64decode(value.strip(), validate=True)
5472
+ if not encrypted:
5473
+ return None
5474
+
5475
+ class DataBlob(ctypes.Structure):
5476
+ _fields_ = [
5477
+ ("cbData", wintypes.DWORD),
5478
+ ("pbData", ctypes.POINTER(ctypes.c_ubyte)),
5479
+ ]
5480
+
5481
+ source_buffer = (ctypes.c_ubyte * len(encrypted)).from_buffer_copy(encrypted)
5482
+ source = DataBlob(
5483
+ len(encrypted), ctypes.cast(source_buffer, ctypes.POINTER(ctypes.c_ubyte))
5484
+ )
5485
+ target = DataBlob()
5486
+ crypt32 = ctypes.WinDLL("crypt32", use_last_error=True)
5487
+ crypt32.CryptUnprotectData.argtypes = [
5488
+ ctypes.POINTER(DataBlob),
5489
+ ctypes.c_void_p,
5490
+ ctypes.c_void_p,
5491
+ ctypes.c_void_p,
5492
+ ctypes.c_void_p,
5493
+ wintypes.DWORD,
5494
+ ctypes.POINTER(DataBlob),
5495
+ ]
5496
+ crypt32.CryptUnprotectData.restype = wintypes.BOOL
5497
+ if not crypt32.CryptUnprotectData(
5498
+ ctypes.byref(source), None, None, None, None, 1, ctypes.byref(target)
5499
+ ):
5500
+ return None
5501
+ try:
5502
+ return ctypes.string_at(target.pbData, target.cbData).decode("utf-8")
5503
+ finally:
5504
+ kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
5505
+ kernel32.LocalFree.argtypes = [ctypes.c_void_p]
5506
+ kernel32.LocalFree.restype = ctypes.c_void_p
5507
+ kernel32.LocalFree(ctypes.cast(target.pbData, ctypes.c_void_p))
5508
+ except Exception:
5509
+ return None
5510
+
5511
+
5512
+ def current_api_key():
5513
+ path = credential_path()
5514
+ if path is None or not path.is_file():
5515
+ return None
5516
+ try:
5517
+ stored = path.read_text(encoding="utf-8").strip()
5518
+ except (OSError, UnicodeError):
5519
+ return None
5520
+ if not stored:
5521
+ return None
5522
+ return unprotect_windows(stored) if os.name == "nt" else stored
5523
+
5524
+
5525
+ api_key = sys.stdin.read().strip()
5526
+ if not api_key:
5527
+ print(json.dumps({"ok": False, "error": "missing_api_key", "message": "Missing LEMONCLAW_API_KEY."}))
5528
+ raise SystemExit(2)
5529
+
5530
+ existing = current_api_key()
5531
+ if existing is not None and hmac.compare_digest(existing, api_key):
5532
+ result = {"ok": True, "data": {"saved": False, "unchanged": True}}
5533
+ else:
5534
+ result = lemon_auth.save_api_key(api_key)
5535
+
5536
+ print(json.dumps(result, ensure_ascii=False, separators=(",", ":")))
5537
+ `;
5538
+ function withoutApiKey(environment = {}) {
5539
+ const sanitized = { ...environment };
5540
+ delete sanitized[API_KEY_ENVIRONMENT_VARIABLE];
5541
+ return sanitized;
5542
+ }
5543
+ function authenticationFailure(result) {
5544
+ if (result.timedOut) return "LemonClaw API Key setup timed out.";
5545
+ if (result.outputLimitExceeded) return "LemonClaw API Key setup returned too much output.";
5546
+ if (result.spawnError) return `Unable to start LemonClaw authentication: ${result.spawnError.message}`;
5547
+ return String(result.stderr || result.stdout || "LemonClaw API Key setup failed.").trim().slice(0, 2e3);
5548
+ }
5549
+ async function ensureRuntimeApiKey(runtime, options = {}) {
5550
+ if (!runtime?.python || !runtime?.runtimeRoot || !runtime?.skillRoot) {
5551
+ throw new Error("Resolved Runtime environment is incomplete.");
5552
+ }
5553
+ const sourceEnvironment = options.env || process.env;
5554
+ const apiKey = String(sourceEnvironment[API_KEY_ENVIRONMENT_VARIABLE] || "").trim();
5555
+ if (!apiKey) {
5556
+ throw new Error(
5557
+ `Missing ${API_KEY_ENVIRONMENT_VARIABLE}. Configure it in the LemonClaw MCP environment and reconnect.`
5558
+ );
5559
+ }
5560
+ const run = options.run || runProcess;
5561
+ const result = await run(runtime.python, ["-c", ENSURE_API_KEY_PROGRAM, runtime.skillRoot], {
5562
+ cwd: runtime.runtimeRoot,
5563
+ env: withoutApiKey(runtime.env),
5564
+ stdin: apiKey,
5565
+ timeoutMs: Math.max(1, Number(options.timeoutMs || 6e4))
5566
+ });
5567
+ if (result.code !== 0 || result.timedOut || result.outputLimitExceeded || result.spawnError) {
5568
+ throw new Error(authenticationFailure(result));
5569
+ }
5570
+ let payload;
5571
+ try {
5572
+ payload = JSON.parse(String(result.stdout || "").trim());
5573
+ } catch {
5574
+ throw new Error("LemonClaw authentication returned an invalid response.");
5575
+ }
5576
+ if (payload?.ok !== true) {
5577
+ throw new Error(String(payload?.message || payload?.error || "LemonClaw API Key setup failed."));
5578
+ }
5579
+ return {
5580
+ apiKeyLastFour: apiKey.slice(-4),
5581
+ saved: payload?.data?.saved === true,
5582
+ unchanged: payload?.data?.unchanged === true
5583
+ };
5584
+ }
5585
+ function removeApiKeyFromEnvironment(environment) {
5586
+ return withoutApiKey(environment);
5587
+ }
5588
+
5589
+ // src/runtime-manager.js
5430
5590
  var { publicError } = import_runtime_core2.default.errors;
5431
5591
  var {
5432
5592
  bootstrapRuntime,
@@ -5464,6 +5624,8 @@ function createRuntimeManager(options = {}) {
5464
5624
  };
5465
5625
  const run = options.runProcess || runProcess;
5466
5626
  const makeEnvironment = options.resolveRuntimeEnvironment || resolveRuntimeEnvironment;
5627
+ const ensureApiKey = options.ensureRuntimeApiKey || ensureRuntimeApiKey;
5628
+ let authenticationQueue = Promise.resolve();
5467
5629
  install.cleanupAbandonedInstallLock({ env });
5468
5630
  async function resolveDescriptor(mode = "current-or-install") {
5469
5631
  if (mode === "auto") return install.maybeAutoUpdate({ env });
@@ -5472,7 +5634,18 @@ function createRuntimeManager(options = {}) {
5472
5634
  return install.bootstrapRuntime({ env, waitForPeer: true });
5473
5635
  }
5474
5636
  async function resolveEnvironment(mode = "current-or-install") {
5475
- return makeEnvironment(await resolveDescriptor(mode), env);
5637
+ const runtime = await makeEnvironment(await resolveDescriptor(mode), env);
5638
+ const authenticationTask = authenticationQueue.then(() => ensureApiKey(runtime, { env, run }));
5639
+ authenticationQueue = authenticationTask.then(
5640
+ () => void 0,
5641
+ () => void 0
5642
+ );
5643
+ const authentication = await authenticationTask;
5644
+ return {
5645
+ ...runtime,
5646
+ apiKeyLastFour: authentication.apiKeyLastFour,
5647
+ env: removeApiKeyFromEnvironment(runtime.env)
5648
+ };
5476
5649
  }
5477
5650
  async function runCli(args, runOptions = {}) {
5478
5651
  try {
@@ -5491,47 +5664,6 @@ function createRuntimeManager(options = {}) {
5491
5664
  return { resolveDescriptor, resolveEnvironment, runCli };
5492
5665
  }
5493
5666
 
5494
- // src/runtime-auth.js
5495
- var AUTH_PROGRAM = String.raw`
5496
- import json
5497
- import sys
5498
-
5499
- operation = sys.argv[1]
5500
- skill_root = sys.argv[2]
5501
- sys.path.insert(0, skill_root)
5502
- from auth import auth as lemon_auth
5503
-
5504
- if operation == "status":
5505
- result = lemon_auth.auth_status()
5506
- elif operation == "save_api_key":
5507
- result = lemon_auth.save_api_key(sys.stdin.read())
5508
- elif operation == "clear":
5509
- result = lemon_auth.clear_auth()
5510
- else:
5511
- raise SystemExit("unsupported auth operation")
5512
-
5513
- print(json.dumps(result, ensure_ascii=False, separators=(",", ":")))
5514
- `;
5515
- async function runRuntimeAuth(runtimeProvider, args, options = {}) {
5516
- const resolveRuntime = options.resolveRuntime || runtimeProvider;
5517
- const run = options.run || runProcess;
5518
- if (typeof resolveRuntime !== "function") throw new Error("Runtime provider is required.");
5519
- const runtime = await resolveRuntime("current-or-install");
5520
- const operation = String(args.operation || "");
5521
- if (!["status", "save_api_key", "clear"].includes(operation)) {
5522
- throw new Error("Unsupported Runtime authentication operation.");
5523
- }
5524
- if (operation === "save_api_key" && !String(args.api_key || "").trim()) {
5525
- throw new Error("API Key is required.");
5526
- }
5527
- return run(runtime.python, ["-c", AUTH_PROGRAM, operation, runtime.skillRoot], {
5528
- cwd: runtime.runtimeRoot,
5529
- env: runtime.env,
5530
- stdin: operation === "save_api_key" ? String(args.api_key) : void 0,
5531
- timeoutMs: Math.max(1, Number(args.timeout_seconds || 60)) * 1e3
5532
- });
5533
- }
5534
-
5535
5667
  // src/tool-result.js
5536
5668
  function publicFailure(result) {
5537
5669
  if (result.timedOut) return "LemonClaw command timed out.";
@@ -5566,8 +5698,8 @@ function toolError(error) {
5566
5698
  }
5567
5699
 
5568
5700
  // src/server.js
5569
- var productSchema = z.enum(["acc", "scm", "erp"]);
5570
- var timeoutSchema = z.number().int().min(1).max(600).default(120);
5701
+ var productSchema = z.enum(["acc", "scm", "erp"]).describe("\u4E1A\u52A1\u4EA7\u54C1\uFF1Aacc=\u8D22\u52A1\uFF0Cscm=\u8FDB\u9500\u5B58\uFF0Cerp=\u4E1A\u8D22\uFF1B\u5FC5\u987B\u4E0E\u5F53\u524D\u6240\u9009\u8D26\u5957\u4EA7\u54C1\u4E00\u81F4\u3002");
5702
+ var timeoutSchema = z.number().int().min(1).max(600).default(120).describe("\u672C\u6B21\u64CD\u4F5C\u7684\u8D85\u65F6\u65F6\u95F4\uFF0C\u5355\u4F4D\u4E3A\u79D2\uFF0C\u53D6\u503C\u8303\u56F4 1 \u81F3 600\u3002");
5571
5703
  var optionalText = z.string().min(1).optional();
5572
5704
  var readOnlyAnnotations = {
5573
5705
  readOnlyHint: true,
@@ -5602,76 +5734,9 @@ function createLemonClawServer(options = {}) {
5602
5734
  const runCli = options.runCli || runtimeManager.runCli;
5603
5735
  const resolveRuntime = options.resolveRuntime || runtimeManager.resolveEnvironment;
5604
5736
  const server = new import_server.McpServer(
5605
- { name: "lemonclaw", version: "0.1.2" },
5606
- {
5607
- instructions: "Use standard API Key authentication: check lemon_auth_status and, when unavailable, request the user's API Key and pass it only to lemon_auth_save_api_key. Never use browser or device-flow authentication. For ACC, SCM, and ERP, determine the product and account first, then use lemon_action_search, lemon_action_show, read every document exposed by show with lemon_action_read_doc, and only then call lemon_action_run. Never guess action parameters. Independent invoicing uses only the lemon_invoice_* tools and requires its Runtime documents."
5608
- }
5609
- );
5610
- server.registerTool(
5611
- "lemon_auth_status",
5612
- {
5613
- title: "Check LemonClaw API Key authentication",
5614
- description: "Check whether the current user's standard LemonClaw API Key can provide a token. This uses the Runtime authentication helper and never returns the API Key or token.",
5615
- inputSchema: z.object({
5616
- timeout_seconds: z.number().int().min(1).max(120).default(60)
5617
- }),
5618
- annotations: readOnlyAnnotations
5619
- },
5620
- async (args) => {
5621
- try {
5622
- return cliToolResult(await runRuntimeAuth(resolveRuntime, { ...args, operation: "status" }));
5623
- } catch (error) {
5624
- return toolError(error);
5625
- }
5626
- }
5627
- );
5628
- server.registerTool(
5629
- "lemon_auth_save_api_key",
5630
- {
5631
- title: "Save LemonClaw API Key",
5632
- description: "Save an API Key with the standard Runtime authentication helper for the current operating-system user. The key is sent to Runtime through stdin, is not placed in process arguments, and is never returned.",
5633
- inputSchema: z.object({
5634
- api_key: z.string().min(1),
5635
- timeout_seconds: z.number().int().min(1).max(120).default(60)
5636
- }),
5637
- annotations: {
5638
- readOnlyHint: false,
5639
- destructiveHint: false,
5640
- idempotentHint: false,
5641
- openWorldHint: false
5642
- }
5643
- },
5644
- async (args) => {
5645
- try {
5646
- return cliToolResult(
5647
- await runRuntimeAuth(resolveRuntime, { ...args, operation: "save_api_key" })
5648
- );
5649
- } catch (error) {
5650
- return toolError(error);
5651
- }
5652
- }
5653
- );
5654
- server.registerTool(
5655
- "lemon_auth_clear",
5737
+ { name: "lemonclaw", version: import_runtime_core3.default.packageVersion },
5656
5738
  {
5657
- title: "Clear LemonClaw API Key authentication",
5658
- description: "Clear the current user's standard LemonClaw API Key and token cache without clearing account context. Use only when the user explicitly requests it.",
5659
- inputSchema: z.object({
5660
- timeout_seconds: z.number().int().min(1).max(120).default(60)
5661
- }),
5662
- annotations: {
5663
- readOnlyHint: false,
5664
- destructiveHint: true,
5665
- idempotentHint: true,
5666
- openWorldHint: false
5667
- }
5668
- },
5669
- async (args) => {
5670
- try {
5671
- return cliToolResult(await runRuntimeAuth(resolveRuntime, { ...args, operation: "clear" }));
5672
- } catch (error) {
5673
- return toolError(error);
5674
- }
5739
+ instructions: "LemonClaw \u7684 API Key \u4EC5\u7531 MCP \u670D\u52A1\u73AF\u5883\u53D8\u91CF\u63D0\u4F9B\uFF0C\u4E0D\u5F97\u5728\u5BF9\u8BDD\u6216 Tool \u53C2\u6570\u4E2D\u7D22\u53D6\u3001\u63A5\u6536\u3001\u5C55\u793A\u6216\u4F20\u9012\u3002\u7528\u6237\u660E\u786E\u63D0\u5230\u4E91\u53D1\u7968\u3001\u4E91\u53D1\u7968\u4EA7\u54C1\u3001\u72EC\u7ACB\u5F00\u7968\u3001\u7A0E\u7968\u5E73\u53F0\u3001\u7ACB\u5373\u5F00\u7968\u3001\u6279\u91CF\u5F00\u7968\u3001\u5F00\u7968\u9884\u89C8\u3001\u9500\u65B9\u4F01\u4E1A\u3001\u53EF\u5F00\u7968\u4F01\u4E1A\u6216\u4E91\u53D1\u7968\u4E0B\u7684\u4F01\u4E1A/\u8D26\u5957\u65F6\uFF0C\u5FC5\u987B\u8FDB\u5165\u72EC\u7ACB\u5F00\u7968\u6D41\u7A0B\uFF0C\u53EA\u4F7F\u7528 lemon_invoice_* Tools\uFF0C\u5E76\u5148\u8BFB\u53D6 Runtime \u5F00\u7968\u6587\u6863\uFF1B\u5176\u4E2D\u67E5\u8BE2\u4E91\u53D1\u7968\u4F01\u4E1A\u3001\u8D26\u5957\u3001\u9500\u65B9\u6216\u53EF\u5F00\u7968\u4E3B\u4F53\u56FA\u5B9A\u4F7F\u7528 lemon_invoice_api \u7684 CompanyFullList\uFF0C\u7981\u6B62\u8C03\u7528 lemon_account_list\u3002\u4EC5\u67E5\u8BE2\u8FDB\u9879\u53D1\u7968\u3001\u9500\u9879\u53D1\u7968\u3001\u53D1\u7968\u8BE6\u60C5\u3001\u5BFC\u51FA\u6216\u7EDF\u8BA1\u4E14\u672A\u660E\u786E\u4E91\u53D1\u7968\u4EA7\u54C1\u65F6\uFF0C\u624D\u6309 ACC/ERP \u666E\u901A\u4E1A\u52A1\u5904\u7406\u3002\u5904\u7406 ACC\u3001SCM\u3001ERP \u4E1A\u52A1\u524D\uFF0C\u5148\u786E\u5B9A\u4EA7\u54C1\u5E76\u83B7\u53D6\u6216\u5207\u6362\u8D26\u5957\uFF1B\u968F\u540E\u4F9D\u6B21\u8C03\u7528 lemon_action_search\u3001lemon_action_show\u3001lemon_action_read_doc \u8BFB\u53D6 show \u8FD4\u56DE\u7684\u5168\u90E8\u5B9E\u9645\u6587\u6863\uFF0C\u6700\u540E\u624D\u53EF\u8C03\u7528 lemon_action_run\uFF0C\u4E25\u7981\u731C\u6D4B Action \u548C\u53C2\u6570\u3002Runtime \u6587\u6863\u4E2D\u4EFB\u4F55\u8981\u6C42\u6536\u96C6\u6216\u4FDD\u5B58 API Key \u7684\u65E7\u6307\u5F15\u5747\u4E0D\u9002\u7528\u4E8E MCP\uFF0C\u56E0\u4E3A\u6BCF\u6B21 Tool \u8C03\u7528\u524D\u90FD\u5DF2\u5728\u5185\u90E8\u5B8C\u6210\u8BA4\u8BC1\u3002"
5675
5740
  }
5676
5741
  );
5677
5742
  registerCliTool(
@@ -5679,8 +5744,8 @@ function createLemonClawServer(options = {}) {
5679
5744
  runCli,
5680
5745
  "lemon_account_current",
5681
5746
  {
5682
- title: "Get current Lemon account context",
5683
- description: "Read the current product and selected account set from the existing local account context. Call this before ACC, SCM, or ERP business actions.",
5747
+ title: "\u83B7\u53D6\u5F53\u524D\u67E0\u6AAC\u4E91\u8D26\u5957",
5748
+ description: "\u83B7\u53D6\u5F53\u524D\u9009\u4E2D\u7684\u67E0\u6AAC\u4E91\u4EA7\u54C1\u548C\u8D26\u5957\u4FE1\u606F\u3002\u6267\u884C ACC \u8D22\u52A1\u3001SCM \u8FDB\u9500\u5B58\u6216 ERP \u4E1A\u8D22\u4E1A\u52A1\u524D\u5E94\u5148\u8C03\u7528\u672C\u5DE5\u5177\uFF0C\u4EE5\u786E\u8BA4\u540E\u7EED Action \u4F7F\u7528\u7684 product \u4E0E\u5F53\u524D\u8D26\u5957\u4E00\u81F4\uFF1B\u672C\u5DE5\u5177\u4E0D\u4F1A\u5207\u6362\u6216\u4FEE\u6539\u8D26\u5957\u3002",
5684
5749
  inputSchema: z.object({ timeout_seconds: timeoutSchema }),
5685
5750
  annotations: readOnlyAnnotations
5686
5751
  },
@@ -5694,10 +5759,10 @@ function createLemonClawServer(options = {}) {
5694
5759
  runCli,
5695
5760
  "lemon_account_list",
5696
5761
  {
5697
- title: "List Lemon account sets",
5698
- description: "List account-set candidates and cache their returned indexes for a later lemon_account_select call. Use only when switch has no usable candidates or the user asks to list accounts.",
5762
+ title: "\u5217\u51FA\u67E0\u6AAC\u4E91\u8D26\u5957",
5763
+ description: "\u4EC5\u5217\u51FA ACC \u8D22\u52A1\u3001SCM \u8FDB\u9500\u5B58\u548C ERP \u4E1A\u8D22\u8D26\u5957\uFF0C\u5E76\u7F13\u5B58\u5019\u9009\u5E8F\u53F7\u4F9B lemon_account_select \u4F7F\u7528\u3002\u672C\u5DE5\u5177\u4E0D\u8FD4\u56DE\u4E91\u53D1\u7968\u4F01\u4E1A\u3001\u4E91\u53D1\u7968\u8D26\u5957\u3001\u9500\u65B9\u4F01\u4E1A\u6216\u53EF\u5F00\u7968\u4E3B\u4F53\uFF1B\u7528\u6237\u660E\u786E\u63D0\u5230\u4E91\u53D1\u7968\u6216\u72EC\u7ACB\u5F00\u7968\u65F6\u7981\u6B62\u8C03\u7528\u672C\u5DE5\u5177\uFF0C\u5E94\u6539\u7528 lemon_invoice_api \u7684 CompanyFullList\u3002\u4EC5\u5F53 lemon_account_switch \u6CA1\u6709\u53EF\u7528\u5019\u9009\uFF0C\u6216\u7528\u6237\u660E\u786E\u67E5\u770B ACC/SCM/ERP \u8D26\u5957\u65F6\u8C03\u7528\u3002",
5699
5764
  inputSchema: z.object({
5700
- dry_run: z.boolean().default(false),
5765
+ dry_run: z.boolean().default(false).describe("\u662F\u5426\u4EC5\u68C0\u67E5\u6D41\u7A0B\u800C\u4E0D\u5B9E\u9645\u66F4\u65B0\u672C\u5730\u5019\u9009\u7F13\u5B58\u3002"),
5701
5766
  timeout_seconds: timeoutSchema
5702
5767
  }),
5703
5768
  annotations: readOnlyAnnotations
@@ -5713,16 +5778,16 @@ function createLemonClawServer(options = {}) {
5713
5778
  runCli,
5714
5779
  "lemon_account_switch",
5715
5780
  {
5716
- title: "Switch Lemon account context",
5717
- description: "Match a product or account clue and switch when unique. If candidates are returned, present them to the user and select from that same candidate set; do not refresh it with account list.",
5781
+ title: "\u5339\u914D\u5E76\u5207\u6362\u67E0\u6AAC\u4E91\u8D26\u5957",
5782
+ description: "\u6839\u636E\u4EA7\u54C1\u3001\u8D26\u5957\u540D\u79F0\u3001\u7F16\u53F7\u6216\u7248\u672C\u7B49\u7EBF\u7D22\u5339\u914D\u5E76\u5207\u6362\u67E0\u6AAC\u4E91\u8D26\u5957\u3002\u552F\u4E00\u5339\u914D\u65F6\u53EF\u76F4\u63A5\u5207\u6362\uFF1B\u8FD4\u56DE\u591A\u4E2A\u5019\u9009\u65F6\uFF0C\u5E94\u5411\u7528\u6237\u5C55\u793A\u5E76\u901A\u8FC7 lemon_account_select \u4ECE\u540C\u4E00\u6279\u5019\u9009\u4E2D\u9009\u62E9\uFF0C\u4E0D\u8981\u8C03\u7528 lemon_account_list \u5237\u65B0\u5019\u9009\u3002",
5718
5783
  inputSchema: z.object({
5719
- query: optionalText,
5784
+ query: optionalText.describe("\u7528\u4E8E\u5339\u914D\u4EA7\u54C1\u3001\u8D26\u5957\u540D\u79F0\u3001\u7F16\u53F7\u6216\u7248\u672C\u7684\u7528\u6237\u7EBF\u7D22\u3002"),
5720
5785
  product: productSchema.optional(),
5721
5786
  asid: optionalText,
5722
5787
  serviceid: optionalText,
5723
5788
  name: optionalText,
5724
5789
  edition: optionalText,
5725
- dry_run: z.boolean().default(false),
5790
+ dry_run: z.boolean().default(false).describe("\u662F\u5426\u53EA\u9884\u89C8\u5339\u914D\u7ED3\u679C\u800C\u4E0D\u5B9E\u9645\u5207\u6362\u8D26\u5957\u3002"),
5726
5791
  timeout_seconds: timeoutSchema
5727
5792
  }),
5728
5793
  annotations: {
@@ -5750,10 +5815,10 @@ function createLemonClawServer(options = {}) {
5750
5815
  runCli,
5751
5816
  "lemon_account_select",
5752
5817
  {
5753
- title: "Select a Lemon account set",
5754
- description: "Select from the candidates cached by the most recent account switch or list. Prefer the returned index. Never invent an index or silently choose between duplicate names.",
5818
+ title: "\u9009\u62E9\u67E0\u6AAC\u4E91\u8D26\u5957\u5019\u9009",
5819
+ description: "\u4ECE\u6700\u8FD1\u4E00\u6B21 lemon_account_switch \u6216 lemon_account_list \u7F13\u5B58\u7684\u5019\u9009\u4E2D\u9009\u62E9\u8D26\u5957\u3002\u4F18\u5148\u4F7F\u7528\u5019\u9009\u8FD4\u56DE\u7684 index\uFF0C\u5E76\u4FDD\u6301\u5019\u9009\u4E2D\u7684 product \u548C\u6807\u8BC6\u4E0D\u53D8\uFF1B\u4E0D\u5F97\u7F16\u9020\u5E8F\u53F7\uFF0C\u4E5F\u4E0D\u5F97\u5728\u91CD\u540D\u8D26\u5957\u4E4B\u95F4\u9759\u9ED8\u9009\u62E9\u3002",
5755
5820
  inputSchema: z.object({
5756
- index: z.number().int().positive().optional(),
5821
+ index: z.number().int().positive().optional().describe("\u6700\u8FD1\u4E00\u6B21\u5019\u9009\u5217\u8868\u8FD4\u56DE\u7684\u5E8F\u53F7\u3002"),
5757
5822
  product: productSchema.optional(),
5758
5823
  asid: optionalText,
5759
5824
  serviceid: optionalText,
@@ -5761,7 +5826,7 @@ function createLemonClawServer(options = {}) {
5761
5826
  timeout_seconds: timeoutSchema
5762
5827
  }).refine(
5763
5828
  (value) => value.index !== void 0 || value.asid || value.serviceid || value.name,
5764
- "Provide index, asid, serviceid, or name from the latest candidate set."
5829
+ "\u5FC5\u987B\u63D0\u4F9B\u6700\u8FD1\u4E00\u6B21\u5019\u9009\u5217\u8868\u4E2D\u7684 index\u3001asid\u3001serviceid \u6216 name\u3002"
5765
5830
  ),
5766
5831
  annotations: {
5767
5832
  readOnlyHint: false,
@@ -5786,11 +5851,11 @@ function createLemonClawServer(options = {}) {
5786
5851
  runCli,
5787
5852
  "lemon_account_clear",
5788
5853
  {
5789
- title: "Clear Lemon account context",
5790
- description: "Clear saved account context without clearing authentication. Use all_products only when the user explicitly requests clearing every product context.",
5854
+ title: "\u6E05\u9664\u67E0\u6AAC\u4E91\u8D26\u5957\u4E0A\u4E0B\u6587",
5855
+ description: "\u6E05\u9664\u5DF2\u4FDD\u5B58\u7684\u67E0\u6AAC\u4E91\u8D26\u5957\u4E0A\u4E0B\u6587\uFF0C\u4F46\u4E0D\u4F1A\u6E05\u9664 API Key \u6216\u8BA4\u8BC1\u4FE1\u606F\u3002\u9ED8\u8BA4\u4EC5\u6E05\u9664\u6307\u5B9A\u6216\u5F53\u524D\u4EA7\u54C1\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u8981\u6C42\u6E05\u9664\u5168\u90E8\u4EA7\u54C1\u8D26\u5957\u65F6\uFF0C\u624D\u53EF\u5C06 all_products \u8BBE\u4E3A true\u3002",
5791
5856
  inputSchema: z.object({
5792
5857
  product: productSchema.optional(),
5793
- all_products: z.boolean().default(false),
5858
+ all_products: z.boolean().default(false).describe("\u662F\u5426\u6E05\u9664 ACC\u3001SCM\u3001ERP \u7684\u5168\u90E8\u8D26\u5957\u4E0A\u4E0B\u6587\u3002"),
5794
5859
  timeout_seconds: timeoutSchema
5795
5860
  }),
5796
5861
  annotations: {
@@ -5813,12 +5878,12 @@ function createLemonClawServer(options = {}) {
5813
5878
  runCli,
5814
5879
  "lemon_action_search",
5815
5880
  {
5816
- title: "Search Lemon business actions",
5817
- description: "Search for ACC, SCM, or ERP action candidates in one explicit product. Search does not select an action, create parameters, or execute business requests.",
5881
+ title: "\u641C\u7D22\u67E0\u6AAC\u4E91\u4E1A\u52A1\u80FD\u529B",
5882
+ description: "\u5728\u6307\u5B9A\u7684\u67E0\u6AAC\u4E91 ACC\u3001SCM \u6216 ERP \u4EA7\u54C1\u4E2D\u641C\u7D22\u4E0E\u7528\u6237\u9700\u6C42\u5339\u914D\u7684\u4E1A\u52A1\u80FD\u529B\u3002\u53EF\u641C\u7D22\u5BA2\u6237\u3001\u4F9B\u5E94\u5546\u3001\u5546\u54C1\u3001\u4ED3\u5E93\u7B49\u57FA\u7840\u8D44\u6599\uFF0C\u4EE5\u53CA\u91C7\u8D2D\u8BA2\u5355\u3001\u9500\u552E\u8BA2\u5355\u3001\u5E93\u5B58\u3001\u6536\u4ED8\u6B3E\u3001\u5F80\u6765\u3001\u51ED\u8BC1\u3001\u8D26\u7C3F\u3001\u53D1\u7968\u548C\u7ECF\u8425\u6216\u8D22\u52A1\u62A5\u8868\u7B49\u80FD\u529B\uFF1BERP \u8FD8\u8986\u76D6\u9500\u552E\u62A5\u4EF7\u3001\u4EF7\u683C\u8D44\u6599\u3001\u8BA2\u5355\u6C47\u603B\u3001\u5E93\u5B58\u8D26\u9F84\u3001\u6682\u4F30\u8C03\u6574\u548C\u5E94\u6536\u5E94\u4ED8\u9884\u8B66\u3002\u672C\u5DE5\u5177\u53EA\u8FD4\u56DE\u5F53\u524D\u4EA7\u54C1\u7684 Action \u5019\u9009\uFF0C\u4E0D\u9009\u62E9 Action\u3001\u4E0D\u751F\u6210\u4E1A\u52A1\u53C2\u6570\uFF0C\u4E5F\u4E0D\u6267\u884C\u67E5\u8BE2\u6216\u5199\u64CD\u4F5C\u3002",
5818
5883
  inputSchema: z.object({
5819
5884
  product: productSchema,
5820
- query: z.string().min(1),
5821
- limit: z.number().int().min(1).max(20).default(5)
5885
+ query: z.string().min(1).describe("\u7528\u6237\u7684\u81EA\u7136\u8BED\u8A00\u4E1A\u52A1\u9700\u6C42\uFF0C\u4F8B\u5982\u201C\u67E5\u8BE2\u672C\u6708\u91C7\u8D2D\u8BA2\u5355\u201D\u3002"),
5886
+ limit: z.number().int().min(1).max(20).default(5).describe("\u6700\u591A\u8FD4\u56DE\u7684\u5019\u9009\u6570\u91CF\u3002")
5822
5887
  }),
5823
5888
  annotations: readOnlyAnnotations
5824
5889
  },
@@ -5840,11 +5905,11 @@ function createLemonClawServer(options = {}) {
5840
5905
  runCli,
5841
5906
  "lemon_action_show",
5842
5907
  {
5843
- title: "Show a Lemon business action",
5844
- description: "Show one action's public contract and the documents that actually exist. A successful show does not prove the action is the unique semantic match.",
5908
+ title: "\u67E5\u770B\u67E0\u6AAC\u4E91\u4E1A\u52A1\u80FD\u529B\u5951\u7EA6",
5909
+ description: "\u67E5\u770B\u6307\u5B9A\u67E0\u6AAC\u4E91\u4E1A\u52A1 Action \u7684\u516C\u5F00\u8C03\u7528\u5951\u7EA6\u3001\u53C2\u6570\u7ED3\u6784\u53CA\u5B9E\u9645\u5B58\u5728\u7684\u8BF4\u660E\u6587\u6863\u3002\u67E5\u770B\u6210\u529F\u4E0D\u4EE3\u8868\u8BE5 Action \u5DF2\u7ECF\u662F\u7528\u6237\u9700\u6C42\u7684\u552F\u4E00\u5339\u914D\uFF1B\u5B58\u5728\u591A\u4E2A\u5408\u7406\u5019\u9009\u65F6\u4ECD\u9700\u7EE7\u7EED\u6BD4\u8F83\uFF0C\u5FC5\u8981\u65F6\u8BF7\u7528\u6237\u786E\u8BA4\u3002",
5845
5910
  inputSchema: z.object({
5846
5911
  product: productSchema,
5847
- action: z.string().min(1)
5912
+ action: z.string().min(1).describe("lemon_action_search \u5019\u9009\u8FD4\u56DE\u7684\u7CBE\u786E Action \u540D\u79F0\u3002")
5848
5913
  }),
5849
5914
  annotations: readOnlyAnnotations
5850
5915
  },
@@ -5858,12 +5923,12 @@ function createLemonClawServer(options = {}) {
5858
5923
  runCli,
5859
5924
  "lemon_action_read_doc",
5860
5925
  {
5861
- title: "Read a Lemon business action document",
5862
- description: "Read one registered ACTION, input, or output Markdown document. Read every document exposed by lemon_action_show for the final selected action before run.",
5926
+ title: "\u8BFB\u53D6\u67E0\u6AAC\u4E91\u4E1A\u52A1\u80FD\u529B\u6587\u6863",
5927
+ description: "\u8BFB\u53D6\u6307\u5B9A\u4E1A\u52A1 Action \u5DF2\u6CE8\u518C\u7684\u529F\u80FD\u8BF4\u660E\u3001\u8F93\u5165\u53C2\u6570\u6216\u8F93\u51FA\u7ED3\u679C\u6587\u6863\u3002\u6700\u7EC8\u9009\u62E9 Action \u540E\uFF0C\u5FC5\u987B\u5728\u6267\u884C\u524D\u8BFB\u53D6 lemon_action_show \u5B9E\u9645\u8FD4\u56DE\u7684\u5168\u90E8\u6587\u6863\uFF0C\u5E76\u4EE5\u6587\u6863\u5B9A\u4E49\u4E3A\u51C6\u6784\u9020\u53C2\u6570\u548C\u5C55\u793A\u7ED3\u679C\uFF1B\u4E0D\u5F97\u731C\u6D4B\u4E0D\u5B58\u5728\u7684\u6587\u6863\u6216\u5B57\u6BB5\u3002",
5863
5928
  inputSchema: z.object({
5864
5929
  product: productSchema,
5865
- action: z.string().min(1),
5866
- document: z.enum(["action", "input", "output"])
5930
+ action: z.string().min(1).describe("\u5DF2\u7ECF\u6838\u9A8C\u7684\u7CBE\u786E Action \u540D\u79F0\u3002"),
5931
+ document: z.enum(["action", "input", "output"]).describe("\u8981\u8BFB\u53D6\u7684\u6587\u6863\u7C7B\u578B\uFF1B\u53EA\u80FD\u9009\u62E9 lemon_action_show \u8FD4\u56DE\u4E3A\u5B9E\u9645\u5B58\u5728\u7684\u7C7B\u578B\u3002")
5867
5932
  }),
5868
5933
  annotations: readOnlyAnnotations
5869
5934
  },
@@ -5884,19 +5949,19 @@ function createLemonClawServer(options = {}) {
5884
5949
  runCli,
5885
5950
  "lemon_action_run",
5886
5951
  {
5887
- title: "Run a Lemon business action",
5888
- description: "Run one already-selected ACC, SCM, or ERP action with its documented nested query/body envelope. This tool never searches, guesses parameters, or executes independent invoicing. Set user_confirmed only after explicit confirmation of a documented write action.",
5952
+ title: "\u67E5\u8BE2\u6216\u6267\u884C\u67E0\u6AAC\u4E91\u4E1A\u52A1\u64CD\u4F5C",
5953
+ description: "\u6267\u884C\u5DF2\u901A\u8FC7\u68C0\u7D22\u548C\u6587\u6863\u6838\u9A8C\u7684\u67E0\u6AAC\u4E91 ACC\u3001SCM \u6216 ERP \u4E1A\u52A1\u64CD\u4F5C\u3002\u652F\u6301\u67E5\u8BE2\u5BA2\u6237\u3001\u4F9B\u5E94\u5546\u3001\u5546\u54C1\u3001\u4ED3\u5E93\u7B49\u57FA\u7840\u8D44\u6599\uFF0C\u4EE5\u53CA\u91C7\u8D2D\u8BA2\u5355\u3001\u9500\u552E\u8BA2\u5355\u3001\u5E93\u5B58\u3001\u6536\u4ED8\u6B3E\u3001\u5F80\u6765\u3001\u51ED\u8BC1\u3001\u8D26\u7C3F\u3001\u53D1\u7968\u548C\u7ECF\u8425\u6216\u8D22\u52A1\u62A5\u8868\uFF1BERP \u8FD8\u652F\u6301\u9500\u552E\u62A5\u4EF7\u3001\u4EF7\u683C\u8D44\u6599\u3001\u8BA2\u5355\u6C47\u603B\u3001\u5E93\u5B58\u8D26\u9F84\u3001\u6682\u4F30\u8C03\u6574\u548C\u5E94\u6536\u5E94\u4ED8\u9884\u8B66\u3002\u5BF9\u4E8E Action \u6587\u6863\u660E\u786E\u652F\u6301\u7684\u65B0\u589E\u3001\u4FEE\u6539\u3001\u63D0\u4EA4\u7B49\u5199\u64CD\u4F5C\uFF0C\u4EC5\u5728\u7528\u6237\u660E\u786E\u786E\u8BA4\u540E\u6267\u884C\u3002\u8C03\u7528\u524D\u5FC5\u987B\u5B8C\u6210 search\u3001show \u548C\u5168\u90E8\u6587\u6863\u8BFB\u53D6\uFF0C\u4E0D\u5F97\u731C\u6D4B\u53C2\u6570\uFF1B\u672C\u5DE5\u5177\u4E0D\u7528\u4E8E\u72EC\u7ACB\u5F00\u7968\u3002",
5889
5954
  inputSchema: z.object({
5890
5955
  product: productSchema,
5891
- action: z.string().min(1),
5956
+ action: z.string().min(1).describe("\u5DF2\u901A\u8FC7 search\u3001show \u548C\u6587\u6863\u6838\u9A8C\u7684\u7CBE\u786E Action \u540D\u79F0\u3002"),
5892
5957
  payload: z.object({
5893
- query: z.record(z.string(), z.unknown()).optional(),
5894
- body: z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())]).optional(),
5895
- _outputMode: z.enum(["basic", "full"]).optional(),
5896
- _extraDisplayFields: z.array(z.string().min(1)).min(1).optional()
5897
- }).strict(),
5898
- user_confirmed: z.boolean().default(false),
5899
- dry_run: z.boolean().default(false),
5958
+ query: z.record(z.string(), z.unknown()).optional().describe("Action \u6587\u6863\u5B9A\u4E49\u7684 URL \u67E5\u8BE2\u53C2\u6570\uFF1B\u65E0\u53C2\u6570\u65F6\u6309\u6587\u6863\u8981\u6C42\u7701\u7565\u6216\u4F20\u7A7A\u5BF9\u8C61\u3002"),
5959
+ body: z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())]).optional().describe("Action \u6587\u6863\u5B9A\u4E49\u7684\u8BF7\u6C42\u4F53\uFF0C\u5FC5\u987B\u4FDD\u6301\u6587\u6863\u89C4\u5B9A\u7684\u5BF9\u8C61\u6216\u6570\u7EC4\u7ED3\u6784\u3002"),
5960
+ _outputMode: z.enum(["basic", "full"]).optional().describe("\u6587\u6863\u5141\u8BB8\u65F6\u9009\u62E9\u57FA\u7840\u7ED3\u679C basic \u6216\u5B8C\u6574\u7ED3\u679C full\u3002"),
5961
+ _extraDisplayFields: z.array(z.string().min(1)).min(1).optional().describe("\u7528\u6237\u660E\u786E\u8981\u6C42\u989D\u5916\u5C55\u793A\u4E14 Action \u6587\u6863\u652F\u6301\u7684\u5B57\u6BB5\u540D\u79F0\u3002")
5962
+ }).strict().describe("\u4E25\u683C\u6309\u7167 Action \u6587\u6863\u6784\u9020\u7684\u5D4C\u5957 query/body \u8BF7\u6C42\u5305\u3002"),
5963
+ user_confirmed: z.boolean().default(false).describe("\u53EA\u6709\u7528\u6237\u660E\u786E\u786E\u8BA4\u8BE5 Action \u6587\u6863\u6807\u6CE8\u7684\u5199\u64CD\u4F5C\u65F6\u624D\u80FD\u8BBE\u4E3A true\u3002"),
5964
+ dry_run: z.boolean().default(false).describe("\u662F\u5426\u4EC5\u6821\u9A8C\u5E76\u9884\u6F14\uFF0C\u800C\u4E0D\u5B9E\u9645\u6267\u884C\u4E1A\u52A1\u8BF7\u6C42\u3002"),
5900
5965
  timeout_seconds: timeoutSchema
5901
5966
  }),
5902
5967
  annotations: {
@@ -5928,10 +5993,10 @@ function createLemonClawServer(options = {}) {
5928
5993
  server.registerTool(
5929
5994
  "lemon_invoice_read_doc",
5930
5995
  {
5931
- title: "Read Lemon independent-invoicing documentation",
5932
- description: "Read a Runtime document relative to the invoice directory. Start with SKILL.md, then read only the immediate, batch, or feedback flow and shared documents it directs you to.",
5996
+ title: "\u8BFB\u53D6\u67E0\u6AAC\u4E91\u53D1\u7968\u4E0E\u72EC\u7ACB\u5F00\u7968\u6587\u6863",
5997
+ description: "\u4E91\u53D1\u7968\u4EA7\u54C1\u3001\u72EC\u7ACB\u5F00\u7968\u548C\u7A0E\u7968\u5E73\u53F0\uFF08\u542B\u5F00\u7968\u52A9\u624B/\u5F00\u7968\u52A9\u7406\uFF09\u7684\u603B\u6D41\u7A0B\u6587\u6863\u5165\u53E3\uFF1B\u672C\u5DE5\u5177\u6309\u76F8\u5BF9\u8DEF\u5F84\u8BFB\u53D6 Runtime \u5F00\u7968\u6587\u6863\uFF0C\u4E0D\u76F4\u63A5\u67E5\u8BE2\u4F01\u4E1A\u6216\u6267\u884C\u5F00\u7968\u3002\u53EA\u8981\u7528\u6237\u660E\u786E\u5904\u4E8E\u4E91\u53D1\u7968\u4EA7\u54C1\uFF0C\u6216\u63D0\u51FA\u67E5\u8BE2\u4E91\u53D1\u7968\u4F01\u4E1A/\u516C\u53F8/\u8D26\u53F7/\u8D26\u5957\u3001\u9500\u65B9/\u8D2D\u65B9/\u5BA2\u6237\u3001\u4F01\u4E1A\u8BE6\u60C5\u3001\u767B\u5F55\u72B6\u6001\u3001\u7A0E\u5C40/\u6570\u7535\u8BA4\u8BC1\u3001\u5269\u4F59\u989D\u5EA6\u3001\u7A0E\u7F16/\u5546\u54C1\u7F16\u7801\u3001\u7ACB\u5373/\u6279\u91CF\u5F00\u7968\u3001\u9884\u89C8/\u786E\u8BA4/\u63D0\u4EA4\u3001\u5BA2\u670D\u6216\u95EE\u9898\u53CD\u9988\uFF0C\u7B2C\u4E00\u6B65\u90FD\u5FC5\u987B\u7528\u672C\u5DE5\u5177\u8BFB\u53D6 SKILL.md\uFF0C\u518D\u6309\u6587\u6863\u4F7F\u7528 lemon_invoice_api \u6216 lemon_invoice_run_helper\uFF0C\u7981\u6B62\u8F6C\u5230 lemon_account_* \u6216 lemon_action_*\u3002\u4EC5\u67E5\u8BE2 ACC/ERP \u8D22\u52A1\u8D26\u5957\u5185\u7684\u8FDB\u9879/\u9500\u9879\u53D1\u7968\u3001\u8BE6\u60C5\u3001\u5BFC\u51FA\u6216\u7EDF\u8BA1\u65F6\u4E0D\u4F7F\u7528\u672C\u5DE5\u5177\u3002",
5933
5998
  inputSchema: z.object({
5934
- path: z.string().min(1).describe("For example SKILL.md or references/immediate/flow.md")
5999
+ path: z.string().min(1).describe("\u5F00\u7968\u76EE\u5F55\u5185\u7684\u76F8\u5BF9\u6587\u6863\u8DEF\u5F84\uFF1B\u9996\u6B21\u8FDB\u5165\u4E91\u53D1\u7968\u6D41\u7A0B\u56FA\u5B9A\u4F20 SKILL.md\uFF0C\u540E\u7EED\u53EA\u8BFB\u53D6\u8BE5\u6587\u6863\u6307\u5411\u7684\u8DEF\u5F84\u3002")
5935
6000
  }),
5936
6001
  annotations: readOnlyAnnotations
5937
6002
  },
@@ -5947,8 +6012,8 @@ function createLemonClawServer(options = {}) {
5947
6012
  server.registerTool(
5948
6013
  "lemon_invoice_api",
5949
6014
  {
5950
- title: "Call the Lemon independent-invoicing API adapter",
5951
- description: "Execute one documented independent-invoicing operation with Runtime Python. Read and follow the invoice documents first. SkillInvoiceIssue is blocked unless user_confirmed is true and required context is supplied.",
6015
+ title: "\u8C03\u7528\u67E0\u6AAC\u4E91\u72EC\u7ACB\u5F00\u7968\u63A5\u53E3",
6016
+ description: "\u8C03\u7528\u4E91\u53D1\u7968\u4EA7\u54C1\uFF08\u72EC\u7ACB\u5F00\u7968/\u7A0E\u7968\u5E73\u53F0\uFF09\u7684\u56FA\u5B9A\u4E1A\u52A1\u63A5\u53E3\u3002\u7528\u6237\u8BE2\u95EE\u4E91\u53D1\u7968\u4E0B\u6709\u54EA\u4E9B\u4F01\u4E1A\u3001\u8D26\u5957\u3001\u9500\u65B9\u6216\u53EF\u5F00\u7968\u4E3B\u4F53\u65F6\uFF0C\u8BFB\u53D6\u6587\u6863\u540E\u56FA\u5B9A\u4F7F\u7528 operation=CompanyFullList\uFF0C\u7981\u6B62\u8C03\u7528 lemon_account_list\u3002\u5176\u4ED6 operation \u7528\u4E8E\u516C\u53F8\u8BE6\u60C5\u3001\u8D2D\u65B9\u5BA2\u6237\u3001\u767B\u5F55\u72B6\u6001\u3001\u7A0E\u5C40\u8BA4\u8BC1\u3001\u5269\u4F59\u989D\u5EA6\u3001\u7A0E\u76EE\u89E3\u6790\u3001\u6B63\u5F0F\u5F00\u7968\u548C\u95EE\u9898\u53CD\u9988\u3002\u8C03\u7528\u524D\u5FC5\u987B\u8BFB\u53D6\u5BF9\u5E94\u6587\u6863\uFF1B\u6B63\u5F0F\u5F00\u7968\u5FC5\u987B\u83B7\u5F97\u7528\u6237\u660E\u786E\u786E\u8BA4\uFF1B\u4E0D\u5F97\u4F20\u9012 API Key\u3001Token \u6216\u5176\u4ED6\u8BA4\u8BC1\u51ED\u636E\u3002",
5952
6017
  inputSchema: z.object({
5953
6018
  operation: z.enum([
5954
6019
  "CompanyFullList",
@@ -5962,7 +6027,7 @@ function createLemonClawServer(options = {}) {
5962
6027
  "TaxBureauAuthChain",
5963
6028
  "SkillInvoiceIssue",
5964
6029
  "FeedbackSubmit"
5965
- ]),
6030
+ ]).describe("\u8981\u6267\u884C\u7684\u56FA\u5B9A\u5F00\u7968\u64CD\u4F5C\uFF0C\u5FC5\u987B\u6765\u81EA\u5DF2\u8BFB\u53D6\u7684\u5BF9\u5E94\u6D41\u7A0B\u6587\u6863\u3002"),
5966
6031
  eiscid: optionalText,
5967
6032
  filter_word: optionalText,
5968
6033
  company_name: optionalText,
@@ -5971,9 +6036,8 @@ function createLemonClawServer(options = {}) {
5971
6036
  uscic: optionalText,
5972
6037
  auth_company_id: optionalText,
5973
6038
  company_detail_id: optionalText,
5974
- payload: z.record(z.string(), z.unknown()).optional(),
5975
- payload_path: optionalText,
5976
- api_key_last_four: optionalText,
6039
+ payload: z.record(z.string(), z.unknown()).optional().describe("\u5BF9\u5E94\u64CD\u4F5C\u6587\u6863\u5B9A\u4E49\u7684\u8BF7\u6C42\u6570\u636E\uFF0C\u4E0D\u5F97\u6DFB\u52A0\u8BA4\u8BC1\u51ED\u636E\u3002"),
6040
+ payload_path: optionalText.describe("\u5BF9\u5E94\u6D41\u7A0B\u6587\u6863\u5141\u8BB8\u8BFB\u53D6\u7684\u672C\u5730\u8BF7\u6C42\u6570\u636E\u6587\u4EF6\u8DEF\u5F84\u3002"),
5977
6041
  ai_tool: optionalText,
5978
6042
  model: optionalText,
5979
6043
  feedback_contact: optionalText,
@@ -5984,7 +6048,7 @@ function createLemonClawServer(options = {}) {
5984
6048
  message_id: optionalText,
5985
6049
  context: optionalText,
5986
6050
  upload_file_path: optionalText,
5987
- user_confirmed: z.boolean().default(false),
6051
+ user_confirmed: z.boolean().default(false).describe("\u4EC5\u5728\u7528\u6237\u660E\u786E\u786E\u8BA4\u6B63\u5F0F\u5F00\u7968\u6216\u6587\u6863\u6807\u6CE8\u7684\u5199\u64CD\u4F5C\u540E\u8BBE\u4E3A true\u3002"),
5988
6052
  timeout_seconds: timeoutSchema
5989
6053
  }),
5990
6054
  annotations: {
@@ -6005,12 +6069,12 @@ function createLemonClawServer(options = {}) {
6005
6069
  server.registerTool(
6006
6070
  "lemon_invoice_run_helper",
6007
6071
  {
6008
- title: "Run a Lemon independent-invoicing helper",
6009
- description: "Run one whitelisted Runtime helper for invoice file parsing, validation, preview generation, preview serving, customer lookup, or customer-service output. Arguments must come from the invoice documents.",
6072
+ title: "\u8FD0\u884C\u67E0\u6AAC\u4E91\u72EC\u7ACB\u5F00\u7968\u8F85\u52A9\u7A0B\u5E8F",
6073
+ description: "\u4EC5\u8FD0\u884C\u4E91\u53D1\u7968\u4EA7\u54C1\u6D41\u7A0B\u5185\u7F6E\u7684\u767D\u540D\u5355\u8F85\u52A9\u7A0B\u5E8F\uFF0C\u7528\u4E8E Excel/\u6570\u636E\u6587\u4EF6\u89E3\u6790\u3001JSON \u6821\u9A8C\u3001\u53D1\u7968\u9884\u89C8\u751F\u6210\u3001\u9884\u89C8\u670D\u52A1\u3001\u5BA2\u6237\u67E5\u8BE2\u548C\u5BA2\u670D\u4FE1\u606F\u8F93\u51FA\uFF1B\u5B83\u4E0D\u67E5\u8BE2\u8D26\u5957\u6216\u4E91\u53D1\u7968\u4F01\u4E1A\u3002\u67E5\u8BE2\u4E91\u53D1\u7968\u4F01\u4E1A\u3001\u8D26\u5957\u3001\u9500\u65B9\u6216\u53EF\u5F00\u7968\u4E3B\u4F53\u5FC5\u987B\u4F7F\u7528 lemon_invoice_api \u7684 CompanyFullList\u3002\u672C\u5DE5\u5177\u4E0D\u80FD\u6267\u884C\u4EFB\u610F\u7CFB\u7EDF\u547D\u4EE4\u3001\u4EFB\u610F Python \u811A\u672C\u6216\u767D\u540D\u5355\u5916\u7A0B\u5E8F\uFF1Boperation \u548C\u53C2\u6570\u5FC5\u987B\u6765\u81EA\u5DF2\u8BFB\u53D6\u7684\u5F00\u7968\u6587\u6863\u3002",
6010
6074
  inputSchema: z.object({
6011
- operation: z.enum(invoiceHelperNames),
6012
- arguments: z.array(z.string()).max(30).default([]),
6013
- stdin: z.string().optional(),
6075
+ operation: z.enum(invoiceHelperNames).describe("\u8981\u8FD0\u884C\u7684\u767D\u540D\u5355\u8F85\u52A9\u64CD\u4F5C\uFF0C\u5FC5\u987B\u6765\u81EA\u5DF2\u8BFB\u53D6\u7684\u5F00\u7968\u6D41\u7A0B\u6587\u6863\u3002"),
6076
+ arguments: z.array(z.string()).max(30).default([]).describe("\u6309\u5BF9\u5E94\u6D41\u7A0B\u6587\u6863\u987A\u5E8F\u63D0\u4F9B\u7684\u8F85\u52A9\u7A0B\u5E8F\u53C2\u6570\uFF0C\u6700\u591A 30 \u9879\u3002"),
6077
+ stdin: z.string().optional().describe("\u4EC5\u5728\u5BF9\u5E94\u6D41\u7A0B\u6587\u6863\u8981\u6C42\u65F6\u4F20\u5165\u7684\u6807\u51C6\u8F93\u5165\u6587\u672C\u3002"),
6014
6078
  timeout_seconds: timeoutSchema
6015
6079
  }),
6016
6080
  annotations: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lemonbeijing/lemonclaw-mcp-service",
3
- "version": "0.1.2",
4
- "description": "Local stdio MCP service for LemonClaw portable Runtime.",
3
+ "version": "0.1.4",
4
+ "description": "用于查询和操作柠檬云 Lemon Cloud 业务数据的 MCP 服务,覆盖账套、进销存 SCM、业财 ERP、财务 ACC 和独立开票;支持客户、供应商、商品、仓库、采购、销售、库存、收付款、往来、凭证、账簿、发票及经营与财务报表,并支持立即开票、批量开票和问题反馈。",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "engines": {