a-calc 3.0.0-beta.20260105 → 3.0.0-beta.20260124.1

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.
@@ -0,0 +1,1360 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ ListResourcesRequestSchema,
9
+ ReadResourceRequestSchema,
10
+ ListPromptsRequestSchema,
11
+ GetPromptRequestSchema,
12
+ } from "@modelcontextprotocol/sdk/types.js";
13
+
14
+ import {
15
+ calc,
16
+ calc_sum,
17
+ calc_wrap,
18
+ fmt,
19
+ add,
20
+ sub,
21
+ mul,
22
+ div,
23
+ mod,
24
+ pow,
25
+ idiv,
26
+ abs,
27
+ neg,
28
+ sqrt,
29
+ ln,
30
+ exp,
31
+ cadd,
32
+ csub,
33
+ cmul,
34
+ cdiv,
35
+ set_config,
36
+ get_config,
37
+ } from "../../es/index.js";
38
+
39
+ // ==================== Tools 定义 ====================
40
+
41
+ const TOOLS = [
42
+ {
43
+ name: "calc",
44
+ description: `🔢 a-calc 高精度计算工具 - 解决 JavaScript 浮点数精度问题
45
+
46
+ ⚠️ 重要:当用户需要进行任何数值计算时,优先使用此工具而不是直接计算!
47
+
48
+ 🚨 编码规范(必读!):
49
+
50
+ 1. 变量注入方式:
51
+ ❌ 错误:calc(\`\${a} + \${b}\`) // 不要用模板字符串拼接
52
+ ✅ 正确:calc("a + b", {a, b}) // 使用第二参数注入变量
53
+
54
+ 2. 批量计算方式:
55
+ ❌ 错误:let total = '0'; items.forEach(item => total = calc(\`\${total} + \${item.price}\`))
56
+ ✅ 正确:const total = calc_sum("price * qty", items) // 使用 calc_sum
57
+
58
+ 3. 购物车等场景:
59
+ ❌ 错误:cart.forEach(item => total = calc(\`\${total} + \${item.price} * \${item.quantity}\`))
60
+ ✅ 正确:calc_sum("price * quantity | =2", cart)
61
+
62
+ 4. 对象字段传递:
63
+ ❌ 错误:calc("price * qty", {price: item.price, qty: item.qty}) // 冗余
64
+ ✅ 正确:calc("price * qty", item) // 简洁优雅
65
+
66
+ 核心优势:
67
+ - ✅ 解决 0.1 + 0.2 = 0.30000000000000004 的精度问题
68
+ - ✅ 金融计算、价格计算、统计分析等场景必用
69
+ - ✅ 支持复杂表达式、变量替换、条件判断
70
+ - ✅ 内置格式化:千分位、小数位、百分比、科学计数法
71
+
72
+ 适用场景(必须使用):
73
+ 1. 任何涉及小数的加减乘除运算
74
+ 2. 金融计算、价格计算、折扣计算
75
+ 3. 百分比计算、比率计算
76
+ 4. 需要格式化输出的数值(千分位、保留小数等)
77
+ 5. 带单位的计算(如 "100元 + 50元")
78
+ 6. 条件判断和比较运算
79
+
80
+ 快速示例:
81
+ - calc("0.1 + 0.2") → "0.3" (精确!)
82
+ - calc("price * qty | =2", {price: 99.9, qty: 3}) → "299.70"
83
+ - calc("1234567 | ,") → "1,234,567" (千分位)
84
+ - calc("score >= 60 ? '及格' : '不及格'", {score: 75}) → "及格"
85
+
86
+ 变量注入最佳实践:
87
+ - 如果对象已有所需字段,直接传入:calc("price * qty", item)
88
+ - 如果需要多个独立变量,使用简写:calc("a + b", {a, b})
89
+ - 避免冗余:❌ calc("price * qty", {price: item.price, qty: item.qty})
90
+
91
+ 支持的运算:
92
+ - 基础运算: + - * / % ** // (加减乘除、取模、幂、整除)
93
+ - 比较运算: > < >= <= == !=
94
+ - 逻辑运算: && || !
95
+ - 数学函数: sqrt, sin, cos, tan, pow, max, min, abs, floor, ceil 等
96
+ - 格式化: =N(小数位), ,(千分位), %(百分比), !e(科学计数), !v(交易量)`,
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: {
100
+ expr: {
101
+ type: "string",
102
+ description: "计算表达式,支持变量名和格式化(用 | 分隔)",
103
+ },
104
+ options: {
105
+ type: "object",
106
+ description: "配置选项和变量数据",
107
+ properties: {
108
+ _error: {
109
+ type: ["string", "number", "null"],
110
+ description: "错误时的返回值,默认会抛出异常",
111
+ },
112
+ _unit: {
113
+ type: "boolean",
114
+ description: "是否启用单位计算,如 '100元 + 50元'",
115
+ },
116
+ _fmt: {
117
+ type: "string",
118
+ description: "默认格式化字符串",
119
+ },
120
+ _mode: {
121
+ type: "string",
122
+ enum: ["normal", "space", "space-all"],
123
+ description: "解析模式",
124
+ },
125
+ _debug: {
126
+ type: "boolean",
127
+ description: "是否启用调试模式",
128
+ },
129
+ },
130
+ additionalProperties: true,
131
+ },
132
+ },
133
+ required: ["expr"],
134
+ },
135
+ },
136
+ {
137
+ name: "fmt",
138
+ description: `📊 a-calc 数值格式化工具 - 专业的数字格式化,性能最优
139
+
140
+ ⚠️ 使用场景:当需要格式化数字(千分位、小数位、百分比等)但不需要计算时使用
141
+
142
+ 性能优势:
143
+ - 跳过表达式解析,比 calc 更快
144
+ - 适合纯格式化场景
145
+
146
+ 常用格式化规则:
147
+ - =N: 精确N位小数 (如 =2 → "100.00")
148
+ - <=N: 最多N位小数 (如 <=2 → "3.14")
149
+ - >=N: 至少N位小数 (如 >=3 → "3.100")
150
+ - ~5: 四舍五入 (如 ~5=2 → "1.13")
151
+ - ~6: 银行家舍入
152
+ - ,: 千分位分隔 (如 , → "1,234,567")
153
+ - %: 百分比 (如 %=2 → "12.34%")
154
+ - !e: 科学计数法 (如 !e=2 → "1.23e+8")
155
+ - +: 显示正号 (如 + → "+100")
156
+ - !n: 返回数字类型
157
+ - !v: 交易量缩写 (如 !v → "1.23M")
158
+ - !t:us/eu/indian/cn4: 千分位预设
159
+
160
+ 快速示例:
161
+ - fmt(100, "=2") → "100.00"
162
+ - fmt(1234567, ",") → "1,234,567"
163
+ - fmt(0.1234, "%=2") → "12.34%"
164
+ - fmt(123456789, "!e=2") → "1.23e+8"
165
+ - fmt(1234567, "!v") → "1.23M"
166
+ - fmt(1234567.89, "!t:eu") → "1.234.567,89"`,
167
+ inputSchema: {
168
+ type: "object",
169
+ properties: {
170
+ value: {
171
+ type: ["number", "string"],
172
+ description: "要格式化的数值",
173
+ },
174
+ format_str: {
175
+ type: "string",
176
+ description: "格式化字符串",
177
+ },
178
+ options: {
179
+ type: "object",
180
+ description: "格式化选项",
181
+ additionalProperties: true,
182
+ },
183
+ },
184
+ required: ["value"],
185
+ },
186
+ },
187
+ {
188
+ name: "calc_sum",
189
+ description: `📈 a-calc 批量聚合计算工具 - 对数组数据进行批量计算并求和
190
+
191
+ ⚠️ 使用场景:处理数组数据、批量计算、统计汇总时使用
192
+
193
+ 🚨 这是处理数组数据的正确方式!不要用 forEach 累加!
194
+
195
+ 典型应用场景:
196
+ 1. 计算订单总价:多个商品的 price * quantity 求和
197
+ 2. 统计销售额:多条销售记录的金额汇总
198
+ 3. 报表数据汇总:批量计算并求和
199
+ 4. 购物车总价计算
200
+
201
+ 编码规范对比(必读!):
202
+
203
+ ❌ 错误写法(不要这样做):
204
+ \`\`\`javascript
205
+ // 购物车总价 - 错误示例
206
+ let total = '0'
207
+ cart.forEach(item => {
208
+ total = calc(\`\${total} + \${item.price} * \${item.quantity}\`)
209
+ })
210
+ \`\`\`
211
+ 问题:使用模板字符串拼接、forEach 累加,代码不清晰、性能差
212
+
213
+ ✅ 正确写法(推荐):
214
+ \`\`\`javascript
215
+ // 购物车总价 - 使用 calc_sum
216
+ const total = calc_sum("price * quantity | =2", cart)
217
+
218
+ // 单个商品小计 - 直接传入对象(最优雅)
219
+ const itemTotal = calc("price * quantity | =2", item)
220
+ \`\`\`
221
+ 优势:代码简洁、性能好、自动处理精度
222
+
223
+ 🎯 最佳实践:
224
+ - 对象已有所需字段 → 直接传入:calc("a + b", obj)
225
+ - 需要多个独立变量 → 使用简写:calc("a + b", {a, b})
226
+ - 避免冗余写法 → ❌ calc("a + b", {a: obj.a, b: obj.b})
227
+
228
+ 快速示例:
229
+ - calc_sum("a + b", [{a:1,b:2}, {a:3,b:4}]) → "10"
230
+ - calc_sum("price * qty", [{price:99.9,qty:2}, {price:49.9,qty:3}]) → "349.50"
231
+ - calc_sum("price * qty * 0.9 | =2", orders) → 计算所有订单9折后总价
232
+
233
+ 优势:
234
+ - 自动处理精度问题
235
+ - 支持复杂表达式
236
+ - 支持格式化输出
237
+ - 性能优于手动累加`,
238
+ inputSchema: {
239
+ type: "object",
240
+ properties: {
241
+ expr: {
242
+ type: "string",
243
+ description: "计算表达式",
244
+ },
245
+ data_array: {
246
+ type: "array",
247
+ description: "数据源数组",
248
+ items: {
249
+ type: "object",
250
+ },
251
+ },
252
+ },
253
+ required: ["expr", "data_array"],
254
+ },
255
+ },
256
+ {
257
+ name: "basic_calc",
258
+ description: `a-calc 基础运算函数 - 直接进行精确的数学运算,性能最优
259
+
260
+ 支持的运算:
261
+ - add: 加法 (支持多参数)
262
+ - sub: 减法 (支持多参数)
263
+ - mul: 乘法 (支持多参数)
264
+ - div: 除法 (支持多参数)
265
+ - mod: 取模
266
+ - pow: 幂运算
267
+ - idiv: 整除
268
+ - abs: 绝对值
269
+ - neg: 取负
270
+ - sqrt: 平方根
271
+ - ln: 自然对数
272
+ - exp: e的幂
273
+
274
+ 使用示例:
275
+ - add(0.1, 0.2) → "0.3"
276
+ - mul(0.1, 0.2, 0.3) → "0.006"
277
+ - div(1, 3) → "0.333..."
278
+ - sqrt(16) → "4"`,
279
+ inputSchema: {
280
+ type: "object",
281
+ properties: {
282
+ operation: {
283
+ type: "string",
284
+ enum: ["add", "sub", "mul", "div", "mod", "pow", "idiv", "abs", "neg", "sqrt", "ln", "exp"],
285
+ description: "运算类型",
286
+ },
287
+ args: {
288
+ type: "array",
289
+ description: "运算参数",
290
+ items: {
291
+ type: ["number", "string"],
292
+ },
293
+ },
294
+ },
295
+ required: ["operation", "args"],
296
+ },
297
+ },
298
+ {
299
+ name: "chain_calc",
300
+ description: `a-calc 链式计算函数 - 流式 API 风格的连续运算
301
+
302
+ 链式函数:
303
+ - cadd: 加法起始
304
+ - csub: 减法起始
305
+ - cmul: 乘法起始
306
+ - cdiv: 除法起始
307
+
308
+ 链上方法: .add() .sub() .mul() .div() .mod() .pow() .idiv()
309
+ 最后调用 () 或 (格式化字符串) 获取结果
310
+
311
+ 使用示例:
312
+ - cadd(100, 200).mul(0.8).sub(50)() → "190"
313
+ - cmul(10, 20, 30).div(100)("=2") → "60.00"
314
+ - cadd(99.9, 199, 49.5).mul(0.9).sub(20)("=2,") → "296.33"`,
315
+ inputSchema: {
316
+ type: "object",
317
+ properties: {
318
+ start_op: {
319
+ type: "string",
320
+ enum: ["cadd", "csub", "cmul", "cdiv"],
321
+ description: "起始运算类型",
322
+ },
323
+ start_args: {
324
+ type: "array",
325
+ description: "起始运算参数",
326
+ items: {
327
+ type: ["number", "string"],
328
+ },
329
+ },
330
+ chain_ops: {
331
+ type: "array",
332
+ description: "链式操作序列",
333
+ items: {
334
+ type: "object",
335
+ properties: {
336
+ op: {
337
+ type: "string",
338
+ enum: ["add", "sub", "mul", "div", "mod", "pow", "idiv"],
339
+ },
340
+ args: {
341
+ type: "array",
342
+ items: {
343
+ type: ["number", "string"],
344
+ },
345
+ },
346
+ },
347
+ required: ["op", "args"],
348
+ },
349
+ },
350
+ format: {
351
+ type: "string",
352
+ description: "最终格式化字符串(可选)",
353
+ },
354
+ },
355
+ required: ["start_op", "start_args"],
356
+ },
357
+ },
358
+ {
359
+ name: "get_acalc_guide",
360
+ description: `获取 a-calc 库的使用指南和最佳实践
361
+
362
+ 可获取的内容:
363
+ - api: API 完整参考
364
+ - formatting: 格式化规则详解
365
+ - functions: 内置数学函数
366
+ - conditional: 条件表达式和比较运算
367
+ - chain: 链式计算
368
+ - examples: 常见使用示例
369
+ - all: 获取全部内容`,
370
+ inputSchema: {
371
+ type: "object",
372
+ properties: {
373
+ topic: {
374
+ type: "string",
375
+ enum: ["api", "formatting", "functions", "conditional", "chain", "examples", "all"],
376
+ description: "要获取的主题",
377
+ },
378
+ },
379
+ required: ["topic"],
380
+ },
381
+ },
382
+ {
383
+ name: "debug_info",
384
+ description: `🔍 调试工具 - 获取 MCP 服务器的运行环境信息
385
+
386
+ 返回信息:
387
+ - cwd: 当前工作目录 (process.cwd())
388
+ - __dirname: 脚本所在目录
389
+ - __filename: 脚本文件路径
390
+ - node_version: Node.js 版本
391
+ - platform: 操作系统平台
392
+ - env: 相关环境变量
393
+
394
+ 用途:调试 MCP 服务器配置问题`,
395
+ inputSchema: {
396
+ type: "object",
397
+ properties: {},
398
+ },
399
+ },
400
+ ];
401
+
402
+ // ==================== Resources 定义 ====================
403
+
404
+ const RESOURCES = [
405
+ {
406
+ uri: "acalc://api/overview",
407
+ name: "a-calc API 概览",
408
+ description: "a-calc 库的完整 API 参考文档",
409
+ mimeType: "text/markdown",
410
+ },
411
+ {
412
+ uri: "acalc://guide/formatting",
413
+ name: "格式化规则指南",
414
+ description: "详细的格式化规则和选项说明",
415
+ mimeType: "text/markdown",
416
+ },
417
+ {
418
+ uri: "acalc://guide/functions",
419
+ name: "内置数学函数",
420
+ description: "支持的数学函数列表和用法",
421
+ mimeType: "text/markdown",
422
+ },
423
+ {
424
+ uri: "acalc://guide/conditional",
425
+ name: "条件表达式",
426
+ description: "条件表达式、比较运算、逻辑运算",
427
+ mimeType: "text/markdown",
428
+ },
429
+ {
430
+ uri: "acalc://examples/common",
431
+ name: "常见示例",
432
+ description: "常见使用场景的代码示例",
433
+ mimeType: "text/markdown",
434
+ },
435
+ ];
436
+
437
+ // ==================== Resource Contents ====================
438
+
439
+ const RESOURCE_CONTENTS = {
440
+ "acalc://api/overview": `# a-calc API 完整参考
441
+
442
+ ## 核心函数
443
+
444
+ ### calc(expr, options?)
445
+ 核心计算函数,支持表达式计算、变量填充、格式化。
446
+
447
+ **参数:**
448
+ - \`expr\`: string | number - 计算表达式
449
+ - \`options\`: object - 配置选项和变量数据
450
+
451
+ **返回:** string | number
452
+
453
+ **示例:**
454
+ \`\`\`javascript
455
+ calc("0.1 + 0.2") // "0.3"
456
+ calc("a + b", {a: 1, b: 2}) // "3"
457
+ calc("10 / 3 | =2") // "3.33"
458
+ \`\`\`
459
+
460
+ ### fmt(value, format?, options?)
461
+ 专用格式化函数,跳过表达式解析,性能更优。
462
+
463
+ **参数:**
464
+ - \`value\`: number | string - 要格式化的数值
465
+ - \`format\`: string - 格式化字符串
466
+ - \`options\`: object - 配置选项
467
+
468
+ **返回:** string | number
469
+
470
+ **示例:**
471
+ \`\`\`javascript
472
+ fmt(100, "=2") // "100.00"
473
+ fmt(1234567, ",") // "1,234,567"
474
+ \`\`\`
475
+
476
+ ### calc_sum(expr, data_array)
477
+ 聚合计算函数,对数组数据批量计算并求和。
478
+
479
+ **参数:**
480
+ - \`expr\`: string - 计算表达式
481
+ - \`data_array\`: array - 数据源数组
482
+
483
+ **返回:** string | number
484
+
485
+ **示例:**
486
+ \`\`\`javascript
487
+ calc_sum("a + b", [{a:1,b:2}, {a:3,b:4}]) // "10"
488
+ \`\`\`
489
+
490
+ ## 基础运算函数
491
+
492
+ 支持多参数运算,返回 number 类型:
493
+
494
+ - \`add(...nums)\` - 加法
495
+ - \`sub(...nums)\` - 减法
496
+ - \`mul(...nums)\` - 乘法
497
+ - \`div(...nums)\` - 除法
498
+ - \`mod(a, b)\` - 取模
499
+ - \`pow(base, exp)\` - 幂运算
500
+ - \`idiv(a, b)\` - 整除
501
+ - \`abs(value)\` - 绝对值
502
+ - \`neg(value)\` - 取负
503
+ - \`sqrt(value)\` - 平方根
504
+ - \`ln(value)\` - 自然对数
505
+ - \`exp(value)\` - e的幂
506
+
507
+ ## 链式计算函数
508
+
509
+ 流式 API 风格的连续运算:
510
+
511
+ - \`cadd(...nums)\` - 加法起始
512
+ - \`csub(first, ...rest)\` - 减法起始
513
+ - \`cmul(...nums)\` - 乘法起始
514
+ - \`cdiv(first, ...rest)\` - 除法起始
515
+
516
+ 链上方法:\`.add()\` \`.sub()\` \`.mul()\` \`.div()\` \`.mod()\` \`.pow()\` \`.idiv()\`
517
+
518
+ **示例:**
519
+ \`\`\`javascript
520
+ cadd(100, 200).mul(0.8).sub(50)() // "190"
521
+ \`\`\`
522
+ `,
523
+
524
+ "acalc://guide/formatting": `# 格式化规则详解
525
+
526
+ ## 小数位控制
527
+
528
+ - \`=N\` - 精确N位小数
529
+ - \`<=N\` - 最多N位小数
530
+ - \`>=N\` - 至少N位小数
531
+ - \`>=M<=N\` - M到N位小数范围
532
+
533
+ **示例:**
534
+ \`\`\`javascript
535
+ calc("10 / 3 | =2") // "3.33"
536
+ calc("3.14159 | <=2") // "3.14"
537
+ calc("3.1 | >=3") // "3.100"
538
+ \`\`\`
539
+
540
+ ## 舍入规则
541
+
542
+ - \`~-\` - 截断(默认)
543
+ - \`~+\` - 进位
544
+ - \`~5\` - 四舍五入
545
+ - \`~6\` - 银行家舍入
546
+
547
+ **示例:**
548
+ \`\`\`javascript
549
+ calc("1.125 | ~5=2") // "1.13"
550
+ calc("1.125 | ~6=2") // "1.12"
551
+ calc("1.124 | ~+=2") // "1.13"
552
+ \`\`\`
553
+
554
+ ## 千分位
555
+
556
+ - \`,\` - 千分位分隔符
557
+ - \`!t:us\` - 美式千分位 (1,234.56)
558
+ - \`!t:eu\` - 欧式千分位 (1.234,56)
559
+ - \`!t:indian\` - 印度式千分位 (12,34,567)
560
+ - \`!t:cn4\` - 中文四位分隔 (1234,5678)
561
+
562
+ **示例:**
563
+ \`\`\`javascript
564
+ calc("1234567 | ,") // "1,234,567"
565
+ fmt(1234567.89, "!t:eu") // "1.234.567,89"
566
+ \`\`\`
567
+
568
+ ## 百分比
569
+
570
+ - \`%\` - 转换为百分比
571
+
572
+ **示例:**
573
+ \`\`\`javascript
574
+ calc("0.1234 | %=2") // "12.34%"
575
+ \`\`\`
576
+
577
+ ## 科学计数法
578
+
579
+ - \`!e\` - 科学计数法输出
580
+
581
+ **示例:**
582
+ \`\`\`javascript
583
+ calc("123456789 | !e=2") // "1.23e+8"
584
+ \`\`\`
585
+
586
+ ## 正负号
587
+
588
+ - \`+\` - 正数显示 + 号
589
+
590
+ **示例:**
591
+ \`\`\`javascript
592
+ calc("100 | +") // "+100"
593
+ \`\`\`
594
+
595
+ ## 返回数字类型
596
+
597
+ - \`!n\` - 返回 number 类型而非 string
598
+
599
+ **示例:**
600
+ \`\`\`javascript
601
+ calc("1 + 1 | !n") // 2 (number)
602
+ \`\`\`
603
+
604
+ ## 交易量格式化
605
+
606
+ - \`!v\` - 交易量缩写 (1.23M, 1.23B)
607
+ - \`!v:wan\` - 中文单位 (1.23万)
608
+
609
+ **示例:**
610
+ \`\`\`javascript
611
+ calc("1234567 | !v") // "1.23M"
612
+ calc("12345 | !v:wan") // "1.23万"
613
+ \`\`\`
614
+
615
+ ## 组合使用
616
+
617
+ 格式化参数可以组合使用:
618
+
619
+ \`\`\`javascript
620
+ calc("0.1234 | %=2+") // "+12.34%"
621
+ calc("1234567.89 | ,=2") // "1,234,567.89"
622
+ calc("price * qty | ~5=2,", {price: 99.9, qty: 3}) // "299.70"
623
+ \`\`\`
624
+ `,
625
+
626
+ "acalc://guide/functions": `# 内置数学函数
627
+
628
+ a-calc 支持在表达式中直接使用数学函数。
629
+
630
+ ## 基础数学函数
631
+
632
+ - \`sqrt(x)\` - 平方根
633
+ - \`cbrt(x)\` - 立方根
634
+ - \`abs(x)\` - 绝对值
635
+ - \`pow(x, y)\` - x 的 y 次方
636
+ - \`exp(x)\` - e 的 x 次方
637
+ - \`ln(x)\` - 自然对数
638
+ - \`log(x)\` - 常用对数(以10为底)
639
+ - \`log2(x)\` - 以2为底的对数
640
+ - \`log10(x)\` - 以10为底的对数
641
+
642
+ ## 三角函数
643
+
644
+ - \`sin(x)\` - 正弦
645
+ - \`cos(x)\` - 余弦
646
+ - \`tan(x)\` - 正切
647
+ - \`asin(x)\` - 反正弦
648
+ - \`acos(x)\` - 反余弦
649
+ - \`atan(x)\` - 反正切
650
+
651
+ ## 双曲函数
652
+
653
+ - \`sinh(x)\` - 双曲正弦
654
+ - \`cosh(x)\` - 双曲余弦
655
+ - \`tanh(x)\` - 双曲正切
656
+ - \`asinh(x)\` - 反双曲正弦
657
+ - \`acosh(x)\` - 反双曲余弦
658
+ - \`atanh(x)\` - 反双曲正切
659
+
660
+ ## 取整函数
661
+
662
+ - \`floor(x)\` - 向下取整
663
+ - \`ceil(x)\` - 向上取整
664
+ - \`trunc(x)\` - 截断小数
665
+ - \`round(x)\` - 四舍五入
666
+
667
+ ## 比较函数
668
+
669
+ - \`max(x, y, ...)\` - 最大值
670
+ - \`min(x, y, ...)\` - 最小值
671
+
672
+ ## 使用示例
673
+
674
+ \`\`\`javascript
675
+ calc("sqrt(16) + pow(2, 3)") // "12"
676
+ calc("sin(0) + cos(0)") // "1"
677
+ calc("max(10, 20, 30)") // "30"
678
+ calc("floor(3.7) + ceil(3.2)") // "7"
679
+ calc("ln(exp(1))") // "1"
680
+ \`\`\`
681
+
682
+ ## 函数嵌套
683
+
684
+ 函数可以嵌套使用:
685
+
686
+ \`\`\`javascript
687
+ calc("sqrt(pow(3, 2) + pow(4, 2))") // "5" (勾股定理)
688
+ calc("round(sqrt(2) * 100) / 100") // "1.41"
689
+ \`\`\`
690
+ `,
691
+
692
+ "acalc://guide/conditional": `# 条件表达式和运算符
693
+
694
+ ## 条件表达式
695
+
696
+ a-calc 支持三元条件表达式:
697
+
698
+ \`\`\`javascript
699
+ calc("score >= 60 ? '及格' : '不及格'", {score: 75}) // "及格"
700
+ calc("age >= 18 ? 'adult' : 'minor'", {age: 20}) // "adult"
701
+ \`\`\`
702
+
703
+ ## 比较运算符
704
+
705
+ - \`>\` - 大于
706
+ - \`<\` - 小于
707
+ - \`>=\` - 大于等于
708
+ - \`<=\` - 小于等于
709
+ - \`==\` - 等于
710
+ - \`!=\` - 不等于
711
+
712
+ **示例:**
713
+ \`\`\`javascript
714
+ calc("10 > 5") // "1" (true)
715
+ calc("10 < 5") // "0" (false)
716
+ calc("10 == 10") // "1"
717
+ calc("10 != 5") // "1"
718
+ \`\`\`
719
+
720
+ ## 逻辑运算符
721
+
722
+ - \`&&\` - 逻辑与
723
+ - \`||\` - 逻辑或
724
+ - \`!\` - 逻辑非
725
+
726
+ **示例:**
727
+ \`\`\`javascript
728
+ calc("(10 > 5) && (20 > 10)") // "1" (true)
729
+ calc("(10 > 5) || (20 < 10)") // "1" (true)
730
+ calc("!(10 > 5)") // "0" (false)
731
+ \`\`\`
732
+
733
+ ## 链式比较
734
+
735
+ a-calc 支持链式比较表达式:
736
+
737
+ \`\`\`javascript
738
+ calc("1 < x < 10", {x: 5}) // "1" (true)
739
+ calc("0 <= score <= 100", {score: 85}) // "1" (true)
740
+ \`\`\`
741
+
742
+ ## 复杂条件
743
+
744
+ 可以组合使用条件和逻辑运算:
745
+
746
+ \`\`\`javascript
747
+ calc("(score >= 90) ? 'A' : (score >= 80) ? 'B' : (score >= 60) ? 'C' : 'D'", {score: 85})
748
+ // "B"
749
+
750
+ calc("(age >= 18 && hasLicense) ? 'can drive' : 'cannot drive'", {
751
+ age: 20,
752
+ hasLicense: 1
753
+ }) // "can drive"
754
+ \`\`\`
755
+ `,
756
+
757
+ "acalc://examples/common": `# 常见使用示例
758
+
759
+ ## 金融计算
760
+
761
+ ### 价格计算
762
+ \`\`\`javascript
763
+ // 含税价格 - 如果有 product 对象包含 price 和 taxRate
764
+ const product = {price: 100, taxRate: 0.13}
765
+ calc("price * (1 + taxRate) | =2", product) // "113.00"
766
+
767
+ // 折扣价格 - 直接传入商品对象
768
+ const item = {price: 199.9, discount: 0.8}
769
+ calc("price * discount | =2", item) // "159.92"
770
+
771
+ // 订单总价 - 直接传入订单对象
772
+ const order = {price: 99.9, qty: 3, shipping: 15}
773
+ calc("price * qty + shipping | =2,", order) // "314.70"
774
+ \`\`\`
775
+
776
+ ### 利率计算
777
+ \`\`\`javascript
778
+ // 单利 - 直接传入投资对象
779
+ const investment = {principal: 10000, rate: 0.05, time: 2}
780
+ calc("principal * rate * time | =2", investment) // "1000.00"
781
+
782
+ // 复利
783
+ calc("principal * pow(1 + rate, time) - principal | =2", investment) // "1025.00"
784
+ \`\`\`
785
+
786
+ ## 电商场景
787
+
788
+ ### 购物车计算
789
+ \`\`\`javascript
790
+ const items = [
791
+ {price: 99.9, qty: 2},
792
+ {price: 49.9, qty: 3},
793
+ {price: 199, qty: 1}
794
+ ]
795
+
796
+ calc_sum("price * qty | =2", items) // "548.50"
797
+ \`\`\`
798
+
799
+ ### 优惠券计算
800
+ \`\`\`javascript
801
+ const cart = {total: 250}
802
+ calc("total > 200 ? total * 0.9 : total | =2", cart) // "225.00"
803
+ \`\`\`
804
+
805
+ ## 数据格式化
806
+
807
+ ### 金额显示
808
+ \`\`\`javascript
809
+ fmt(1234567.89, ",=2") // "1,234,567.89"
810
+ fmt(1234567, "!v") // "1.23M"
811
+ \`\`\`
812
+
813
+ ### 百分比显示
814
+ \`\`\`javascript
815
+ fmt(0.1234, "%=2") // "12.34%"
816
+ fmt(0.0523, "%=2+") // "+5.23%" (涨跌幅)
817
+ \`\`\`
818
+
819
+ ### 科学计数法
820
+ \`\`\`javascript
821
+ fmt(123456789, "!e=2") // "1.23e+8"
822
+ \`\`\`
823
+
824
+ ## 统计计算
825
+
826
+ ### 平均值
827
+ \`\`\`javascript
828
+ const values = [10, 20, 30, 40, 50]
829
+ const sum = add(...values) // 150
830
+ const avg = div(sum, values.length) // 30
831
+ \`\`\`
832
+
833
+ ### 标准差
834
+ \`\`\`javascript
835
+ import { add, div, sqrt, sub, mul } from 'a-calc'
836
+
837
+ const values = [10, 20, 30, 40, 50]
838
+ const avg = 30
839
+ const variance = div(
840
+ add(...values.map(v => mul(sub(v, avg), sub(v, avg)))),
841
+ values.length
842
+ ) // 200
843
+ const stdDev = sqrt(variance) // 14.142...
844
+ \`\`\`
845
+
846
+ ## 单位计算
847
+
848
+ ### 带单位的计算
849
+ \`\`\`javascript
850
+ calc("100元 + 50元", {_unit: true}) // "150元"
851
+ calc("10% + 5%", {_unit: true}) // "15%"
852
+ calc("1.5kg * 2", {_unit: true}) // "3kg"
853
+ \`\`\`
854
+
855
+ ## 链式计算
856
+
857
+ ### 复杂运算
858
+ \`\`\`javascript
859
+ // (100 + 200) * 0.8 - 50
860
+ cadd(100, 200).mul(0.8).sub(50)("=2") // "190.00"
861
+
862
+ // 价格计算链
863
+ cmul(99.9, 3) // 单价 * 数量
864
+ .mul(0.9) // 打9折
865
+ .add(15) // 加运费
866
+ ("=2,") // "284.73"
867
+ \`\`\`
868
+ `
869
+ };
870
+
871
+ // ==================== Prompts 定义 ====================
872
+
873
+ const PROMPTS = [
874
+ {
875
+ name: "a-calc",
876
+ description: "强制在所有数值计算中使用 a-calc(推荐)",
877
+ arguments: [],
878
+ },
879
+ ];
880
+
881
+ const PROMPT_CONTENTS = {
882
+ "a-calc": {
883
+ messages: [
884
+ {
885
+ role: "user",
886
+ content: {
887
+ type: "text",
888
+ text: `# 数值计算强制规则
889
+
890
+ ⚠️ **重要:在本次对话中,所有数值计算必须使用 a-calc MCP 工具!**
891
+
892
+ ## 强制使用场景
893
+
894
+ ### 1. 任何涉及小数的运算(必须使用)
895
+ - ✅ 使用 calc("0.1 + 0.2")
896
+ - ❌ 不要直接计算 0.1 + 0.2
897
+
898
+ ### 2. 价格和金额计算(必须使用)
899
+ - ✅ 使用 calc("price * qty | =2", item) // 直接传入对象
900
+ - ❌ 不要使用 JavaScript 的 * 运算符
901
+
902
+ ### 3. 百分比和折扣计算(必须使用)
903
+ - ✅ 使用 calc("price * 0.9 | =2", product) // 直接传入对象
904
+ - ❌ 不要直接计算
905
+
906
+ ### 4. 需要格式化的数值(必须使用)
907
+ - ✅ 使用 fmt(1234567, ",") 或 calc("value | ,", data)
908
+ - ❌ 不要使用 toLocaleString()
909
+
910
+ ### 5. 批量数据计算(必须使用)
911
+ - ✅ 使用 calc_sum("price * qty", items)
912
+ - ❌ 不要使用 reduce() 或 forEach() 手动累加
913
+
914
+ ## 可以不使用的场景
915
+
916
+ 只有以下情况可以不使用 a-calc:
917
+ - 简单的整数加减:1 + 1, 10 - 5
918
+ - 数组长度、索引等非计算场景
919
+
920
+ ## 为什么必须使用 a-calc?
921
+
922
+ JavaScript 的浮点数精度问题:
923
+ - 0.1 + 0.2 = 0.30000000000000004 ❌
924
+ - 0.3 - 0.1 = 0.19999999999999998 ❌
925
+ - 99.9 * 3 = 299.70000000000005 ❌
926
+
927
+ 使用 a-calc 后:
928
+ - calc("0.1 + 0.2") = "0.3" ✅
929
+ - calc("0.3 - 0.1") = "0.2" ✅
930
+ - calc("99.9 * 3") = "299.7" ✅
931
+
932
+ ## 编码规范和最佳实践
933
+
934
+ ### ❌ 错误写法 1:使用模板字符串拼接
935
+ \`\`\`javascript
936
+ // 不要这样写!
937
+ let total = '0'
938
+ cart.forEach(item => {
939
+ total = calc(\`\${total} + \${item.price} * \${item.quantity}\`)
940
+ })
941
+ \`\`\`
942
+ **问题**:代码不清晰、难以维护、性能差
943
+
944
+ ### ❌ 错误写法 2:重复写字段名(冗余)
945
+ \`\`\`javascript
946
+ // 不要这样写!
947
+ const itemTotal = calc("price * qty | =2", {
948
+ price: item.price,
949
+ qty: item.qty
950
+ })
951
+ \`\`\`
952
+ **问题**:代码冗余、不简洁、重复劳动
953
+
954
+ ### ✅ 正确写法 1:使用 calc_sum(批量计算)
955
+ \`\`\`javascript
956
+ const total = calc_sum("price * qty | =2", cart)
957
+ \`\`\`
958
+
959
+ ### ✅ 正确写法 2:直接传入对象(最优雅)
960
+ \`\`\`javascript
961
+ // 对象已有所需字段,直接传入
962
+ const itemTotal = calc("price * qty | =2", item)
963
+ \`\`\`
964
+
965
+ ### ✅ 正确写法 3:使用变量简写
966
+ \`\`\`javascript
967
+ // 多个独立变量,使用简写
968
+ const result = calc("a + b", {a, b})
969
+ \`\`\`
970
+
971
+ ### ✅ 正确写法 4:数组映射
972
+ \`\`\`javascript
973
+ // 对每个对象进行计算
974
+ const results = items.map(item => calc("price * qty | =2", item))
975
+ \`\`\`
976
+
977
+ ### 完整示例:购物车计算
978
+
979
+ \`\`\`javascript
980
+ import { calc, calc_sum, fmt } from 'a-calc'
981
+
982
+ // ❌ 错误:使用模板字符串累加
983
+ const wrongTotal = () => {
984
+ let total = '0'
985
+ cart.forEach(item => {
986
+ total = calc(\`\${total} + \${item.price} * \${item.quantity}\`)
987
+ })
988
+ return total
989
+ }
990
+
991
+ // ✅ 正确:使用 calc_sum
992
+ const correctTotal = () => {
993
+ return calc_sum("price * quantity | =2", cart)
994
+ }
995
+
996
+ // ✅ 正确:单个商品小计(直接传入 item 对象)
997
+ const itemSubtotal = (item) => {
998
+ return calc("price * quantity | =2", item)
999
+ }
1000
+
1001
+ // ✅ 正确:应用折扣(直接传入对象)
1002
+ const applyDiscount = (order) => {
1003
+ return calc("total * (1 - discountRate) | =2", order)
1004
+ }
1005
+
1006
+ // ✅ 正确:含税价格(直接传入对象)
1007
+ const withTax = (order) => {
1008
+ return calc("subtotal * (1 + taxRate) | =2", order)
1009
+ }
1010
+ \`\`\`
1011
+
1012
+ ## 核心原则
1013
+
1014
+ 1. **批量计算用 calc_sum** - 不要用 forEach 累加
1015
+ 2. **变量用第二参数注入** - 不要用模板字符串拼接
1016
+ 3. **保持表达式简洁** - 一次计算完成,不要分步累加
1017
+ 4. **使用格式化** - 用 \`| =2\` 保留小数位
1018
+
1019
+ ## 实施要求
1020
+
1021
+ 在编写代码时:
1022
+ 1. 遇到数值计算,立即考虑是否需要使用 a-calc
1023
+ 2. 涉及小数、金额、价格的,必须使用 a-calc
1024
+ 3. 优先使用 calc_sum 处理数组数据
1025
+ 4. 使用第二参数注入变量,不要用模板字符串
1026
+ 5. 在代码注释中说明为什么使用 a-calc
1027
+
1028
+ 请确认你理解并将严格遵守这些规则。`,
1029
+ },
1030
+ },
1031
+ ],
1032
+ },
1033
+ };
1034
+
1035
+ // ==================== Server Setup ====================
1036
+
1037
+ const server = new Server(
1038
+ {
1039
+ name: "a-calc-mcp-server",
1040
+ version: "1.0.0",
1041
+ },
1042
+ {
1043
+ capabilities: {
1044
+ tools: {},
1045
+ resources: {},
1046
+ prompts: {},
1047
+ },
1048
+ }
1049
+ );
1050
+
1051
+ // ==================== Tool Handlers ====================
1052
+
1053
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
1054
+ return { tools: TOOLS };
1055
+ });
1056
+
1057
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1058
+ const { name, arguments: args } = request.params;
1059
+
1060
+ try {
1061
+ switch (name) {
1062
+ case "calc": {
1063
+ const { expr, options = {} } = args;
1064
+ const result = calc(expr, options);
1065
+ return {
1066
+ content: [
1067
+ {
1068
+ type: "text",
1069
+ text: JSON.stringify({ result, type: typeof result }),
1070
+ },
1071
+ ],
1072
+ };
1073
+ }
1074
+
1075
+ case "fmt": {
1076
+ const { value, format_str, options = {} } = args;
1077
+ const result = fmt(value, format_str, options);
1078
+ return {
1079
+ content: [
1080
+ {
1081
+ type: "text",
1082
+ text: JSON.stringify({ result, type: typeof result }),
1083
+ },
1084
+ ],
1085
+ };
1086
+ }
1087
+
1088
+ case "calc_sum": {
1089
+ const { expr, data_array } = args;
1090
+ const result = calc_sum(expr, data_array);
1091
+ return {
1092
+ content: [
1093
+ {
1094
+ type: "text",
1095
+ text: JSON.stringify({ result, type: typeof result }),
1096
+ },
1097
+ ],
1098
+ };
1099
+ }
1100
+
1101
+ case "basic_calc": {
1102
+ const { operation, args: calcArgs } = args;
1103
+ let result;
1104
+
1105
+ switch (operation) {
1106
+ case "add":
1107
+ result = add(...calcArgs);
1108
+ break;
1109
+ case "sub":
1110
+ result = sub(...calcArgs);
1111
+ break;
1112
+ case "mul":
1113
+ result = mul(...calcArgs);
1114
+ break;
1115
+ case "div":
1116
+ result = div(...calcArgs);
1117
+ break;
1118
+ case "mod":
1119
+ result = mod(...calcArgs);
1120
+ break;
1121
+ case "pow":
1122
+ result = pow(...calcArgs);
1123
+ break;
1124
+ case "idiv":
1125
+ result = idiv(...calcArgs);
1126
+ break;
1127
+ case "abs":
1128
+ result = abs(calcArgs[0]);
1129
+ break;
1130
+ case "neg":
1131
+ result = neg(calcArgs[0]);
1132
+ break;
1133
+ case "sqrt":
1134
+ result = sqrt(calcArgs[0]);
1135
+ break;
1136
+ case "ln":
1137
+ result = ln(calcArgs[0]);
1138
+ break;
1139
+ case "exp":
1140
+ result = exp(calcArgs[0]);
1141
+ break;
1142
+ default:
1143
+ throw new Error(`Unknown operation: ${operation}`);
1144
+ }
1145
+
1146
+ return {
1147
+ content: [
1148
+ {
1149
+ type: "text",
1150
+ text: JSON.stringify({ result, type: typeof result }),
1151
+ },
1152
+ ],
1153
+ };
1154
+ }
1155
+
1156
+ case "chain_calc": {
1157
+ const { start_op, start_args, chain_ops = [], format } = args;
1158
+
1159
+ let chainFn;
1160
+ switch (start_op) {
1161
+ case "cadd":
1162
+ chainFn = cadd(...start_args);
1163
+ break;
1164
+ case "csub":
1165
+ chainFn = csub(...start_args);
1166
+ break;
1167
+ case "cmul":
1168
+ chainFn = cmul(...start_args);
1169
+ break;
1170
+ case "cdiv":
1171
+ chainFn = cdiv(...start_args);
1172
+ break;
1173
+ default:
1174
+ throw new Error(`Unknown start operation: ${start_op}`);
1175
+ }
1176
+
1177
+ for (const { op, args: opArgs } of chain_ops) {
1178
+ switch (op) {
1179
+ case "add":
1180
+ chainFn = chainFn.add(...opArgs);
1181
+ break;
1182
+ case "sub":
1183
+ chainFn = chainFn.sub(...opArgs);
1184
+ break;
1185
+ case "mul":
1186
+ chainFn = chainFn.mul(...opArgs);
1187
+ break;
1188
+ case "div":
1189
+ chainFn = chainFn.div(...opArgs);
1190
+ break;
1191
+ case "mod":
1192
+ chainFn = chainFn.mod(...opArgs);
1193
+ break;
1194
+ case "pow":
1195
+ chainFn = chainFn.pow(...opArgs);
1196
+ break;
1197
+ case "idiv":
1198
+ chainFn = chainFn.idiv(...opArgs);
1199
+ break;
1200
+ default:
1201
+ throw new Error(`Unknown chain operation: ${op}`);
1202
+ }
1203
+ }
1204
+
1205
+ const result = format ? chainFn(format) : chainFn();
1206
+ return {
1207
+ content: [
1208
+ {
1209
+ type: "text",
1210
+ text: JSON.stringify({ result, type: typeof result }),
1211
+ },
1212
+ ],
1213
+ };
1214
+ }
1215
+
1216
+ case "get_acalc_guide": {
1217
+ const { topic } = args;
1218
+ let content = "";
1219
+
1220
+ if (topic === "all") {
1221
+ content = Object.values(RESOURCE_CONTENTS).join("\n\n---\n\n");
1222
+ } else {
1223
+ const resourceMap = {
1224
+ api: "acalc://api/overview",
1225
+ formatting: "acalc://guide/formatting",
1226
+ functions: "acalc://guide/functions",
1227
+ conditional: "acalc://guide/conditional",
1228
+ chain: "acalc://api/overview",
1229
+ examples: "acalc://examples/common",
1230
+ };
1231
+
1232
+ const uri = resourceMap[topic];
1233
+ if (uri && RESOURCE_CONTENTS[uri]) {
1234
+ content = RESOURCE_CONTENTS[uri];
1235
+ } else {
1236
+ throw new Error(`Unknown topic: ${topic}`);
1237
+ }
1238
+ }
1239
+
1240
+ return {
1241
+ content: [
1242
+ {
1243
+ type: "text",
1244
+ text: content,
1245
+ },
1246
+ ],
1247
+ };
1248
+ }
1249
+
1250
+ case "debug_info": {
1251
+ const debugInfo = {
1252
+ cwd: process.cwd(),
1253
+ __dirname: import.meta.url,
1254
+ node_version: process.version,
1255
+ platform: process.platform,
1256
+ arch: process.arch,
1257
+ env: {
1258
+ HOME: process.env.HOME,
1259
+ USERPROFILE: process.env.USERPROFILE,
1260
+ PATH: process.env.PATH?.split(process.platform === 'win32' ? ';' : ':').slice(0, 5).join('\n '),
1261
+ NODE_ENV: process.env.NODE_ENV,
1262
+ },
1263
+ };
1264
+
1265
+ return {
1266
+ content: [
1267
+ {
1268
+ type: "text",
1269
+ text: JSON.stringify(debugInfo, null, 2),
1270
+ },
1271
+ ],
1272
+ };
1273
+ }
1274
+
1275
+ default:
1276
+ throw new Error(`Unknown tool: ${name}`);
1277
+ }
1278
+ } catch (error) {
1279
+ return {
1280
+ content: [
1281
+ {
1282
+ type: "text",
1283
+ text: JSON.stringify({
1284
+ error: error.message,
1285
+ stack: error.stack,
1286
+ }),
1287
+ },
1288
+ ],
1289
+ isError: true,
1290
+ };
1291
+ }
1292
+ });
1293
+
1294
+ // ==================== Resource Handlers ====================
1295
+
1296
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
1297
+ return { resources: RESOURCES };
1298
+ });
1299
+
1300
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1301
+ const { uri } = request.params;
1302
+
1303
+ if (RESOURCE_CONTENTS[uri]) {
1304
+ return {
1305
+ contents: [
1306
+ {
1307
+ uri,
1308
+ mimeType: "text/markdown",
1309
+ text: RESOURCE_CONTENTS[uri],
1310
+ },
1311
+ ],
1312
+ };
1313
+ }
1314
+
1315
+ throw new Error(`Resource not found: ${uri}`);
1316
+ });
1317
+
1318
+ // ==================== Prompt Handlers ====================
1319
+
1320
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
1321
+ return { prompts: PROMPTS };
1322
+ });
1323
+
1324
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
1325
+ const { name } = request.params;
1326
+
1327
+ if (PROMPT_CONTENTS[name]) {
1328
+ return PROMPT_CONTENTS[name];
1329
+ }
1330
+
1331
+ throw new Error(`Prompt not found: ${name}`);
1332
+ });
1333
+
1334
+ // ==================== Start Server ====================
1335
+
1336
+ async function main() {
1337
+ // 解析命令行参数
1338
+ const args = process.argv.slice(2);
1339
+ const cwdIndex = args.indexOf('--cwd');
1340
+
1341
+ if (cwdIndex !== -1 && args[cwdIndex + 1]) {
1342
+ const targetCwd = args[cwdIndex + 1];
1343
+ try {
1344
+ process.chdir(targetCwd);
1345
+ console.error(`Changed working directory to: ${process.cwd()}`);
1346
+ } catch (error) {
1347
+ console.error(`Failed to change directory to ${targetCwd}:`, error.message);
1348
+ }
1349
+ }
1350
+
1351
+ const transport = new StdioServerTransport();
1352
+ await server.connect(transport);
1353
+ console.error("a-calc MCP Server running on stdio");
1354
+ console.error(`Working directory: ${process.cwd()}`);
1355
+ }
1356
+
1357
+ main().catch((error) => {
1358
+ console.error("Fatal error:", error);
1359
+ process.exit(1);
1360
+ });