@zltquant/zlt-mcp 0.4.2 → 0.5.0-beta.0

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
@@ -14,6 +14,12 @@ npx -y @zltquant/zlt-mcp list --json
14
14
  npx -y @zltquant/zlt-mcp call zlt-runtime-doctor --args-json '{}'
15
15
  ```
16
16
 
17
+ 业务调用支持 `call --output-json <新文件路径>`:完整 JSON 写入文件,stdout 返回含
18
+ `ok`、`tool`、`resultFile`、`cliProvenance`、精简 `data` 的回执。
19
+ 输出目录须已存在,已有文件会在执行工具前报错;每次使用新文件名。完整参数与大段数据从结果文件读取。
20
+ stderr 保留诊断,失败返回非零退出码。工具执行后若写文件失败,完整结果会输出到 stdout;先核对结果,不要自动重复执行。
21
+ 不传该参数时保持原有完整 stdout。
22
+
17
23
  其他支持原生 MCP 的客户端(Trae / Claude Code / Cursor 等)可以使用下面的配置:
18
24
 
19
25
  ```json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zltquant/zlt-mcp",
3
- "version": "0.4.2",
3
+ "version": "0.5.0-beta.0",
4
4
  "description": "智量通 ZLT Quant MCP server(Windows x64;量化策略创建与本地回测)",
5
5
  "bin": {
6
6
  "zlt-mcp": "./zlt-mcp-proxy.bundle.cjs"
@@ -24936,6 +24936,12 @@ function echoResolvedBacktestConfig(tool, args, result, contexts) {
24936
24936
  const echoedRunId = typeof parsed.Data.runId === "string" ? parsed.Data.runId.trim() : "";
24937
24937
  const runId = echoedRunId || (tool.name === "mcp-re-backtest" && typeof args.runId === "string" ? args.runId.trim() : "");
24938
24938
  const context = runId ? contexts.get(runId) : void 0;
24939
+ if (runId) echo.runId = runId;
24940
+ if (context?.codePath) {
24941
+ echo.codePath = context.codePath;
24942
+ echo.runDir = context.codePath;
24943
+ }
24944
+ if (context?.runParams) echo.runParams = { ...context.runParams };
24939
24945
  if (context?.attemptStartedAtMs) {
24940
24946
  echo.attemptFence = {
24941
24947
  attemptStartedAtMs: context.attemptStartedAtMs,
@@ -27501,7 +27507,7 @@ function runtimeRecoveryStopData(message, extra = {}, handler = "runtimeStart")
27501
27507
  // src/index.ts
27502
27508
  var CLI_NAME = "zlt-mcp";
27503
27509
  var CLI_FALLBACK_PACKAGE_NAME = "@zltquant/zlt-mcp";
27504
- var CLI_FALLBACK_VERSION = "0.4.2";
27510
+ var CLI_FALLBACK_VERSION = "0.5.0-beta.0";
27505
27511
  if (process.argv.length <= 2) {
27506
27512
  startMcpServer();
27507
27513
  } else {
@@ -27511,21 +27517,44 @@ if (process.argv.length <= 2) {
27511
27517
  if (kind !== "backtest") throw new Error(`Unsupported keepalive kind: ${kind}`);
27512
27518
  await keepMcpBacktestAlive(id, codePath);
27513
27519
  });
27514
- program2.command("call <tool>").description("Call any MCP tool through the bundled MCP server").option("--args-json <json>", "JSON object containing tool arguments").option("--args-file <path>", "Read the JSON argument object from a file").option("--timeout-ms <ms>", "MCP request inactivity timeout in milliseconds").option("--max-total-timeout-ms <ms>", "Optional hard upper bound for the request").option("--no-progress", "Suppress progress diagnostics on stderr").action(async (tool, options) => {
27520
+ program2.command("call <tool>").description("Call any MCP tool through the bundled MCP server").option("--args-json <json>", "JSON object containing tool arguments").option("--args-file <path>", "Read the JSON argument object from a file").option("--output-json <path>", "Save the complete result to a new JSON file and print a compact receipt").option("--timeout-ms <ms>", "MCP request inactivity timeout in milliseconds").option("--max-total-timeout-ms <ms>", "Optional hard upper bound for the request").option("--no-progress", "Suppress progress diagnostics on stderr").action(async (tool, options) => {
27521
+ let outputFd;
27515
27522
  try {
27516
27523
  const args = parseMcpArgs(options.argsJson, options.argsFile);
27524
+ const timeoutMs = parseTimeoutOption(options.timeoutMs, "--timeout-ms");
27525
+ const maxTotalTimeoutMs = parseTimeoutOption(options.maxTotalTimeoutMs, "--max-total-timeout-ms");
27526
+ const resultFile = options.outputJson === void 0 ? void 0 : path14.resolve(options.outputJson);
27527
+ if (resultFile !== void 0) outputFd = fs13.openSync(resultFile, "wx");
27517
27528
  const result = await callMcpTool(tool, args, {
27518
- timeoutMs: parseTimeoutOption(options.timeoutMs, "--timeout-ms"),
27519
- maxTotalTimeoutMs: parseTimeoutOption(options.maxTotalTimeoutMs, "--max-total-timeout-ms"),
27529
+ timeoutMs,
27530
+ maxTotalTimeoutMs,
27520
27531
  showProgress: options.progress !== false
27521
27532
  });
27522
- process.stdout.write(JSON.stringify(withCliProvenance(result)) + "\n");
27533
+ const complete = withCliProvenance(result);
27534
+ const serialized = JSON.stringify(complete) + "\n";
27535
+ if (outputFd !== void 0 && resultFile !== void 0) {
27536
+ try {
27537
+ fs13.writeFileSync(outputFd, serialized, "utf-8");
27538
+ fs13.closeSync(outputFd);
27539
+ outputFd = void 0;
27540
+ } catch (error2) {
27541
+ process.stdout.write(serialized);
27542
+ throw new Error(`Tool returned a result, but saving ${resultFile} failed; complete result is on stdout. Do not repeat the tool automatically. ${String(error2)}`);
27543
+ }
27544
+ const receipt = compactCliReceipt(tool, complete, resultFile);
27545
+ process.stdout.write(JSON.stringify(receipt) + "\n");
27546
+ if (!receipt.ok) process.exitCode = 1;
27547
+ } else {
27548
+ process.stdout.write(serialized);
27549
+ }
27523
27550
  if (result.isError === true) process.exitCode = 1;
27524
27551
  } catch (error2) {
27525
27552
  const message = error2 instanceof Error ? error2.message : String(error2);
27526
27553
  process.stderr.write(`Error: ${message}
27527
27554
  `);
27528
27555
  process.exitCode = 1;
27556
+ } finally {
27557
+ if (outputFd !== void 0) fs13.closeSync(outputFd);
27529
27558
  }
27530
27559
  });
27531
27560
  program2.command("list").description("List MCP tools exposed by the bundled server").option("--json", "Emit the complete tools/list response as JSON").action(async (options) => {
@@ -27619,6 +27648,46 @@ function resolveCliPackageProvenance() {
27619
27648
  function withCliProvenance(result) {
27620
27649
  return { ...result, cliProvenance: resolveCliPackageProvenance() };
27621
27650
  }
27651
+ function compactCliReceipt(tool, result, resultFile) {
27652
+ const payload = parseMcpResult(result);
27653
+ const code = payload?.ErrNo;
27654
+ const ok = result.isError !== true && (code === void 0 || code === null || Number(code) === 0);
27655
+ const source = payload?.Data;
27656
+ const data = {};
27657
+ if (source && typeof source === "object" && !Array.isArray(source)) {
27658
+ const fields = source;
27659
+ for (const key of [
27660
+ "runId",
27661
+ "backtestId",
27662
+ "strategyId",
27663
+ "localPath",
27664
+ "codePath",
27665
+ "runDir",
27666
+ "attemptFence",
27667
+ "status",
27668
+ "progress",
27669
+ "available",
27670
+ "runtimeReady",
27671
+ "backtestReady",
27672
+ "nextAction",
27673
+ "recommendedAction",
27674
+ "error_code",
27675
+ "error_msg"
27676
+ ]) {
27677
+ if (fields[key] !== void 0) {
27678
+ data[key] = key === "error_msg" && typeof fields[key] === "string" ? fields[key].slice(0, 512) : fields[key];
27679
+ }
27680
+ }
27681
+ }
27682
+ return {
27683
+ ok,
27684
+ tool,
27685
+ resultFile,
27686
+ cliProvenance: result.cliProvenance,
27687
+ data,
27688
+ ...!ok ? { error: { code: code ?? null, message: String(payload?.ErrMsg ?? "Tool reported an error; see resultFile").slice(0, 512) } } : {}
27689
+ };
27690
+ }
27622
27691
  function parseTimeoutOption(value, flag) {
27623
27692
  if (value === void 0) return void 0;
27624
27693
  const parsed = Number(value);