@douyinfe/semi-mcp 1.0.15 → 1.0.17

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/dist/http.js CHANGED
@@ -383,13 +383,13 @@ function replaceCodeBlocksWithPlaceholders(content, componentName) {
383
383
  }
384
384
  const getSemiDocumentTool = {
385
385
  name: 'get_semi_document',
386
- description: '获取 Semi Design 组件文档或组件列表。对于大型文档,代码块会被替换为占位符,需要使用 get_semi_code_block 工具获取具体代码',
386
+ description: '获取 Semi Design 组件文档、额外文档或组件列表。支持获取:1) 组件文档(如 Button、Input 等组件);2) 额外文档,包括:advanced 分类下的文档(customize-theme、dark-mode、design-source、design-to-code)、ecosystem 分类下的文档(changelog、faq、react19、tailwind、update-to-v2、web-components)、experience 分类下的文档(accessibility、content-guidelines、internationalization)、start 分类下的文档(getting-started、introduction、overview)。注意:changelog 文档较大,需要使用分页格式获取,传入 changelog-1(第1页,最新内容)、changelog-2(第2页)等格式,每页300行。对于大型文档,代码块会被替换为占位符,需要使用 get_semi_code_block 工具获取具体代码',
387
387
  inputSchema: {
388
388
  type: 'object',
389
389
  properties: {
390
390
  componentName: {
391
391
  type: 'string',
392
- description: '组件名称,例如 Button、Input 等。如果不提供,则返回组件列表'
392
+ description: '组件名称或文档名称。组件名称例如:Button、Input、Table 等;额外文档名称例如:customize-theme、dark-mode、design-source、design-to-code、changelog-1(changelog第1页,最新)、changelog-2(changelog第2页)等、faq、react19、tailwind、update-to-v2、web-components、accessibility、content-guidelines、internationalization、getting-started、introduction、overview 等。注意:changelog 必须使用分页格式(changelog-1、changelog-2等),不能直接传入 changelog。如果不提供,则返回组件列表'
393
393
  },
394
394
  version: {
395
395
  type: 'string',
@@ -400,12 +400,72 @@ const getSemiDocumentTool = {
400
400
  }
401
401
  };
402
402
  const LARGE_DOCUMENT_THRESHOLD = 888;
403
+ const CHANGELOG_PAGE_SIZE = 300;
404
+ function generateDocumentUrl(docPath) {
405
+ const pathParts = docPath.split('/');
406
+ let contentIndex = -1;
407
+ for(let i = 0; i < pathParts.length; i++)if ('content' === pathParts[i].toLowerCase()) {
408
+ contentIndex = i;
409
+ break;
410
+ }
411
+ if (-1 === contentIndex || contentIndex + 3 >= pathParts.length) return '';
412
+ const category = pathParts[contentIndex + 1];
413
+ const componentName = pathParts[contentIndex + 2];
414
+ if (!category || !componentName) return '';
415
+ return `https://semi.design/zh-CN/${category}/${componentName}`;
416
+ }
417
+ function parseChangelogPage(componentName) {
418
+ const changelogMatch = componentName.match(/^(changelog)(?:-(\d+))?$/);
419
+ if (changelogMatch) {
420
+ const baseName = changelogMatch[1];
421
+ const pageStr = changelogMatch[2];
422
+ if (!pageStr) return {
423
+ isChangelog: true,
424
+ baseName
425
+ };
426
+ {
427
+ const page = parseInt(pageStr, 10);
428
+ return {
429
+ isChangelog: true,
430
+ page,
431
+ baseName
432
+ };
433
+ }
434
+ }
435
+ return {
436
+ isChangelog: false
437
+ };
438
+ }
439
+ function paginateChangelog(content, page) {
440
+ const lines = content.split('\n');
441
+ const totalLines = lines.length;
442
+ const totalPages = Math.ceil(totalLines / CHANGELOG_PAGE_SIZE);
443
+ const startIndex = (page - 1) * CHANGELOG_PAGE_SIZE;
444
+ const endIndex = Math.min(startIndex + CHANGELOG_PAGE_SIZE, totalLines);
445
+ const pageLines = lines.slice(startIndex, endIndex);
446
+ const pageContent = pageLines.join('\n');
447
+ return {
448
+ content: pageContent,
449
+ totalPages,
450
+ currentPage: page
451
+ };
452
+ }
403
453
  async function handleGetSemiDocument(args) {
404
454
  const componentName = args?.componentName;
405
455
  const version = args?.version || 'latest';
406
456
  try {
407
457
  if (componentName) {
408
- const result = await getComponentDocuments(componentName, version);
458
+ const changelogInfo = parseChangelogPage(componentName);
459
+ if (changelogInfo.isChangelog && !changelogInfo.page) return {
460
+ content: [
461
+ {
462
+ type: 'text',
463
+ text: `changelog 文档较大,需要使用分页方式获取。\n\n请使用以下格式获取:\n- changelog-1(第1页,最新内容)\n- changelog-2(第2页)\n- changelog-3(第3页)\n- ...\n\n页码从1开始,1为最新内容。`
464
+ }
465
+ ]
466
+ };
467
+ const actualComponentName = changelogInfo.baseName || componentName;
468
+ const result = await getComponentDocuments(actualComponentName, version);
409
469
  const allComponents = await getComponentList(version);
410
470
  if (!result) return {
411
471
  content: [
@@ -415,6 +475,47 @@ async function handleGetSemiDocument(args) {
415
475
  }
416
476
  ]
417
477
  };
478
+ if (changelogInfo.isChangelog && changelogInfo.page) {
479
+ const page = changelogInfo.page;
480
+ if (0 === result.documents.length) return {
481
+ content: [
482
+ {
483
+ type: 'text',
484
+ text: `未找到 changelog 文档 (版本 ${version})`
485
+ }
486
+ ],
487
+ isError: true
488
+ };
489
+ const doc = result.documents[0];
490
+ const paginated = paginateChangelog(doc.content, page);
491
+ if (page < 1 || page > paginated.totalPages) return {
492
+ content: [
493
+ {
494
+ type: 'text',
495
+ text: `页码 ${page} 超出范围。changelog 文档共有 ${paginated.totalPages} 页,请使用 changelog-1 到 changelog-${paginated.totalPages}。`
496
+ }
497
+ ],
498
+ isError: true
499
+ };
500
+ const nextPageHint = page < paginated.totalPages ? `使用 changelog-${page + 1} 获取下一页` : '';
501
+ const prevPageHint = page > 1 ? `使用 changelog-${page - 1} 获取上一页` : '';
502
+ const pageHints = [
503
+ nextPageHint,
504
+ prevPageHint
505
+ ].filter(Boolean).join(',');
506
+ const header = `===== ${doc.name} (第 ${page}/${paginated.totalPages} 页) =====${pageHints ? `\n[提示: ${pageHints}]` : ''}`;
507
+ const footer = `\n\n[当前页: ${page}/${paginated.totalPages} | 总行数: ${doc.content.split('\n').length} | 每页: ${CHANGELOG_PAGE_SIZE} 行]`;
508
+ const url = generateDocumentUrl(doc.path);
509
+ const urlFooter = url ? `\n\n文档链接: ${url}` : '';
510
+ return {
511
+ content: [
512
+ {
513
+ type: 'text',
514
+ text: `${header}\n\n${paginated.content}${footer}${urlFooter}`
515
+ }
516
+ ]
517
+ };
518
+ }
418
519
  const documentsWithLines = result.documents.map((doc)=>({
419
520
  ...doc,
420
521
  lines: doc.content.split('\n').length
@@ -442,7 +543,9 @@ async function handleGetSemiDocument(args) {
442
543
  const docContents = processedDocs.map((doc)=>{
443
544
  let header = `===== ${doc.name} =====`;
444
545
  if (doc.codeBlockCount > 0) header += `\n[注意: 此文档原有 ${doc.originalLines} 行,包含 ${doc.codeBlockCount} 个代码块已被隐藏。使用 get_semi_code_block 工具查看具体代码]`;
445
- return `${header}\n\n${doc.content}`;
546
+ const url = generateDocumentUrl(doc.path);
547
+ const urlFooter = url ? `\n\n文档链接: ${url}` : '';
548
+ return `${header}\n\n${doc.content}${urlFooter}`;
446
549
  }).join('\n\n');
447
550
  return {
448
551
  content: [
@@ -453,7 +556,11 @@ async function handleGetSemiDocument(args) {
453
556
  ]
454
557
  };
455
558
  }
456
- const docContents = result.documents.map((doc)=>`===== ${doc.name} =====\n\n${doc.content}`).join('\n\n');
559
+ const docContents = result.documents.map((doc)=>{
560
+ const url = generateDocumentUrl(doc.path);
561
+ const urlFooter = url ? `\n\n文档链接: ${url}` : '';
562
+ return `===== ${doc.name} =====\n\n${doc.content}${urlFooter}`;
563
+ }).join('\n\n');
457
564
  return {
458
565
  content: [
459
566
  {
package/dist/index.js CHANGED
@@ -382,13 +382,13 @@ function replaceCodeBlocksWithPlaceholders(content, componentName) {
382
382
  }
383
383
  const getSemiDocumentTool = {
384
384
  name: 'get_semi_document',
385
- description: '获取 Semi Design 组件文档或组件列表。对于大型文档,代码块会被替换为占位符,需要使用 get_semi_code_block 工具获取具体代码',
385
+ description: '获取 Semi Design 组件文档、额外文档或组件列表。支持获取:1) 组件文档(如 Button、Input 等组件);2) 额外文档,包括:advanced 分类下的文档(customize-theme、dark-mode、design-source、design-to-code)、ecosystem 分类下的文档(changelog、faq、react19、tailwind、update-to-v2、web-components)、experience 分类下的文档(accessibility、content-guidelines、internationalization)、start 分类下的文档(getting-started、introduction、overview)。注意:changelog 文档较大,需要使用分页格式获取,传入 changelog-1(第1页,最新内容)、changelog-2(第2页)等格式,每页300行。对于大型文档,代码块会被替换为占位符,需要使用 get_semi_code_block 工具获取具体代码',
386
386
  inputSchema: {
387
387
  type: 'object',
388
388
  properties: {
389
389
  componentName: {
390
390
  type: 'string',
391
- description: '组件名称,例如 Button、Input 等。如果不提供,则返回组件列表'
391
+ description: '组件名称或文档名称。组件名称例如:Button、Input、Table 等;额外文档名称例如:customize-theme、dark-mode、design-source、design-to-code、changelog-1(changelog第1页,最新)、changelog-2(changelog第2页)等、faq、react19、tailwind、update-to-v2、web-components、accessibility、content-guidelines、internationalization、getting-started、introduction、overview 等。注意:changelog 必须使用分页格式(changelog-1、changelog-2等),不能直接传入 changelog。如果不提供,则返回组件列表'
392
392
  },
393
393
  version: {
394
394
  type: 'string',
@@ -399,12 +399,72 @@ const getSemiDocumentTool = {
399
399
  }
400
400
  };
401
401
  const LARGE_DOCUMENT_THRESHOLD = 888;
402
+ const CHANGELOG_PAGE_SIZE = 300;
403
+ function generateDocumentUrl(docPath) {
404
+ const pathParts = docPath.split('/');
405
+ let contentIndex = -1;
406
+ for(let i = 0; i < pathParts.length; i++)if ('content' === pathParts[i].toLowerCase()) {
407
+ contentIndex = i;
408
+ break;
409
+ }
410
+ if (-1 === contentIndex || contentIndex + 3 >= pathParts.length) return '';
411
+ const category = pathParts[contentIndex + 1];
412
+ const componentName = pathParts[contentIndex + 2];
413
+ if (!category || !componentName) return '';
414
+ return `https://semi.design/zh-CN/${category}/${componentName}`;
415
+ }
416
+ function parseChangelogPage(componentName) {
417
+ const changelogMatch = componentName.match(/^(changelog)(?:-(\d+))?$/);
418
+ if (changelogMatch) {
419
+ const baseName = changelogMatch[1];
420
+ const pageStr = changelogMatch[2];
421
+ if (!pageStr) return {
422
+ isChangelog: true,
423
+ baseName
424
+ };
425
+ {
426
+ const page = parseInt(pageStr, 10);
427
+ return {
428
+ isChangelog: true,
429
+ page,
430
+ baseName
431
+ };
432
+ }
433
+ }
434
+ return {
435
+ isChangelog: false
436
+ };
437
+ }
438
+ function paginateChangelog(content, page) {
439
+ const lines = content.split('\n');
440
+ const totalLines = lines.length;
441
+ const totalPages = Math.ceil(totalLines / CHANGELOG_PAGE_SIZE);
442
+ const startIndex = (page - 1) * CHANGELOG_PAGE_SIZE;
443
+ const endIndex = Math.min(startIndex + CHANGELOG_PAGE_SIZE, totalLines);
444
+ const pageLines = lines.slice(startIndex, endIndex);
445
+ const pageContent = pageLines.join('\n');
446
+ return {
447
+ content: pageContent,
448
+ totalPages,
449
+ currentPage: page
450
+ };
451
+ }
402
452
  async function handleGetSemiDocument(args) {
403
453
  const componentName = args?.componentName;
404
454
  const version = args?.version || 'latest';
405
455
  try {
406
456
  if (componentName) {
407
- const result = await getComponentDocuments(componentName, version);
457
+ const changelogInfo = parseChangelogPage(componentName);
458
+ if (changelogInfo.isChangelog && !changelogInfo.page) return {
459
+ content: [
460
+ {
461
+ type: 'text',
462
+ text: `changelog 文档较大,需要使用分页方式获取。\n\n请使用以下格式获取:\n- changelog-1(第1页,最新内容)\n- changelog-2(第2页)\n- changelog-3(第3页)\n- ...\n\n页码从1开始,1为最新内容。`
463
+ }
464
+ ]
465
+ };
466
+ const actualComponentName = changelogInfo.baseName || componentName;
467
+ const result = await getComponentDocuments(actualComponentName, version);
408
468
  const allComponents = await getComponentList(version);
409
469
  if (!result) return {
410
470
  content: [
@@ -414,6 +474,47 @@ async function handleGetSemiDocument(args) {
414
474
  }
415
475
  ]
416
476
  };
477
+ if (changelogInfo.isChangelog && changelogInfo.page) {
478
+ const page = changelogInfo.page;
479
+ if (0 === result.documents.length) return {
480
+ content: [
481
+ {
482
+ type: 'text',
483
+ text: `未找到 changelog 文档 (版本 ${version})`
484
+ }
485
+ ],
486
+ isError: true
487
+ };
488
+ const doc = result.documents[0];
489
+ const paginated = paginateChangelog(doc.content, page);
490
+ if (page < 1 || page > paginated.totalPages) return {
491
+ content: [
492
+ {
493
+ type: 'text',
494
+ text: `页码 ${page} 超出范围。changelog 文档共有 ${paginated.totalPages} 页,请使用 changelog-1 到 changelog-${paginated.totalPages}。`
495
+ }
496
+ ],
497
+ isError: true
498
+ };
499
+ const nextPageHint = page < paginated.totalPages ? `使用 changelog-${page + 1} 获取下一页` : '';
500
+ const prevPageHint = page > 1 ? `使用 changelog-${page - 1} 获取上一页` : '';
501
+ const pageHints = [
502
+ nextPageHint,
503
+ prevPageHint
504
+ ].filter(Boolean).join(',');
505
+ const header = `===== ${doc.name} (第 ${page}/${paginated.totalPages} 页) =====${pageHints ? `\n[提示: ${pageHints}]` : ''}`;
506
+ const footer = `\n\n[当前页: ${page}/${paginated.totalPages} | 总行数: ${doc.content.split('\n').length} | 每页: ${CHANGELOG_PAGE_SIZE} 行]`;
507
+ const url = generateDocumentUrl(doc.path);
508
+ const urlFooter = url ? `\n\n文档链接: ${url}` : '';
509
+ return {
510
+ content: [
511
+ {
512
+ type: 'text',
513
+ text: `${header}\n\n${paginated.content}${footer}${urlFooter}`
514
+ }
515
+ ]
516
+ };
517
+ }
417
518
  const documentsWithLines = result.documents.map((doc)=>({
418
519
  ...doc,
419
520
  lines: doc.content.split('\n').length
@@ -441,7 +542,9 @@ async function handleGetSemiDocument(args) {
441
542
  const docContents = processedDocs.map((doc)=>{
442
543
  let header = `===== ${doc.name} =====`;
443
544
  if (doc.codeBlockCount > 0) header += `\n[注意: 此文档原有 ${doc.originalLines} 行,包含 ${doc.codeBlockCount} 个代码块已被隐藏。使用 get_semi_code_block 工具查看具体代码]`;
444
- return `${header}\n\n${doc.content}`;
545
+ const url = generateDocumentUrl(doc.path);
546
+ const urlFooter = url ? `\n\n文档链接: ${url}` : '';
547
+ return `${header}\n\n${doc.content}${urlFooter}`;
445
548
  }).join('\n\n');
446
549
  return {
447
550
  content: [
@@ -452,7 +555,11 @@ async function handleGetSemiDocument(args) {
452
555
  ]
453
556
  };
454
557
  }
455
- const docContents = result.documents.map((doc)=>`===== ${doc.name} =====\n\n${doc.content}`).join('\n\n');
558
+ const docContents = result.documents.map((doc)=>{
559
+ const url = generateDocumentUrl(doc.path);
560
+ const urlFooter = url ? `\n\n文档链接: ${url}` : '';
561
+ return `===== ${doc.name} =====\n\n${doc.content}${urlFooter}`;
562
+ }).join('\n\n');
456
563
  return {
457
564
  content: [
458
565
  {
@@ -17,6 +17,12 @@ export declare function replaceCodeBlocksWithPlaceholders(content: string, compo
17
17
  * 工具定义:获取 Semi Design 组件文档
18
18
  */
19
19
  export declare const getSemiDocumentTool: Tool;
20
+ /**
21
+ * 从文档路径生成 URL
22
+ * @param docPath - 文档路径,格式:/content/{category}/{componentName}/index.md
23
+ * @returns URL,格式:https://semi.design/zh-CN/{category}/{componentName}
24
+ */
25
+ export declare function generateDocumentUrl(docPath: string): string;
20
26
  /**
21
27
  * 工具处理器:处理 get_semi_document 工具调用
22
28
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@douyinfe/semi-mcp",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Semi Design MCP Server - Model Context Protocol server for Semi Design components and documentation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",