@iress-oss/ids-mcp-server 0.0.1-dev.4 → 0.0.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.
Files changed (125) hide show
  1. package/LICENSE +193 -0
  2. package/README.md +159 -29
  3. package/build/componentHandlers.js +205 -0
  4. package/{dist → build}/config.js +5 -5
  5. package/build/index.js +51 -0
  6. package/{dist → build}/iressHandlers.js +46 -52
  7. package/{dist → build}/resourceHandlers.js +22 -23
  8. package/{dist → build}/searchHandlers.js +92 -107
  9. package/{dist → build}/toolHandler.js +13 -13
  10. package/build/tools.js +165 -0
  11. package/{dist → build}/utils.js +15 -11
  12. package/docs/api-reference.md +0 -0
  13. package/docs/best-practices.md +0 -0
  14. package/docs/configuration.md +0 -0
  15. package/docs/examples.md +0 -0
  16. package/docs/guidelines.md +269 -0
  17. package/{generated/docs → docs/ids}/components-autocomplete-docs.md +5 -5
  18. package/{generated/docs → docs/ids}/components-autocomplete-recipes-docs.md +51 -17
  19. package/{generated/docs → docs/ids}/components-card-recipes-docs.md +1 -1
  20. package/{generated/docs → docs/ids}/components-checkbox-docs.md +19 -6
  21. package/{generated/docs → docs/ids}/components-checkboxgroup-docs.md +18 -18
  22. package/{generated/docs → docs/ids}/components-checkboxgroup-recipes-docs.md +9 -9
  23. package/{generated/docs → docs/ids}/components-col-docs.md +1 -1
  24. package/{generated/docs → docs/ids}/components-combobox-docs.md +6 -6
  25. package/{generated/docs → docs/ids}/components-container-docs.md +42 -8
  26. package/{generated/docs → docs/ids}/components-filter-docs.md +66 -13
  27. package/{generated/docs → docs/ids}/components-form-docs.md +368 -342
  28. package/{generated/docs → docs/ids}/components-form-recipes-docs.md +11 -202
  29. package/{generated/docs → docs/ids}/components-hide-docs.md +70 -16
  30. package/{generated/docs → docs/ids}/components-icon-docs.md +4 -4
  31. package/{generated/docs → docs/ids}/components-input-recipes-docs.md +2 -2
  32. package/{generated/docs → docs/ids}/components-inputcurrency-recipes-docs.md +40 -6
  33. package/{generated/docs → docs/ids}/components-modal-docs.md +113 -3
  34. package/docs/ids/components-popover-docs.md +4 -0
  35. package/{generated/docs → docs/ids}/components-radiogroup-docs.md +21 -21
  36. package/{generated/docs → docs/ids}/components-richselect-docs.md +111 -149
  37. package/{generated/docs → docs/ids}/components-row-docs.md +4 -4
  38. package/{generated/docs → docs/ids}/components-skeleton-docs.md +3 -3
  39. package/{generated/docs → docs/ids}/components-skeleton-recipes-docs.md +1 -1
  40. package/{generated/docs → docs/ids}/components-skiplink-docs.md +1 -1
  41. package/{generated/docs → docs/ids}/components-slideout-docs.md +113 -3
  42. package/docs/ids/components-table-ag-grid-docs.md +2694 -0
  43. package/{generated/docs → docs/ids}/components-table-docs.md +597 -92
  44. package/{generated/docs → docs/ids}/components-tabset-docs.md +2 -2
  45. package/{generated/docs → docs/ids}/components-tag-docs.md +1 -1
  46. package/{generated/docs → docs/ids}/components-toaster-docs.md +5 -56
  47. package/{generated/docs → docs/ids}/extensions-editor-docs.md +5 -5
  48. package/{generated/docs → docs/ids}/foundations-colours-docs.md +1 -1
  49. package/{generated/docs → docs/ids}/foundations-typography-docs.md +2 -7
  50. package/docs/ids/get-started-develop-docs.md +48 -0
  51. package/{generated/docs → docs/ids}/introduction-docs.md +4 -4
  52. package/{generated/docs → docs/ids}/patterns-loading-docs.md +2 -332
  53. package/docs/ids/resources-migration-guides-from-v4-to-v5-docs.md +639 -0
  54. package/docs/ids/themes-available-themes-docs.md +74 -0
  55. package/docs/ids/themes-tokens-docs.md +4580 -0
  56. package/docs/ids/versions-docs.md +27 -0
  57. package/docs/tutorials/basic-integration.md +0 -0
  58. package/package.json +15 -44
  59. package/LICENSE.txt +0 -201
  60. package/dist/componentHandlers.js +0 -241
  61. package/dist/componentHandlers.test.js +0 -380
  62. package/dist/index.js +0 -53
  63. package/dist/iressHandlers.test.js +0 -316
  64. package/dist/resourceHandlers.test.js +0 -352
  65. package/dist/searchHandlers.test.js +0 -524
  66. package/dist/toolHandler.test.js +0 -369
  67. package/dist/tools.js +0 -165
  68. package/dist/utils.test.js +0 -286
  69. package/generated/docs/components-popover-docs.md +0 -464
  70. package/generated/docs/components-provider-docs.md +0 -105
  71. package/generated/docs/components-table-ag-grid-docs.md +0 -1074
  72. package/generated/docs/foundations-accessibility-docs.md +0 -62
  73. package/generated/docs/foundations-consistency-docs.md +0 -52
  74. package/generated/docs/foundations-content-docs.md +0 -23
  75. package/generated/docs/foundations-introduction-docs.md +0 -17
  76. package/generated/docs/foundations-principles-docs.md +0 -70
  77. package/generated/docs/foundations-user-experience-docs.md +0 -63
  78. package/generated/docs/foundations-visual-design-docs.md +0 -46
  79. package/generated/docs/get-started-develop-docs.md +0 -209
  80. package/generated/docs/guidelines.md +0 -812
  81. package/generated/docs/resources-migration-guides-from-v4-to-v5-docs.md +0 -437
  82. package/generated/docs/themes-available-themes-docs.md +0 -66
  83. package/generated/docs/themes-tokens-docs.md +0 -1200
  84. package/generated/docs/versions-docs.md +0 -17
  85. /package/{dist → build}/types.js +0 -0
  86. /package/{generated/docs → docs/ids}/components-alert-docs.md +0 -0
  87. /package/{generated/docs → docs/ids}/components-badge-docs.md +0 -0
  88. /package/{generated/docs → docs/ids}/components-button-docs.md +0 -0
  89. /package/{generated/docs → docs/ids}/components-button-recipes-docs.md +0 -0
  90. /package/{generated/docs → docs/ids}/components-buttongroup-docs.md +0 -0
  91. /package/{generated/docs → docs/ids}/components-card-docs.md +0 -0
  92. /package/{generated/docs → docs/ids}/components-divider-docs.md +0 -0
  93. /package/{generated/docs → docs/ids}/components-expander-docs.md +0 -0
  94. /package/{generated/docs → docs/ids}/components-field-docs.md +0 -0
  95. /package/{generated/docs → docs/ids}/components-inline-docs.md +0 -0
  96. /package/{generated/docs → docs/ids}/components-input-docs.md +0 -0
  97. /package/{generated/docs → docs/ids}/components-inputcurrency-docs.md +0 -0
  98. /package/{generated/docs → docs/ids}/components-label-docs.md +0 -0
  99. /package/{generated/docs → docs/ids}/components-menu-docs.md +0 -0
  100. /package/{generated/docs → docs/ids}/components-menu-menuitem-docs.md +0 -0
  101. /package/{generated/docs → docs/ids}/components-navbar-docs.md +0 -0
  102. /package/{generated/docs → docs/ids}/components-navbar-recipes-docs.md +0 -0
  103. /package/{generated/docs → docs/ids}/components-panel-docs.md +0 -0
  104. /package/{generated/docs → docs/ids}/components-placeholder-docs.md +0 -0
  105. /package/{generated/docs → docs/ids}/components-popover-recipes-docs.md +0 -0
  106. /package/{generated/docs → docs/ids}/components-progress-docs.md +0 -0
  107. /package/{generated/docs → docs/ids}/components-radio-docs.md +0 -0
  108. /package/{generated/docs → docs/ids}/components-readonly-docs.md +0 -0
  109. /package/{generated/docs → docs/ids}/components-select-docs.md +0 -0
  110. /package/{generated/docs → docs/ids}/components-slider-docs.md +0 -0
  111. /package/{generated/docs → docs/ids}/components-spinner-docs.md +0 -0
  112. /package/{generated/docs → docs/ids}/components-stack-docs.md +0 -0
  113. /package/{generated/docs → docs/ids}/components-tabset-tab-docs.md +0 -0
  114. /package/{generated/docs → docs/ids}/components-text-docs.md +0 -0
  115. /package/{generated/docs → docs/ids}/components-toaster-toast-docs.md +0 -0
  116. /package/{generated/docs → docs/ids}/components-toggle-docs.md +0 -0
  117. /package/{generated/docs → docs/ids}/components-tooltip-docs.md +0 -0
  118. /package/{generated/docs → docs/ids}/components-validationmessage-docs.md +0 -0
  119. /package/{generated/docs → docs/ids}/contact-us-docs.md +0 -0
  120. /package/{generated/docs → docs/ids}/extensions-editor-recipes-docs.md +0 -0
  121. /package/{generated/docs → docs/ids}/frequently-asked-questions-docs.md +0 -0
  122. /package/{generated/docs → docs/ids}/get-started-using-storybook-docs.md +0 -0
  123. /package/{generated/docs → docs/ids}/resources-changelog-docs.md +0 -0
  124. /package/{generated/docs → docs/ids}/resources-code-katas-docs.md +0 -0
  125. /package/{generated/docs → docs/ids}/themes-introduction-docs.md +0 -0
package/build/index.js ADDED
@@ -0,0 +1,51 @@
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, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { SERVER_CONFIG, CAPABILITIES } from "./config.js";
6
+ import { toolDefinitions } from "./tools.js";
7
+ import { handleToolCall } from "./toolHandler.js";
8
+ import { handleListResources, handleReadResource } from "./resourceHandlers.js";
9
+ /**
10
+ * Create MCP server for Iress Design System (IDS) component library context
11
+ */
12
+ const server = new Server(SERVER_CONFIG, { capabilities: CAPABILITIES });
13
+ /**
14
+ * List available IDS component documentation resources
15
+ */
16
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
17
+ return handleListResources();
18
+ });
19
+ /**
20
+ * Read content from a specific markdown file
21
+ */
22
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
23
+ return handleReadResource(request);
24
+ });
25
+ /**
26
+ * List available IDS development tools
27
+ */
28
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
29
+ return {
30
+ tools: toolDefinitions,
31
+ };
32
+ });
33
+ /**
34
+ * Handle IDS component library tool calls
35
+ */
36
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
37
+ const result = handleToolCall(request);
38
+ return result;
39
+ });
40
+ /**
41
+ * Start the server
42
+ */
43
+ async function main() {
44
+ const transport = new StdioServerTransport();
45
+ await server.connect(transport);
46
+ console.error("IDS Component Library MCP Server running on stdio");
47
+ }
48
+ main().catch((error) => {
49
+ console.error("Server error:", error);
50
+ process.exit(1);
51
+ });
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Tool handlers for Iress component-specific operations
3
3
  */
4
- import { z } from 'zod';
5
- import * as path from 'path';
6
- import { mapIressComponentToFile, extractIressComponents, readFileContent, } from './utils.js';
7
- import { DOCS_DIR } from './config.js';
4
+ import { z } from "zod";
5
+ import * as path from "path";
6
+ import { mapIressComponentToFile, extractIressComponents, readFileContent, } from "./utils.js";
7
+ import { DOCS_DIR } from "./config.js";
8
8
  export function handleGetIressComponentInfo(args) {
9
9
  const schema = z.object({
10
10
  component_name: z.string(),
@@ -18,7 +18,7 @@ export function handleGetIressComponentInfo(args) {
18
18
  return {
19
19
  content: [
20
20
  {
21
- type: 'text',
21
+ type: "text",
22
22
  text: `Component "${component_name}" not found. Make sure you're using the correct Iress component name (e.g., IressButton, IressInput, IressTable).`,
23
23
  },
24
24
  ],
@@ -29,78 +29,47 @@ export function handleGetIressComponentInfo(args) {
29
29
  const content = readFileContent(filePath);
30
30
  let response = `**${component_name} Component Documentation**\n\n`;
31
31
  // Extract overview/description
32
- const lines = content.split('\n');
33
- const overviewStart = lines.findIndex((line) => line.toLowerCase().includes('overview'));
32
+ const lines = content.split("\n");
33
+ const overviewStart = lines.findIndex((line) => line.toLowerCase().includes("overview"));
34
34
  if (overviewStart !== -1) {
35
- const overviewEnd = lines.findIndex((line, index) => index > overviewStart && line.startsWith('#'));
35
+ const overviewEnd = lines.findIndex((line, index) => index > overviewStart && line.startsWith("#"));
36
36
  const overviewLines = lines.slice(overviewStart, overviewEnd !== -1 ? overviewEnd : overviewStart + 10);
37
- response += `${overviewLines.join('\n')}\n\n`;
37
+ response += `${overviewLines.join("\n")}\n\n`;
38
38
  }
39
39
  // Include props if requested
40
40
  if (include_props) {
41
- const propSections = content.match(/(mode|prop|Properties|API)[\s\S]*?(?=\n##|\n\[#|$)/gi) ??
41
+ const propSections = content.match(/(mode|prop|Properties|API)[\s\S]*?(?=\n##|\n\[#|$)/gi) ||
42
42
  [];
43
43
  if (propSections.length > 0) {
44
44
  response += `**Props & API:**\n${propSections
45
45
  .slice(0, 3)
46
- .join('\n\n')}\n\n`;
46
+ .join("\n\n")}\n\n`;
47
47
  }
48
48
  }
49
49
  // Include examples if requested
50
50
  if (include_examples) {
51
- const codeBlocks = content.match(/```[\s\S]*?```/g) ?? [];
52
- const jsxBlocks = content.match(/<Iress[A-Z][^>]*>[\s\S]*?<\/Iress[A-Z][^>]*>/g) ?? [];
51
+ const codeBlocks = content.match(/```[\s\S]*?```/g) || [];
52
+ const jsxBlocks = content.match(/<Iress[A-Z][^>]*>[\s\S]*?<\/Iress[A-Z][^>]*>/g) || [];
53
53
  const examples = [...codeBlocks, ...jsxBlocks];
54
54
  if (examples.length > 0) {
55
55
  response += `**Usage Examples:**\n${examples
56
56
  .slice(0, 3)
57
- .join('\n\n')}\n\n`;
57
+ .join("\n\n")}\n\n`;
58
58
  }
59
59
  }
60
60
  return {
61
61
  content: [
62
62
  {
63
- type: 'text',
63
+ type: "text",
64
64
  text: response,
65
65
  },
66
66
  ],
67
67
  };
68
68
  }
69
69
  catch (error) {
70
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
71
- throw new Error(`Failed to read component documentation: ${errorMessage}`);
70
+ throw new Error(`Failed to read component documentation: ${error}`);
72
71
  }
73
72
  }
74
- function formatComponentDetails(componentName, componentFile) {
75
- if (!componentFile) {
76
- return `**${componentName}** ❌ Not found\n\n`;
77
- }
78
- try {
79
- const filePath = path.join(DOCS_DIR, componentFile);
80
- const content = readFileContent(filePath);
81
- const lines = content.split('\n');
82
- const description = lines
83
- .slice(0, 20)
84
- .find((line) => line.trim() &&
85
- !line.startsWith('#') &&
86
- !line.startsWith('<!--') &&
87
- !line.includes('Overview') &&
88
- line.length > 20)
89
- ?.trim() ?? 'IDS component';
90
- return `**${componentName}** ✅\n - File: ${componentFile}\n - Description: ${description}\n\n`;
91
- }
92
- catch {
93
- return `**${componentName}** ❌\n - Error reading documentation\n\n`;
94
- }
95
- }
96
- function formatComponentSummary(componentName, componentFile) {
97
- const status = componentFile ? '✅ Available' : '❌ Not found';
98
- let result = `**${componentName}** ${status}\n`;
99
- if (componentFile) {
100
- result += ` - Documentation: ${componentFile}\n`;
101
- }
102
- return result + '\n';
103
- }
104
73
  export function handleAnalyzeComponentMentions(args) {
105
74
  const schema = z.object({
106
75
  text: z.string(),
@@ -112,7 +81,7 @@ export function handleAnalyzeComponentMentions(args) {
112
81
  return {
113
82
  content: [
114
83
  {
115
- type: 'text',
84
+ type: "text",
116
85
  text: "No Iress component mentions found in the provided text. Components should be mentioned with the 'Iress' prefix (e.g., IressButton, IressInput).",
117
86
  },
118
87
  ],
@@ -122,21 +91,46 @@ export function handleAnalyzeComponentMentions(args) {
122
91
  for (const componentName of componentMentions) {
123
92
  const componentFile = mapIressComponentToFile(componentName);
124
93
  if (detailed && componentFile) {
125
- response += formatComponentDetails(componentName, componentFile);
94
+ try {
95
+ const filePath = path.join(DOCS_DIR, componentFile);
96
+ const content = readFileContent(filePath);
97
+ // Get brief description
98
+ const lines = content.split("\n");
99
+ const description = lines
100
+ .slice(0, 20)
101
+ .find((line) => line.trim() &&
102
+ !line.startsWith("#") &&
103
+ !line.startsWith("<!--") &&
104
+ !line.includes("Overview") &&
105
+ line.length > 20)
106
+ ?.trim() || "IDS component";
107
+ response += `**${componentName}** ✅\n`;
108
+ response += ` - File: ${componentFile}\n`;
109
+ response += ` - Description: ${description}\n\n`;
110
+ }
111
+ catch (error) {
112
+ response += `**${componentName}** ❌\n`;
113
+ response += ` - Error reading documentation\n\n`;
114
+ }
126
115
  }
127
116
  else {
128
- response += formatComponentSummary(componentName, componentFile);
117
+ const status = componentFile ? "✅ Available" : "❌ Not found";
118
+ response += `**${componentName}** ${status}\n`;
119
+ if (componentFile) {
120
+ response += ` - Documentation: ${componentFile}\n`;
121
+ }
122
+ response += "\n";
129
123
  }
130
124
  }
131
125
  if (!detailed &&
132
126
  componentMentions.some((name) => mapIressComponentToFile(name))) {
133
127
  response +=
134
- '\n*Use the `get_iress_component_info` tool with a specific component name for detailed information.*';
128
+ "\n*Use the `get_iress_component_info` tool with a specific component name for detailed information.*";
135
129
  }
136
130
  return {
137
131
  content: [
138
132
  {
139
- type: 'text',
133
+ type: "text",
140
134
  text: response,
141
135
  },
142
136
  ],
@@ -1,36 +1,36 @@
1
1
  /**
2
2
  * Resource handlers for MCP server
3
3
  */
4
- import * as path from 'path';
5
- import { getMarkdownFiles, readFileContent } from './utils.js';
6
- import { DOCS_DIR } from './config.js';
4
+ import * as path from "path";
5
+ import { getMarkdownFiles, readFileContent } from "./utils.js";
6
+ import { DOCS_DIR } from "./config.js";
7
7
  export function handleListResources() {
8
8
  const markdownFiles = getMarkdownFiles();
9
9
  // Categorize resources for better organization
10
10
  const categorizedResources = markdownFiles.map((file) => {
11
- let category = 'Other';
11
+ let category = "Other";
12
12
  let name = file;
13
- if (file.startsWith('components-')) {
14
- category = 'Components';
15
- name = file.replace('components-', '').replace('-docs.md', '');
13
+ if (file.startsWith("components-")) {
14
+ category = "Components";
15
+ name = file.replace("components-", "").replace("-docs.md", "");
16
16
  }
17
- else if (file.startsWith('foundations-')) {
18
- category = 'Foundations';
19
- name = file.replace('foundations-', '').replace('-docs.md', '');
17
+ else if (file.startsWith("foundations-")) {
18
+ category = "Foundations";
19
+ name = file.replace("foundations-", "").replace("-docs.md", "");
20
20
  }
21
- else if (file.startsWith('resources-')) {
22
- category = 'Resources';
23
- name = file.replace('resources-', '').replace('-docs.md', '');
21
+ else if (file.startsWith("resources-")) {
22
+ category = "Resources";
23
+ name = file.replace("resources-", "").replace("-docs.md", "");
24
24
  }
25
- else if (file.includes('introduction')) {
26
- category = 'Getting Started';
27
- name = 'Introduction';
25
+ else if (file.includes("introduction")) {
26
+ category = "Getting Started";
27
+ name = "Introduction";
28
28
  }
29
29
  return {
30
30
  uri: `file://${path.join(DOCS_DIR, file)}`,
31
31
  name: `${category}: ${name}`,
32
32
  description: `IDS ${category.toLowerCase()} documentation for ${name}`,
33
- mimeType: 'text/markdown',
33
+ mimeType: "text/markdown",
34
34
  };
35
35
  });
36
36
  return {
@@ -39,14 +39,14 @@ export function handleListResources() {
39
39
  }
40
40
  export function handleReadResource(request) {
41
41
  const url = new URL(request.params.uri);
42
- if (url.protocol !== 'file:') {
42
+ if (url.protocol !== "file:") {
43
43
  throw new Error(`Unsupported protocol: ${url.protocol}`);
44
44
  }
45
45
  const filePath = url.pathname;
46
46
  // Ensure the file is within our docs directory
47
47
  const relativePath = path.relative(DOCS_DIR, filePath);
48
- if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
49
- throw new Error('Access denied: File is outside the docs directory');
48
+ if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
49
+ throw new Error("Access denied: File is outside the docs directory");
50
50
  }
51
51
  try {
52
52
  const content = readFileContent(filePath);
@@ -54,14 +54,13 @@ export function handleReadResource(request) {
54
54
  contents: [
55
55
  {
56
56
  uri: request.params.uri,
57
- mimeType: 'text/markdown',
57
+ mimeType: "text/markdown",
58
58
  text: content,
59
59
  },
60
60
  ],
61
61
  };
62
62
  }
63
63
  catch (error) {
64
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
65
- throw new Error(`Failed to read file: ${errorMessage}`);
64
+ throw new Error(`Failed to read file: ${error}`);
66
65
  }
67
66
  }
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Tool handlers for search and documentation operations
3
3
  */
4
- import { z } from 'zod';
5
- import * as path from 'path';
6
- import { getMarkdownFiles, readFileContent } from './utils.js';
7
- import { DOCS_DIR } from './config.js';
4
+ import { z } from "zod";
5
+ import * as path from "path";
6
+ import { getMarkdownFiles, readFileContent } from "./utils.js";
7
+ import { DOCS_DIR } from "./config.js";
8
8
  export function handleGetUsageExamples(args) {
9
9
  const schema = z.object({
10
10
  component: z.string(),
@@ -14,18 +14,18 @@ export function handleGetUsageExamples(args) {
14
14
  const markdownFiles = getMarkdownFiles();
15
15
  // Find component files (main + recipes)
16
16
  const componentFiles = markdownFiles.filter((file) => file.includes(`${component.toLowerCase()}`) ||
17
- (file.includes('recipes') &&
17
+ (file.includes("recipes") &&
18
18
  file.toLowerCase().includes(component.toLowerCase())));
19
19
  if (componentFiles.length === 0) {
20
20
  return {
21
21
  content: [
22
22
  {
23
- type: 'text',
23
+ type: "text",
24
24
  text: `No examples found for "${component}". Try: ${markdownFiles
25
- .filter((f) => f.startsWith('components-'))
25
+ .filter((f) => f.startsWith("components-"))
26
26
  .slice(0, 5)
27
- .map((f) => f.replace('components-', '').replace('-docs.md', ''))
28
- .join(', ')}`,
27
+ .map((f) => f.replace("components-", "").replace("-docs.md", ""))
28
+ .join(", ")}`,
29
29
  },
30
30
  ],
31
31
  };
@@ -36,8 +36,8 @@ export function handleGetUsageExamples(args) {
36
36
  const filePath = path.join(DOCS_DIR, file);
37
37
  const content = readFileContent(filePath);
38
38
  // Extract code examples
39
- const codeBlocks = content.match(/```[\s\S]*?```/g) ?? [];
40
- const jsxBlocks = content.match(/<[A-Z][^>]*>[\s\S]*?<\/[A-Z][^>]*>/g) ?? [];
39
+ const codeBlocks = content.match(/```[\s\S]*?```/g) || [];
40
+ const jsxBlocks = content.match(/<[A-Z][^>]*>[\s\S]*?<\/[A-Z][^>]*>/g) || [];
41
41
  if (pattern) {
42
42
  // Filter examples by pattern
43
43
  const patternMatches = [...codeBlocks, ...jsxBlocks].filter((block) => block.toLowerCase().includes(pattern.toLowerCase()));
@@ -51,18 +51,13 @@ export function handleGetUsageExamples(args) {
51
51
  console.error(`Error reading file ${file}:`, error);
52
52
  }
53
53
  }
54
- const patternSuffix = pattern ? ` (${pattern} pattern)` : '';
55
- const patternNotFoundSuffix = pattern ? ` with pattern "${pattern}"` : '';
56
- const examplesText = examples.length > 0
57
- ? `**${component} Usage Examples**${patternSuffix}:\n\n${examples
58
- .slice(0, 5)
59
- .join('\n\n---\n\n')}`
60
- : `No usage examples found for "${component}"${patternNotFoundSuffix}.`;
61
54
  return {
62
55
  content: [
63
56
  {
64
- type: 'text',
65
- text: examplesText,
57
+ type: "text",
58
+ text: examples.length > 0
59
+ ? `**${component} Usage Examples**${pattern ? ` (${pattern} pattern)` : ""}:\n\n${examples.slice(0, 5).join("\n\n---\n\n")}`
60
+ : `No usage examples found for "${component}"${pattern ? ` with pattern "${pattern}"` : ""}.`,
66
61
  },
67
62
  ],
68
63
  };
@@ -79,7 +74,7 @@ export function handleSearchIdsDocs(args) {
79
74
  try {
80
75
  const filePath = path.join(DOCS_DIR, file);
81
76
  const content = readFileContent(filePath);
82
- const lines = content.split('\n');
77
+ const lines = content.split("\n");
83
78
  lines.forEach((line, index) => {
84
79
  const searchLine = case_sensitive ? line : line.toLowerCase();
85
80
  const searchQuery = case_sensitive ? query : query.toLowerCase();
@@ -87,9 +82,9 @@ export function handleSearchIdsDocs(args) {
87
82
  // Get context (surrounding lines)
88
83
  const contextStart = Math.max(0, index - 1);
89
84
  const contextEnd = Math.min(lines.length - 1, index + 1);
90
- const context = lines.slice(contextStart, contextEnd + 1).join('\n');
85
+ const context = lines.slice(contextStart, contextEnd + 1).join("\n");
91
86
  results.push({
92
- file: file.replace('-docs.md', '').replace(/^[a-z]+-/, ''),
87
+ file: file.replace("-docs.md", "").replace(/^[a-z]+-/, ""),
93
88
  line: index + 1,
94
89
  content: line.trim(),
95
90
  context,
@@ -104,12 +99,12 @@ export function handleSearchIdsDocs(args) {
104
99
  return {
105
100
  content: [
106
101
  {
107
- type: 'text',
102
+ type: "text",
108
103
  text: results.length > 0
109
104
  ? `Found ${results.length} matches in IDS documentation:\n\n${results
110
105
  .slice(0, 15) // Limit results
111
106
  .map((r) => `**${r.file}:${r.line}**\n\`\`\`\n${r.context}\n\`\`\``)
112
- .join('\n\n')}`
107
+ .join("\n\n")}`
113
108
  : `No matches found for "${query}" in IDS documentation.`,
114
109
  },
115
110
  ],
@@ -118,32 +113,31 @@ export function handleSearchIdsDocs(args) {
118
113
  export function handleGetDesignTokens(args) {
119
114
  const schema = z.object({
120
115
  type: z
121
- .enum(['colors', 'spacing', 'typography', 'breakpoints', 'all'])
122
- .default('all'),
116
+ .enum(["colors", "spacing", "typography", "breakpoints", "all"])
117
+ .default("all"),
123
118
  });
124
119
  const { type } = schema.parse(args);
125
120
  const markdownFiles = getMarkdownFiles();
126
121
  // Find foundation files related to design tokens
127
- const foundationFiles = markdownFiles.filter((file) => file.startsWith('foundations-') &&
128
- (type === 'all' || file.includes(type)));
122
+ const foundationFiles = markdownFiles.filter((file) => file.startsWith("foundations-") && (type === "all" || file.includes(type)));
129
123
  const tokenInfo = [];
130
124
  for (const file of foundationFiles) {
131
125
  try {
132
126
  const filePath = path.join(DOCS_DIR, file);
133
127
  const content = readFileContent(filePath);
134
128
  // Extract CSS custom properties and token information
135
- const cssVariables = content.match(/--iress-[a-z-]+/g) ?? [];
136
- const tokenSections = content.match(/#{2,3}\s+[^#\n]+/g) ?? [];
129
+ const cssVariables = content.match(/--iress-[a-z-]+/g) || [];
130
+ const tokenSections = content.match(/###?\s+[^#\n]+[\s\S]*?(?=###|$)/g) || [];
137
131
  if (cssVariables.length > 0 || tokenSections.length > 0) {
138
132
  let fileInfo = `**${file
139
- .replace('foundations-', '')
140
- .replace('-docs.md', '')}**\n`;
133
+ .replace("foundations-", "")
134
+ .replace("-docs.md", "")}**\n`;
141
135
  if (cssVariables.length > 0) {
142
136
  const uniqueVars = [...new Set(cssVariables)].slice(0, 10);
143
- fileInfo += `CSS Variables: ${uniqueVars.join(', ')}\n`;
137
+ fileInfo += `CSS Variables: ${uniqueVars.join(", ")}\n`;
144
138
  }
145
139
  if (tokenSections.length > 0) {
146
- fileInfo += `\n${tokenSections.slice(0, 3).join('\n\n')}`;
140
+ fileInfo += `\n${tokenSections.slice(0, 3).join("\n\n")}`;
147
141
  }
148
142
  tokenInfo.push(fileInfo);
149
143
  }
@@ -152,61 +146,20 @@ export function handleGetDesignTokens(args) {
152
146
  console.error(`Error reading file ${file}:`, error);
153
147
  }
154
148
  }
155
- const typeLabel = type !== 'all' ? ` (${type})` : '';
156
- const typeNotFoundLabel = type !== 'all' ? ` for ${type}` : '';
157
149
  return {
158
150
  content: [
159
151
  {
160
- type: 'text',
152
+ type: "text",
161
153
  text: tokenInfo.length > 0
162
- ? `**IDS Design Tokens${typeLabel}**\n\n${tokenInfo.join('\n\n---\n\n')}`
163
- : `No design token information found${typeNotFoundLabel}. Available foundations: ${markdownFiles
164
- .filter((f) => f.startsWith('foundations-'))
165
- .map((f) => f.replace('foundations-', '').replace('-docs.md', ''))
166
- .join(', ')}`,
154
+ ? `**IDS Design Tokens${type !== "all" ? ` (${type})` : ""}**\n\n${tokenInfo.join("\n\n---\n\n")}`
155
+ : `No design token information found${type !== "all" ? ` for ${type}` : ""}. Available foundations: ${markdownFiles
156
+ .filter((f) => f.startsWith("foundations-"))
157
+ .map((f) => f.replace("foundations-", "").replace("-docs.md", ""))
158
+ .join(", ")}`,
167
159
  },
168
160
  ],
169
161
  };
170
162
  }
171
- function findSectionContent(content, section) {
172
- const sectionRegex = new RegExp(`(#{1,3}\\s+.*${section}.*?(?=#{1,3}|$))`, 'gis');
173
- const sectionMatch = sectionRegex.exec(content);
174
- if (sectionMatch) {
175
- return sectionMatch[0];
176
- }
177
- // Try to find sections that contain the search term
178
- const sections = content.split(/(?=#{1,3}\s+)/);
179
- const matchingSections = sections.filter((sectionContent) => sectionContent.toLowerCase().includes(section.toLowerCase()));
180
- return matchingSections.length > 0 ? matchingSections.join('\n\n') : null;
181
- }
182
- function addContextLines(lines, startIndex, endIndex, contextLines) {
183
- for (let j = startIndex; j < endIndex; j++) {
184
- if (!contextLines.includes(lines[j])) {
185
- contextLines.push(lines[j]);
186
- }
187
- }
188
- }
189
- function filterContentByQuery(content, query) {
190
- const lines = content.split('\n');
191
- const contextLines = [];
192
- const queryLower = query.toLowerCase();
193
- for (let i = 0; i < lines.length; i++) {
194
- const line = lines[i];
195
- if (line.toLowerCase().includes(queryLower)) {
196
- // Add context lines before
197
- const startContext = Math.max(0, i - 3);
198
- addContextLines(lines, startContext, i, contextLines);
199
- // Add the matching line
200
- if (!contextLines.includes(line)) {
201
- contextLines.push(line);
202
- }
203
- // Add context lines after
204
- const endContext = Math.min(lines.length, i + 4);
205
- addContextLines(lines, i + 1, endContext, contextLines);
206
- }
207
- }
208
- return contextLines.length > 0 ? contextLines.join('\n') : null;
209
- }
210
163
  export function handleGetDesignGuidelines(args) {
211
164
  const schema = z.object({
212
165
  section: z.string().optional(),
@@ -215,14 +168,14 @@ export function handleGetDesignGuidelines(args) {
215
168
  const { section, query } = schema.parse(args);
216
169
  try {
217
170
  // Read the guidelines.md file from the docs directory
218
- const guidelinesPath = path.join(DOCS_DIR, 'guidelines.md');
171
+ const guidelinesPath = path.join(DOCS_DIR, "..", "guidelines.md");
219
172
  const content = readFileContent(guidelinesPath);
220
173
  if (!content) {
221
174
  return {
222
175
  content: [
223
176
  {
224
- type: 'text',
225
- text: 'Design guidelines file not found. Please ensure guidelines.md exists in the docs directory.',
177
+ type: "text",
178
+ text: "Design guidelines file not found. Please ensure guidelines.md exists in the docs directory.",
226
179
  },
227
180
  ],
228
181
  };
@@ -230,56 +183,88 @@ export function handleGetDesignGuidelines(args) {
230
183
  let filteredContent = content;
231
184
  // Filter by section if specified
232
185
  if (section) {
233
- const sectionContent = findSectionContent(content, section);
234
- if (sectionContent) {
235
- filteredContent = sectionContent;
186
+ const sectionRegex = new RegExp(`(#{1,3}\\s+.*${section}.*?(?=#{1,3}|$))`, "gis");
187
+ const sectionMatch = content.match(sectionRegex);
188
+ if (sectionMatch) {
189
+ filteredContent = sectionMatch[0];
236
190
  }
237
191
  else {
238
- return {
239
- content: [
240
- {
241
- type: 'text',
242
- text: `Section "${section}" not found in design guidelines. Available sections include: Core Design Principles, Visual Design Standards, Component Guidelines, Accessibility, Layout Systems, and Best Practices.`,
243
- },
244
- ],
245
- };
192
+ // Try to find sections that contain the search term
193
+ const sections = content.split(/(?=#{1,3}\s+)/);
194
+ const matchingSections = sections.filter((section) => section.toLowerCase().includes(section.toLowerCase()));
195
+ if (matchingSections.length > 0) {
196
+ filteredContent = matchingSections.join("\n\n");
197
+ }
198
+ else {
199
+ return {
200
+ content: [
201
+ {
202
+ type: "text",
203
+ text: `Section "${section}" not found in design guidelines. Available sections include: Core Design Principles, Visual Design Standards, Component Guidelines, Accessibility, Layout Systems, and Best Practices.`,
204
+ },
205
+ ],
206
+ };
207
+ }
246
208
  }
247
209
  }
248
210
  // Filter by query if specified
249
211
  if (query) {
250
- const queryContent = filterContentByQuery(filteredContent, query);
251
- if (queryContent) {
252
- filteredContent = queryContent;
212
+ const lines = filteredContent.split("\n");
213
+ const relevantLines = [];
214
+ let contextLines = [];
215
+ for (let i = 0; i < lines.length; i++) {
216
+ const line = lines[i];
217
+ if (line.toLowerCase().includes(query.toLowerCase())) {
218
+ // Add context lines before
219
+ const startContext = Math.max(0, i - 3);
220
+ for (let j = startContext; j < i; j++) {
221
+ if (!contextLines.includes(lines[j])) {
222
+ contextLines.push(lines[j]);
223
+ }
224
+ }
225
+ // Add the matching line
226
+ if (!contextLines.includes(line)) {
227
+ contextLines.push(line);
228
+ }
229
+ // Add context lines after
230
+ const endContext = Math.min(lines.length, i + 4);
231
+ for (let j = i + 1; j < endContext; j++) {
232
+ if (!contextLines.includes(lines[j])) {
233
+ contextLines.push(lines[j]);
234
+ }
235
+ }
236
+ }
237
+ }
238
+ if (contextLines.length > 0) {
239
+ filteredContent = contextLines.join("\n");
253
240
  }
254
241
  else {
255
242
  return {
256
243
  content: [
257
244
  {
258
- type: 'text',
245
+ type: "text",
259
246
  text: `No guidelines found matching "${query}". Try searching for terms like: accessibility, typography, colors, spacing, components, principles, or usability.`,
260
247
  },
261
248
  ],
262
249
  };
263
250
  }
264
251
  }
265
- const sectionSuffix = section ? ` - ${section}` : '';
266
- const querySuffix = query ? ` (filtered by: ${query})` : '';
267
252
  return {
268
253
  content: [
269
254
  {
270
- type: 'text',
271
- text: `**IDS Design Guidelines${sectionSuffix}${querySuffix}**\n\n${filteredContent}`,
255
+ type: "text",
256
+ text: `**IDS Design Guidelines${section ? ` - ${section}` : ""}${query ? ` (filtered by: ${query})` : ""}**\n\n${filteredContent}`,
272
257
  },
273
258
  ],
274
259
  };
275
260
  }
276
261
  catch (error) {
277
- console.error('Error reading guidelines:', error);
262
+ console.error("Error reading guidelines:", error);
278
263
  return {
279
264
  content: [
280
265
  {
281
- type: 'text',
282
- text: 'Error reading design guidelines. Please ensure the guidelines.md file exists and is accessible.',
266
+ type: "text",
267
+ text: "Error reading design guidelines. Please ensure the guidelines.md file exists and is accessible.",
283
268
  },
284
269
  ],
285
270
  };