@fjyueke/bify-mcp 1.0.3 → 1.0.5

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.
Files changed (3) hide show
  1. package/README.md +68 -5
  2. package/dist/index.js +107 -25
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,26 +9,89 @@
9
9
 
10
10
  Bify 是基于 Taroify 的移动端组件库,基于 Vant 视觉规范,提供一致的 API 接口,助力开发者快速搭建小程序应用。
11
11
 
12
- Bify MCP 是一项独立的 MCP(模型上下文协议)服务,旨在将 Bify 与大模型连接起来。它使大模型能够直接从文档中检索组件、API数据。
12
+ Bify MCP 是一项独立的 MCP(模型上下文协议)服务,旨在将 Bify 与大模型连接起来。它使大模型能够直接从文档中检索组件、API 数据,并支持 Arco Mobile → Bify 代码转换。
13
13
 
14
14
  - 直接使用 npx 运行
15
15
  - 无需外部依赖,只需要 Node 环境
16
+ - 支持 68+ 个组件文档查询
17
+ - 支持 Arco Mobile 代码转换
16
18
 
17
- ## Cursor 用法
19
+ ## 配置方式
18
20
 
19
- Cursor Mcp 使用指南参考:<https://docs.cursor.com/context/model-context-protocol#using-mcp-tools-in-agent>
21
+ ### Cursor
20
22
 
21
- ``` json
23
+ ```json
22
24
  {
23
25
  "mcpServers": {
24
26
  "@fjyueke/bify-mcp": {
25
27
  "command": "npx",
26
28
  "args": [
27
29
  "-y",
28
- "@fjyueke/bify-mcp",
30
+ "@fjyueke/bify-mcp"
29
31
  ],
30
32
  "env": {}
31
33
  }
32
34
  }
33
35
  }
34
36
  ```
37
+
38
+ ### Trae
39
+
40
+ 在 `.trae/skills/` 目录下创建配置文件,或在 Trae 设置中添加 MCP 服务。
41
+
42
+ ### 其他支持 MCP 的 IDE
43
+
44
+ 参考对应 IDE 的 MCP 配置文档,使用上述配置格式。
45
+
46
+ ## 可用工具
47
+
48
+ | 工具名 | 功能 |
49
+ |--------|------|
50
+ | `list-components` | 列出所有可用的 Bify 组件 |
51
+ | `get-component-docs` | 获取指定组件的详细文档 |
52
+ | `get-component-props` | 获取指定组件的属性和 API 文档 |
53
+ | `list-component-example` | 获取指定组件的所有示例代码 |
54
+ | `convert-arco-to-bify` | 将 Arco Mobile React 代码转换为 Bify 代码 |
55
+ | `get-arco-conversion-help` | 获取 Arco Mobile → Bify 转换帮助信息 |
56
+
57
+ ## 使用示例
58
+
59
+ ### 查询组件文档
60
+
61
+ ```bash
62
+ # 列出所有组件
63
+ list-components
64
+
65
+ # 获取 Cell 组件文档
66
+ get-component-docs Cell
67
+
68
+ # 获取 Cell 组件属性
69
+ get-component-props Cell
70
+
71
+ # 获取 Cell 组件示例
72
+ list-component-example Cell
73
+ ```
74
+
75
+ ### Arco Mobile 代码转换
76
+
77
+ ```bash
78
+ # 获取转换帮助
79
+ get-arco-conversion-help
80
+
81
+ # 转换代码
82
+ convert-arco-to-bify "<Cell label='标题' desc='描述' showArrow>内容</Cell>"
83
+ ```
84
+
85
+ ## 版本历史
86
+
87
+ | 版本 | 日期 | 说明 |
88
+ |------|------|------|
89
+ | 1.0.3 | 2026-07-13 | 优化代码转换工具,增加 40+ 组件映射、值映射、布尔属性转换 |
90
+ | 1.0.2 | 2026-07-13 | 添加 Arco Mobile → Bify 代码转换功能 |
91
+ | 1.0.1 | 2026-07-13 | 更正包名为 bify-mcp |
92
+ | 1.0.0 | 2026-07-13 | 初始版本,支持 68+ 组件文档查询 |
93
+
94
+ ## 相关链接
95
+
96
+ - npm 包地址:https://www.npmjs.com/package/@fjyueke/bify-mcp
97
+ - Bify 组件库:https://github.com/fjyueke/bify
package/dist/index.js CHANGED
@@ -616,20 +616,36 @@ function findAllArcoComponents() {
616
616
 
617
617
  // src/services/arco-converter.ts
618
618
  async function convertArcoToBify(arcoCode) {
619
+ const warnings = [];
620
+ const suggestions = [];
621
+ const usedMappings = [];
619
622
  let result = arcoCode;
620
- result = convertImports(result);
621
- result = convertComponents(result);
623
+ const importsResult = convertImports(result, warnings);
624
+ result = importsResult.code;
625
+ usedMappings.push(...importsResult.mappings);
626
+ const componentsResult = convertComponents(result, warnings, suggestions);
627
+ result = componentsResult.code;
628
+ usedMappings.push(...componentsResult.mappings);
622
629
  result = convertIconImports(result);
623
630
  result = fixCodeFormat(result);
624
- return result;
631
+ const uniqueMappings = usedMappings.filter(
632
+ (m, index, self) => self.findIndex((t) => t.arcoName === m.arcoName) === index
633
+ );
634
+ return {
635
+ code: result,
636
+ mappings: uniqueMappings,
637
+ warnings,
638
+ suggestions
639
+ };
625
640
  }
626
- function convertImports(code) {
641
+ function convertImports(code, warnings) {
627
642
  let result = code;
643
+ const usedMappings = [];
628
644
  const arcoImportRegex = /import\s+([\s\S]*?)\s+from\s+['"]@arco-design\/mobile-react['"]/g;
629
645
  const matches = [...code.matchAll(arcoImportRegex)];
630
646
  const bifyCoreComponents = [];
631
647
  const bifyIconComponents = [];
632
- const remainingComponents = [];
648
+ const unsupportedComponents = [];
633
649
  for (const match of matches) {
634
650
  const importContent = match[1].trim();
635
651
  const namedImportRegex = /\{([\s\S]*?)\}/;
@@ -639,17 +655,16 @@ function convertImports(code) {
639
655
  for (const component of components) {
640
656
  const mapping = findMappingByArcoName(component);
641
657
  if (mapping) {
658
+ usedMappings.push(mapping);
642
659
  if (mapping.bifyImport === "@fjyueke/bify-icons") {
643
660
  bifyIconComponents.push(component);
644
661
  } else {
645
662
  bifyCoreComponents.push(mapping.bifyName || component);
646
663
  }
647
664
  } else {
648
- remainingComponents.push(component);
665
+ unsupportedComponents.push(component);
649
666
  }
650
667
  }
651
- } else {
652
- remainingComponents.push(importContent);
653
668
  }
654
669
  result = result.replace(match[0], "");
655
670
  }
@@ -666,22 +681,29 @@ function convertImports(code) {
666
681
  `;
667
682
  result = iconImport + result;
668
683
  }
669
- return result;
684
+ if (unsupportedComponents.length > 0) {
685
+ warnings.push(`\u4EE5\u4E0B\u7EC4\u4EF6\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u8F6C\u6362\uFF1A${unsupportedComponents.join(", ")}`);
686
+ }
687
+ return { code: result, mappings: usedMappings };
670
688
  }
671
- function convertComponents(code) {
689
+ function convertComponents(code, warnings, suggestions) {
672
690
  let result = code;
691
+ const usedMappings = [];
673
692
  const arcoComponents = findAllArcoComponents();
674
693
  for (const arcoComponent of arcoComponents) {
675
694
  const mapping = findMappingByArcoName(arcoComponent);
676
695
  if (!mapping || !mapping.bifyName) continue;
696
+ const componentPattern = new RegExp(`<${arcoComponent}`, "g");
697
+ if (!componentPattern.test(code)) continue;
698
+ usedMappings.push(mapping);
677
699
  const bifyComponent = mapping.bifyName;
678
- const componentRegex = new RegExp(
700
+ const selfClosingRegex = new RegExp(
679
701
  `<${arcoComponent}([^>]*)\\/?>`,
680
702
  "g"
681
703
  );
682
- result = result.replace(componentRegex, (match, props) => {
704
+ result = result.replace(selfClosingRegex, (match, props) => {
683
705
  let newProps = props;
684
- newProps = applyPropMappings(newProps, mapping);
706
+ newProps = applyPropMappings(newProps, mapping, warnings);
685
707
  newProps = applyValueMappings(newProps, mapping);
686
708
  return `<${bifyComponent}${newProps}/>`;
687
709
  });
@@ -691,15 +713,23 @@ function convertComponents(code) {
691
713
  );
692
714
  result = result.replace(closingComponentRegex, (match, props, children) => {
693
715
  let newProps = props;
694
- newProps = applyPropMappings(newProps, mapping);
716
+ newProps = applyPropMappings(newProps, mapping, warnings);
695
717
  newProps = applyValueMappings(newProps, mapping);
696
718
  return `<${bifyComponent}${newProps}>${children}</${bifyComponent}>`;
697
719
  });
720
+ addSuggestions(mapping, suggestions);
698
721
  }
699
- return result;
722
+ return { code: result, mappings: usedMappings };
700
723
  }
701
- function applyPropMappings(props, mapping) {
724
+ function applyPropMappings(props, mapping, warnings) {
702
725
  let result = props;
726
+ const arcoProps = props.match(/\b(\w+)=/g)?.map((p) => p.slice(0, -1)) || [];
727
+ const mappedProps = mapping.propMappings.map((m) => m.arcoProp);
728
+ for (const arcoProp of arcoProps) {
729
+ if (!mappedProps.includes(arcoProp) && !["className", "style", "children"].includes(arcoProp)) {
730
+ warnings.push(`\u7EC4\u4EF6 ${mapping.arcoName} \u7684\u5C5E\u6027 ${arcoProp} \u672A\u627E\u5230\u6620\u5C04\uFF0C\u5DF2\u4FDD\u7559\u539F\u6837`);
731
+ }
732
+ }
703
733
  for (const propMapping of mapping.propMappings) {
704
734
  const propRegex = new RegExp(
705
735
  `${propMapping.arcoProp}=(["'])(.*?)\\1`,
@@ -731,7 +761,10 @@ function applyValueMappings(props, mapping) {
731
761
  );
732
762
  result = result.replace(propRegex, (match, quote, value) => {
733
763
  const mappedValue = valueMap[value] || value;
734
- return `${propName}=${quote}${mappedValue}${quote}`;
764
+ if (mappedValue !== value) {
765
+ return `${propName}=${quote}${mappedValue}${quote}`;
766
+ }
767
+ return match;
735
768
  });
736
769
  }
737
770
  return result;
@@ -753,6 +786,18 @@ function fixCodeFormat(code) {
753
786
  result = nonEmptyLines.join("\n");
754
787
  return result.trim();
755
788
  }
789
+ function addSuggestions(mapping, suggestions) {
790
+ const suggestionMap = {
791
+ Cell: "Bify \u7684 Cell \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u5E03\u5C40\u5C5E\u6027\uFF0C\u5EFA\u8BAE\u67E5\u770B\u6587\u6863\u4E86\u89E3 align\u3001size \u7B49\u5C5E\u6027",
792
+ Button: "Bify \u7684 Button \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u6837\u5F0F\u53D8\u4F53\uFF0C\u5EFA\u8BAE\u67E5\u770B variant \u5C5E\u6027",
793
+ Dialog: "Bify \u7684 Dialog \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u4EA4\u4E92\u9009\u9879\uFF0C\u5EFA\u8BAE\u67E5\u770B closeOnClickOverlay \u7B49\u5C5E\u6027",
794
+ Tabs: "Bify \u7684 Tabs \u7EC4\u4EF6\u652F\u6301\u6ED1\u52A8\u5207\u6362\uFF0C\u5EFA\u8BAE\u67E5\u770B swipeable \u5C5E\u6027",
795
+ Field: "Bify \u7684 Field \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u9A8C\u8BC1\u5C5E\u6027\uFF0C\u5EFA\u8BAE\u67E5\u770B rules \u5C5E\u6027"
796
+ };
797
+ if (suggestionMap[mapping.arcoName]) {
798
+ suggestions.push(suggestionMap[mapping.arcoName]);
799
+ }
800
+ }
756
801
  async function getArcoConversionHelp() {
757
802
  const availableComponents = componentMappings.filter((m) => m.bifyName).map((m) => `- ${m.arcoName} \u2192 ${m.bifyName}`).join("\n");
758
803
  const valueMappingExamples = componentMappings.filter((m) => m.valueMappings).map((m) => {
@@ -806,9 +851,15 @@ import { Cell, CellGroup, Button } from '@fjyueke/bify-core';
806
851
  | \`max\` | \`count\` | Rate \u6700\u5927\u6570\u91CF |
807
852
  | \`percent\` | \`percentage\` | Progress \u767E\u5206\u6BD4 |
808
853
 
854
+ ### \u6700\u4F73\u5B9E\u8DF5
855
+
856
+ 1. **\u4F7F\u7528 AI \u8F85\u52A9\u8F6C\u6362**\uFF1A\u540C\u65F6\u914D\u7F6E Arco Mobile MCP \u548C Bify MCP\uFF0C\u8BA9 AI \u67E5\u8BE2\u53CC\u65B9\u6587\u6863\u540E\u518D\u8FDB\u884C\u8F6C\u6362
857
+ 2. **\u624B\u52A8\u68C0\u67E5**\uFF1A\u8F6C\u6362\u540E\u8BF7\u68C0\u67E5\u8B66\u544A\u4FE1\u606F\uFF0C\u5904\u7406\u672A\u6620\u5C04\u7684\u5C5E\u6027
858
+ 3. **\u53C2\u8003\u6587\u6863**\uFF1A\u4F7F\u7528 \`get-component-docs\` \u548C \`get-component-props\` \u67E5\u770B Bify \u7EC4\u4EF6\u7684\u8BE6\u7EC6\u7528\u6CD5
859
+
809
860
  ### \u8C03\u7528\u65B9\u5F0F
810
861
 
811
- \u4F7F\u7528 \`convert-arco-to-bify\` \u5DE5\u5177\uFF0C\u4F20\u5165 Arco Mobile \u4EE3\u7801\u5373\u53EF\u83B7\u5F97\u8F6C\u6362\u540E\u7684 Bify \u4EE3\u7801\u3002`;
862
+ \u4F7F\u7528 \`convert-arco-to-bify\` \u5DE5\u5177\uFF0C\u4F20\u5165 Arco Mobile \u4EE3\u7801\u5373\u53EF\u83B7\u5F97\u8F6C\u6362\u540E\u7684 Bify \u4EE3\u7801\u53CA\u8BE6\u7EC6\u62A5\u544A\u3002`;
812
863
  }
813
864
 
814
865
  // src/tools/components.ts
@@ -880,19 +931,50 @@ function registerTifyTools(server) {
880
931
  );
881
932
  server.tool(
882
933
  "convert-arco-to-bify",
883
- "Converts Arco Mobile React code to Bify code",
934
+ "Converts Arco Mobile React code to Bify code with detailed report including warnings and suggestions",
884
935
  { arcoCode: z.string() },
885
936
  async (args) => {
886
- const convertedCode = await convertArcoToBify(args.arcoCode);
937
+ const result = await convertArcoToBify(args.arcoCode);
938
+ let report = `## \u8F6C\u6362\u7ED3\u679C
939
+
940
+ ### \u8F6C\u6362\u540E\u7684\u4EE3\u7801
941
+
942
+ \`\`\`tsx
943
+ ${result.code}
944
+ \`\`\``;
945
+ if (result.mappings.length > 0) {
946
+ report += `
947
+
948
+ ### \u4F7F\u7528\u7684\u6620\u5C04
949
+
950
+ | Arco \u7EC4\u4EF6 | Bify \u7EC4\u4EF6 |
951
+ |-----------|-----------|
952
+ ${result.mappings.map((m) => `| ${m.arcoName} | ${m.bifyName} |`).join("\n")}`;
953
+ }
954
+ if (result.warnings.length > 0) {
955
+ report += `
956
+
957
+ ### \u26A0\uFE0F \u8B66\u544A
958
+
959
+ - ${result.warnings.join("\n- ")}`;
960
+ }
961
+ if (result.suggestions.length > 0) {
962
+ report += `
963
+
964
+ ### \u{1F4A1} \u5EFA\u8BAE
965
+
966
+ - ${result.suggestions.join("\n- ")}`;
967
+ }
968
+ report += `
969
+
970
+ ### \u8F6C\u6362\u8BF4\u660E
971
+
972
+ \u5982\u9700\u66F4\u7CBE\u786E\u7684\u8F6C\u6362\uFF0C\u5EFA\u8BAE\u540C\u65F6\u4F7F\u7528 Arco Mobile MCP \u548C Bify MCP \u67E5\u8BE2\u53CC\u65B9\u7EC4\u4EF6\u6587\u6863\u540E\u8FDB\u884C\u624B\u52A8\u8C03\u6574\u3002`;
887
973
  return {
888
974
  content: [
889
975
  {
890
976
  type: "text",
891
- text: `## \u8F6C\u6362\u7ED3\u679C
892
-
893
- \`\`\`tsx
894
- ${convertedCode}
895
- \`\`\``
977
+ text: report
896
978
  }
897
979
  ]
898
980
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjyueke/bify-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "MCP UI builder by Bify",
6
6
  "license": "MIT",