ccs-mcp-server 1.3.0 → 1.4.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/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * CCS Runtime Evidence MCP Server v1.0.0
3
+ * CCS Runtime Evidence MCP Server
4
4
  *
5
5
  * A standalone Model Context Protocol (MCP) server that exposes CCS runtime
6
6
  * verification as MCP tools, so any MCP-compatible client (Claude Desktop,
@@ -435,7 +435,7 @@ function verifyIntentBinding(intent, toolName, toolArgs, now = Date.now()) {
435
435
  // ---------------------------------------------------------------------------
436
436
 
437
437
  const PROTOCOL_VERSION = "2024-11-05";
438
- const SERVER_INFO = { name: "ccs-runtime-evidence", version: CCS_VERSION, title: "CCS Runtime Evidence" };
438
+ const SERVER_INFO = { name: "agent-runtime-guard", version: CCS_VERSION, title: "Agent Runtime Guard" };
439
439
 
440
440
  // MCP tool annotations (spec 2024-11-05+). Hints describe the tool's real
441
441
  // runtime behaviour so clients/registries can drive consent, UI gating and
@@ -718,7 +718,67 @@ function handleRequest(req) {
718
718
  return null;
719
719
  }
720
720
 
721
+ function cliInfo() {
722
+ const S = " ";
723
+ return [
724
+ `ccs-mcp-server v${CCS_VERSION} — Agent 运行时验证 + CCS 收据验签`,
725
+ ``,
726
+ `用法:`,
727
+ `${S}npx -y ccs-mcp-server # 作为 MCP server 启动(stdio)`,
728
+ `${S}npx -y ccs-mcp-server --help # 显示本说明`,
729
+ `${S}npx -y ccs-mcp-server --version # 显示版本`,
730
+ `${S}npx -y ccs-mcp-server --tools # 列出可用工具`,
731
+ ``,
732
+ `配置到 MCP 客户端(Claude Code / Cursor / Cline / Windsurf):`,
733
+ `${S}{ "mcpServers": { "ccs-mcp-server": { "command": "npx", "args": ["-y", "ccs-mcp-server"] } } }`,
734
+ ``,
735
+ `免费可用(本地离线,零依赖,无需 API key):`,
736
+ `${S}verify_tool_call 7 维运行时验证,危险调用默认拦截(fail-closed)`,
737
+ `${S}issue_evidence Ed25519 证据收据(放行与拦截都产生,第三方可离线验证)`,
738
+ `${S}audit_mcp_config MCP 配置静态安全审计`,
739
+ `${S}verify_intent_binding 校验实际参数与声明意图是否一致(抓跨模型参数漂移)`,
740
+ `${S}verify_receipt 离线验签 CCS 收据、检测篡改`,
741
+ `${S}locate_tampering 逐字段定位收据被改动的位置(RFC 6901 路径)`,
742
+ ``,
743
+ `需要订阅(¥49.90/月,支付宝 SkillPay):`,
744
+ `${S}· CCS收据验签 深度篡改取证`,
745
+ `${S}· CCS收据批量审计 目录级批量验签与合规留痕`,
746
+ `${S}· MCP配置安全体检 完整 7 维分级报告`,
747
+ `${S}货架: https://skillpay.alipay.com/public/correctover`,
748
+ ``,
749
+ `文档: https://github.com/DSHCorrectover/agent-runtime-guard`,
750
+ ].join("\n");
751
+ }
752
+
753
+ function cliTools() {
754
+ return [
755
+ "verify_tool_call Runtime verification, 7 dimensions, fail-closed by default",
756
+ "issue_evidence Issue an Ed25519-signed evidence receipt",
757
+ "audit_mcp_config Static security audit of MCP server configuration",
758
+ "verify_intent_binding Detect drift between declared intent and actual arguments",
759
+ "verify_receipt Offline receipt verification and tamper detection",
760
+ "locate_tampering Field-level localization of tampered fields (RFC 6901)",
761
+ ].join("\n");
762
+ }
763
+
721
764
  function main() {
765
+ // CLI 参数层:只处理显式的信息类参数,未命中则行为与以往完全一致。
766
+ // 为什么需要这层:MCP 客户端调用不带参数,但人类用户会敲 --help / --version 探路。
767
+ // 之前无论传什么参数都直接启动 stdio 服务并打广告,用户得不到任何信息、命令还会挂住。
768
+ const argv = process.argv.slice(2);
769
+ if (argv.includes("--help") || argv.includes("-h") || argv.includes("help")) {
770
+ process.stdout.write(cliInfo() + "\n");
771
+ process.exit(0);
772
+ }
773
+ if (argv.includes("--version") || argv.includes("-v")) {
774
+ process.stdout.write(CCS_VERSION + "\n");
775
+ process.exit(0);
776
+ }
777
+ if (argv.includes("--tools")) {
778
+ process.stdout.write(cliTools() + "\n");
779
+ process.exit(0);
780
+ }
781
+
722
782
  const kp = receipts.getKeypair();
723
783
  const fp = receipts.publicKeyFingerprint();
724
784
  const banner =
package/test/run-tests.js CHANGED
@@ -248,6 +248,102 @@ test("指针与点号路径同时可查(既有消费方不被破坏)", () =>
248
248
  assert.strictEqual(d.path_dotted, "a.b");
249
249
  });
250
250
 
251
+ // ---------------------------------------------------------------------------
252
+ // 6. CLI 参数层
253
+ //
254
+ // 为什么这些断言重要:用户会用 --help / --version 探路。
255
+ // 在此之前,任何参数都会被无视、直接启动 stdio 服务并打广告 ——
256
+ // 用户得不到信息、命令还会挂住,这是最早的流失点。
257
+ // 同时必须保证:CLI 层是纯增量的,不带参数时协议行为一字不变。
258
+ // ---------------------------------------------------------------------------
259
+
260
+ const { spawnSync } = require("child_process");
261
+ const path = require("path");
262
+ const INDEX = path.join(__dirname, "..", "src", "index.js");
263
+
264
+ function runCli(args, input) {
265
+ return spawnSync(process.execPath, [INDEX, ...args], {
266
+ input: input || "",
267
+ encoding: "utf8",
268
+ timeout: 15000,
269
+ });
270
+ }
271
+
272
+ test("--help 输出版本号", () => {
273
+ const r = runCli(["--help"]);
274
+ assert.strictEqual(r.status, 0);
275
+ assert.ok(/ccs-mcp-server v\d+\.\d+\.\d+/.test(r.stdout), "缺少版本号行");
276
+ });
277
+
278
+ test("--help 输出用法说明而非广告", () => {
279
+ const r = runCli(["--help"]);
280
+ assert.ok(r.stdout.includes("用法:"), "缺少用法段");
281
+ assert.ok(r.stdout.includes("mcpServers"), "缺少 MCP 配置示例");
282
+ });
283
+
284
+ test("--help 列出全部工具", () => {
285
+ const r = runCli(["--help"]);
286
+ for (const tool of ["verify_tool_call", "issue_evidence", "audit_mcp_config",
287
+ "verify_intent_binding", "verify_receipt", "locate_tampering"]) {
288
+ assert.ok(r.stdout.includes(tool), `--help 未列出工具 ${tool}`);
289
+ }
290
+ });
291
+
292
+ test("--help 不把广告放在开头", () => {
293
+ const r = runCli(["--help"]);
294
+ const firstLine = r.stdout.split("\n")[0];
295
+ assert.ok(!firstLine.includes("支付宝"), "第一行就是广告(时序错位)");
296
+ });
297
+
298
+ test("--version 只输出版本号", () => {
299
+ const r = runCli(["--version"]);
300
+ assert.strictEqual(r.status, 0);
301
+ assert.strictEqual(r.stdout.trim(), require("../package.json").version);
302
+ });
303
+
304
+ test("-v 与 --version 等价", () => {
305
+ assert.strictEqual(runCli(["-v"]).stdout.trim(), require("../package.json").version);
306
+ });
307
+
308
+ test("-h 与 --help 等价", () => {
309
+ assert.ok(runCli(["-h"]).stdout.includes("用法:"));
310
+ });
311
+
312
+ test("--tools 输出纯工具名,无广告", () => {
313
+ const r = runCli(["--tools"]);
314
+ assert.strictEqual(r.status, 0);
315
+ assert.ok(r.stdout.includes("verify_tool_call"));
316
+ assert.ok(!r.stdout.includes("支付宝"), "--tools 不应含广告");
317
+ assert.ok(!r.stdout.includes("SkillPay"), "--tools 不应含 SkillPay");
318
+ });
319
+
320
+ test("CLI 参数不启动 stdio 服务(立即退出)", () => {
321
+ const r = runCli(["--help"]);
322
+ assert.strictEqual(r.status, 0, "应正常退出而非挂住等待 stdin");
323
+ });
324
+
325
+ test("不带参数时协议行为不变:initialize 正常", () => {
326
+ const r = runCli([], '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}\n');
327
+ const line = r.stdout.split("\n").find((l) => l.includes('"id":1'));
328
+ assert.ok(line, "未收到 initialize 响应");
329
+ const d = JSON.parse(line);
330
+ assert.ok(d.result && d.result.serverInfo, "响应结构异常");
331
+ assert.strictEqual(d.result.protocolVersion, "2024-11-05");
332
+ });
333
+
334
+ test("不带参数时协议行为不变:tools/list 返回 6 个工具", () => {
335
+ const r = runCli([], '{"jsonrpc":"2.0","id":1,"method":"tools/list"}\n');
336
+ const line = r.stdout.split("\n").find((l) => l.includes('"id":1'));
337
+ const d = JSON.parse(line);
338
+ assert.strictEqual(d.result.tools.length, 6);
339
+ });
340
+
341
+ test("未知参数不误触发 CLI 层(仍进入服务模式)", () => {
342
+ const r = runCli(["--nonexistent-flag"], '{"jsonrpc":"2.0","id":1,"method":"ping"}\n');
343
+ const line = r.stdout.split("\n").find((l) => l.includes('"id":1'));
344
+ assert.ok(line, "未知参数不应阻止服务启动");
345
+ });
346
+
251
347
  // ---------------------------------------------------------------------------
252
348
  console.log(`\n${"=".repeat(52)}`);
253
349
  console.log(` ${passed}/${passed + failed} PASS`);