@sdata/web-vue-mcp 1.13.0 → 1.15.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.
Files changed (3) hide show
  1. package/README.md +6 -1
  2. package/dist/index.js +170 -188
  3. package/package.json +6 -3
package/README.md CHANGED
@@ -6,7 +6,9 @@
6
6
 
7
7
  [MCP](https://modelcontextprotocol.io/) 是一个让 AI 模型连接外部工具与数据源的开放协议。本服务把 SD Design 组件库的 API 元数据暴露给 AI 助手,使其在编码时无需盲猜组件 Props,而是基于组件库真实导出的接口回答。
8
8
 
9
- 数据来源与组件库对外发布的 `web-types` / `vetur` IDE 元数据一致(均由 [`vue-docgen-api`](https://github.com/vue-styleguidist/vue-docgen) 从组件源码提取),覆盖 85 个文档化组件。
9
+ 服务基于 MCP TypeScript SDK v2,支持当前的 `2026-07-28` 协议,并继续兼容使用 `initialize` 握手的旧版客户端。
10
+
11
+ 数据来源与组件库对外发布的 `web-types` / `vetur` IDE 元数据一致(均由 [`vue-docgen-api`](https://github.com/vue-styleguidist/vue-docgen) 从组件源码提取),覆盖全部文档化组件。
10
12
 
11
13
  ## 安装
12
14
 
@@ -117,6 +119,9 @@ pnpm --filter @sdata/web-vue-mcp run build
117
119
 
118
120
  # 类型检查
119
121
  pnpm --filter @sdata/web-vue-mcp run typecheck
122
+
123
+ # 构建后分别以 2026-07-28 和旧版协议运行 stdio 集成测试
124
+ pnpm --filter @sdata/web-vue-mcp run test
120
125
  ```
121
126
 
122
127
  ## 可用工具
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
2
+ import { McpServer } from "@modelcontextprotocol/server";
3
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
4
+ import * as z from "zod/v4";
5
5
  //#endregion
6
6
  //#region src/index.ts
7
7
  const data = {
8
- version: "3.24.1",
9
- generatedAt: "2026-07-30T02:31:45.857Z",
8
+ version: "3.26.0",
9
+ generatedAt: "2026-08-05T06:12:16.712Z",
10
10
  library: {
11
11
  "name": "@sdata/web-vue",
12
12
  "framework": "Vue 3",
@@ -6300,6 +6300,64 @@ const data = {
6300
6300
  }
6301
6301
  ]
6302
6302
  },
6303
+ {
6304
+ "name": "sd-thinking-orb",
6305
+ "title": "思考球 ThinkingOrb",
6306
+ "category": "反馈",
6307
+ "description": "为 AI、智能体和异步推理场景提供语义明确的点阵思考动效。",
6308
+ "docUrl": "https://sd-design.js.org/components/thinking-orb",
6309
+ "importPath": "@sdata/web-vue",
6310
+ "importName": "ThinkingOrb",
6311
+ "props": [
6312
+ {
6313
+ "name": "state",
6314
+ "type": "ThinkingOrbState",
6315
+ "default": "",
6316
+ "description": {
6317
+ "zh": "当前思考状态",
6318
+ "en": "Current thinking state"
6319
+ }
6320
+ },
6321
+ {
6322
+ "name": "size",
6323
+ "type": "ThinkingOrbSize",
6324
+ "default": "",
6325
+ "description": {
6326
+ "zh": "针对使用场景调优的尺寸",
6327
+ "en": "Purpose-tuned rendered size"
6328
+ }
6329
+ },
6330
+ {
6331
+ "name": "theme",
6332
+ "type": "ThinkingOrbTheme",
6333
+ "default": "",
6334
+ "description": {
6335
+ "zh": "主题模式,auto 跟随最近的 sd-theme 容器",
6336
+ "en": "Theme mode; auto follows the nearest sd-theme container"
6337
+ }
6338
+ },
6339
+ {
6340
+ "name": "speed",
6341
+ "type": "number",
6342
+ "default": "",
6343
+ "description": {
6344
+ "zh": "动画速度倍率",
6345
+ "en": "Animation speed multiplier"
6346
+ }
6347
+ },
6348
+ {
6349
+ "name": "paused",
6350
+ "type": "boolean",
6351
+ "default": "",
6352
+ "description": {
6353
+ "zh": "是否暂停动画",
6354
+ "en": "Whether the animation is paused"
6355
+ }
6356
+ }
6357
+ ],
6358
+ "events": [],
6359
+ "slots": []
6360
+ },
6303
6361
  {
6304
6362
  "name": "sd-tour",
6305
6363
  "title": "漫游式引导 Tour",
@@ -11636,7 +11694,6 @@ const data = {
11636
11694
  const components = data.components;
11637
11695
  const library = data.library;
11638
11696
  const PKG_NAME = "@sdata/web-vue-mcp";
11639
- const PKG_VERSION = "0.1.0";
11640
11697
  const normalizeKey = (value) => value.toLowerCase().trim().replace(/^sd-/, "");
11641
11698
  const byKey = /* @__PURE__ */ new Map();
11642
11699
  for (const component of components) {
@@ -11678,99 +11735,6 @@ const importStatements = (component) => ({
11678
11735
  `app.use(SDVue);`
11679
11736
  ].join("\n")
11680
11737
  });
11681
- const tools = [
11682
- {
11683
- name: "list_components",
11684
- description: "List all SD Design components with their category, bilingual title and API size. Optionally filter by category. Use this first to discover what is available.",
11685
- inputSchema: {
11686
- type: "object",
11687
- properties: { category: {
11688
- type: "string",
11689
- description: "Optional category filter, e.g. 通用 / 布局 / 导航 / 数据展示 / 反馈 / 其他."
11690
- } }
11691
- }
11692
- },
11693
- {
11694
- name: "get_categories",
11695
- description: "List all SD Design component categories with the number of components in each.",
11696
- inputSchema: {
11697
- type: "object",
11698
- properties: {}
11699
- }
11700
- },
11701
- {
11702
- name: "get_component",
11703
- description: "Get full detail for a component: description, import statements, documentation URL, and every documented prop, event and slot (bilingual zh/en). Accepts the tag (sd-button), kebab (button) or PascalCase (Button) name.",
11704
- inputSchema: {
11705
- type: "object",
11706
- properties: { name: {
11707
- type: "string",
11708
- description: "Component name, e.g. \"sd-button\", \"button\" or \"Button\"."
11709
- } },
11710
- required: ["name"]
11711
- }
11712
- },
11713
- {
11714
- name: "search_components",
11715
- description: "Search components by keyword across name, title, description and prop/event/slot text (both Chinese and English). Returns matching components with the fields that matched.",
11716
- inputSchema: {
11717
- type: "object",
11718
- properties: { query: {
11719
- type: "string",
11720
- description: "Search keyword, e.g. \"日期\", \"tree\", \"上传\"."
11721
- } },
11722
- required: ["query"]
11723
- }
11724
- },
11725
- {
11726
- name: "get_component_props",
11727
- description: "Get only the documented props for a component (name, type, default, bilingual description).",
11728
- inputSchema: {
11729
- type: "object",
11730
- properties: { name: {
11731
- type: "string",
11732
- description: "Component name."
11733
- } },
11734
- required: ["name"]
11735
- }
11736
- },
11737
- {
11738
- name: "get_component_events",
11739
- description: "Get only the documented events for a component (name and bilingual description).",
11740
- inputSchema: {
11741
- type: "object",
11742
- properties: { name: {
11743
- type: "string",
11744
- description: "Component name."
11745
- } },
11746
- required: ["name"]
11747
- }
11748
- },
11749
- {
11750
- name: "get_component_slots",
11751
- description: "Get only the documented slots for a component (name and bilingual description).",
11752
- inputSchema: {
11753
- type: "object",
11754
- properties: { name: {
11755
- type: "string",
11756
- description: "Component name."
11757
- } },
11758
- required: ["name"]
11759
- }
11760
- },
11761
- {
11762
- name: "find_by_prop",
11763
- description: "Find components that expose a given prop. Useful for \"which components have a size prop?\" or \"what can I set disabled on?\".",
11764
- inputSchema: {
11765
- type: "object",
11766
- properties: { prop: {
11767
- type: "string",
11768
- description: "Prop name to search for, e.g. \"size\", \"disabled\"."
11769
- } },
11770
- required: ["prop"]
11771
- }
11772
- }
11773
- ];
11774
11738
  const search = (query) => {
11775
11739
  const needle = query.toLowerCase().trim();
11776
11740
  if (!needle) return [];
@@ -11824,94 +11788,112 @@ const findByProp = (prop) => {
11824
11788
  }
11825
11789
  return results;
11826
11790
  };
11827
- const server = new Server({
11828
- name: PKG_NAME,
11829
- version: PKG_VERSION
11830
- }, { capabilities: { tools: {} } });
11831
- server.setRequestHandler(ListToolsRequestSchema, () => ({ tools }));
11832
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
11833
- const { name, arguments: args = {} } = request.params;
11834
- switch (name) {
11835
- case "list_components": {
11836
- const category = args?.category?.trim();
11837
- const list = category ? components.filter((component) => component.category === category) : components;
11838
- return result({
11839
- total: list.length,
11840
- ...category ? { category } : {},
11841
- library: library.name,
11842
- version: data.version,
11843
- components: list.map(summary)
11844
- });
11845
- }
11846
- case "get_categories": {
11847
- const counts = data.categories.map((category) => ({
11848
- category,
11849
- count: components.filter((component) => component.category === category).length
11850
- }));
11851
- return result({
11852
- total: components.length,
11853
- categories: counts
11854
- });
11855
- }
11856
- case "get_component": {
11857
- const component = findComponent(args?.name);
11858
- if (!component) return notFound(args?.name ?? "");
11859
- return result({
11860
- ...summary(component),
11861
- import: importStatements(component),
11862
- props: component.props,
11863
- events: component.events,
11864
- slots: component.slots
11865
- });
11866
- }
11867
- case "search_components": {
11868
- const query = args?.query ?? "";
11869
- const matches = search(query);
11870
- return result({
11871
- query,
11872
- total: matches.length,
11873
- matches
11874
- });
11875
- }
11876
- case "get_component_props": {
11877
- const component = findComponent(args?.name);
11878
- if (!component) return notFound(args?.name ?? "");
11879
- return result({
11880
- name: component.name,
11881
- title: component.title,
11882
- props: component.props
11883
- });
11884
- }
11885
- case "get_component_events": {
11886
- const component = findComponent(args?.name);
11887
- if (!component) return notFound(args?.name ?? "");
11888
- return result({
11889
- name: component.name,
11890
- title: component.title,
11891
- events: component.events
11892
- });
11893
- }
11894
- case "get_component_slots": {
11895
- const component = findComponent(args?.name);
11896
- if (!component) return notFound(args?.name ?? "");
11897
- return result({
11898
- name: component.name,
11899
- title: component.title,
11900
- slots: component.slots
11901
- });
11902
- }
11903
- case "find_by_prop": {
11904
- const prop = args?.prop ?? "";
11905
- const results = findByProp(prop);
11906
- return result({
11907
- prop,
11908
- total: results.length,
11909
- results
11910
- });
11911
- }
11912
- default: return result({ error: `Unknown tool: ${name}` });
11913
- }
11914
- });
11915
- await server.connect(new StdioServerTransport());
11791
+ const createServer = () => {
11792
+ const server = new McpServer({
11793
+ name: PKG_NAME,
11794
+ version: "1.15.0"
11795
+ });
11796
+ server.registerTool("list_components", {
11797
+ description: "List all SD Design components with their category, bilingual title and API size. Optionally filter by category. Use this first to discover what is available.",
11798
+ inputSchema: z.object({ category: z.string().optional().describe("Optional category filter, e.g. 通用 / 布局 / 导航 / 数据展示 / 反馈 / 其他.") })
11799
+ }, ({ category }) => {
11800
+ const normalizedCategory = category?.trim();
11801
+ const list = normalizedCategory ? components.filter((component) => component.category === normalizedCategory) : components;
11802
+ return result({
11803
+ total: list.length,
11804
+ ...normalizedCategory ? { category: normalizedCategory } : {},
11805
+ library: library.name,
11806
+ version: data.version,
11807
+ components: list.map(summary)
11808
+ });
11809
+ });
11810
+ server.registerTool("get_categories", {
11811
+ description: "List all SD Design component categories with the number of components in each.",
11812
+ inputSchema: z.object({})
11813
+ }, () => {
11814
+ const counts = data.categories.map((category) => ({
11815
+ category,
11816
+ count: components.filter((component) => component.category === category).length
11817
+ }));
11818
+ return result({
11819
+ total: components.length,
11820
+ categories: counts
11821
+ });
11822
+ });
11823
+ server.registerTool("get_component", {
11824
+ description: "Get full detail for a component: description, import statements, documentation URL, and every documented prop, event and slot (bilingual zh/en). Accepts the tag (sd-button), kebab (button) or PascalCase (Button) name.",
11825
+ inputSchema: z.object({ name: z.string().describe("Component name, e.g. \"sd-button\", \"button\" or \"Button\".") })
11826
+ }, ({ name }) => {
11827
+ const component = findComponent(name);
11828
+ if (!component) return notFound(name);
11829
+ return result({
11830
+ ...summary(component),
11831
+ import: importStatements(component),
11832
+ props: component.props,
11833
+ events: component.events,
11834
+ slots: component.slots
11835
+ });
11836
+ });
11837
+ server.registerTool("search_components", {
11838
+ description: "Search components by keyword across name, title, description and prop/event/slot text (both Chinese and English). Returns matching components with the fields that matched.",
11839
+ inputSchema: z.object({ query: z.string().describe("Search keyword, e.g. \"日期\", \"tree\", \"上传\".") })
11840
+ }, ({ query }) => {
11841
+ const matches = search(query);
11842
+ return result({
11843
+ query,
11844
+ total: matches.length,
11845
+ matches
11846
+ });
11847
+ });
11848
+ server.registerTool("get_component_props", {
11849
+ description: "Get only the documented props for a component (name, type, default, bilingual description).",
11850
+ inputSchema: z.object({ name: z.string().describe("Component name.") })
11851
+ }, ({ name }) => {
11852
+ const component = findComponent(name);
11853
+ if (!component) return notFound(name);
11854
+ return result({
11855
+ name: component.name,
11856
+ title: component.title,
11857
+ props: component.props
11858
+ });
11859
+ });
11860
+ server.registerTool("get_component_events", {
11861
+ description: "Get only the documented events for a component (name and bilingual description).",
11862
+ inputSchema: z.object({ name: z.string().describe("Component name.") })
11863
+ }, ({ name }) => {
11864
+ const component = findComponent(name);
11865
+ if (!component) return notFound(name);
11866
+ return result({
11867
+ name: component.name,
11868
+ title: component.title,
11869
+ events: component.events
11870
+ });
11871
+ });
11872
+ server.registerTool("get_component_slots", {
11873
+ description: "Get only the documented slots for a component (name and bilingual description).",
11874
+ inputSchema: z.object({ name: z.string().describe("Component name.") })
11875
+ }, ({ name }) => {
11876
+ const component = findComponent(name);
11877
+ if (!component) return notFound(name);
11878
+ return result({
11879
+ name: component.name,
11880
+ title: component.title,
11881
+ slots: component.slots
11882
+ });
11883
+ });
11884
+ server.registerTool("find_by_prop", {
11885
+ description: "Find components that expose a given prop. Useful for \"which components have a size prop?\" or \"what can I set disabled on?\".",
11886
+ inputSchema: z.object({ prop: z.string().describe("Prop name to search for, e.g. \"size\", \"disabled\".") })
11887
+ }, ({ prop }) => {
11888
+ const results = findByProp(prop);
11889
+ return result({
11890
+ prop,
11891
+ total: results.length,
11892
+ results
11893
+ });
11894
+ });
11895
+ return server;
11896
+ };
11897
+ serveStdio(createServer);
11916
11898
  //#endregion
11917
11899
  export {};
package/package.json CHANGED
@@ -44,10 +44,12 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "@modelcontextprotocol/sdk": "^1.29.0"
47
+ "@modelcontextprotocol/server": "2.0.0",
48
+ "zod": "4.4.3"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@babel/types": "^7.29.7",
52
+ "@modelcontextprotocol/client": "2.0.0",
51
53
  "@semantic-release/commit-analyzer": "^13.0.1",
52
54
  "@semantic-release/exec": "^7.1.0",
53
55
  "@semantic-release/github": "^12.0.9",
@@ -62,10 +64,11 @@
62
64
  "engines": {
63
65
  "node": ">=20"
64
66
  },
65
- "version": "1.13.0",
67
+ "version": "1.15.0",
66
68
  "scripts": {
67
69
  "gen": "node ./scripts/gen-component-data.mjs",
68
- "build": "pnpm run gen && tsdown",
70
+ "build": "node ./scripts/build.mjs",
71
+ "test": "node ./scripts/build.mjs 9.8.7-test && node --test ./test/*.test.mjs",
69
72
  "typecheck": "pnpm run gen && tsc --noEmit",
70
73
  "dev:link": "pnpm link --global && npm link"
71
74
  }