@iress-oss/ids-mcp-server 0.0.1-dev.4 → 0.0.1-dev.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.
- package/generated/docs/components-autocomplete-docs.md +3 -3
- package/generated/docs/components-combobox-docs.md +4 -4
- package/generated/docs/components-filter-docs.md +3 -3
- package/generated/docs/components-form-docs.md +37 -5
- package/generated/docs/components-table-ag-grid-docs.md +1696 -104
- package/generated/docs/components-table-docs.md +6 -6
- package/generated/docs/extensions-editor-docs.md +3 -3
- package/generated/docs/themes-available-themes-docs.md +29 -29
- package/package.json +2 -12
- package/dist/componentHandlers.js +0 -241
- package/dist/componentHandlers.test.js +0 -380
- package/dist/config.js +0 -16
- package/dist/index.js +0 -53
- package/dist/iressHandlers.js +0 -144
- package/dist/iressHandlers.test.js +0 -316
- package/dist/resourceHandlers.js +0 -67
- package/dist/resourceHandlers.test.js +0 -352
- package/dist/searchHandlers.js +0 -287
- package/dist/searchHandlers.test.js +0 -524
- package/dist/toolHandler.js +0 -31
- package/dist/toolHandler.test.js +0 -369
- package/dist/tools.js +0 -165
- package/dist/types.js +0 -4
- package/dist/utils.js +0 -59
- package/dist/utils.test.js +0 -286
package/dist/index.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
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, () => {
|
|
17
|
-
const result = handleListResources();
|
|
18
|
-
return result;
|
|
19
|
-
});
|
|
20
|
-
/**
|
|
21
|
-
* Read content from a specific markdown file
|
|
22
|
-
*/
|
|
23
|
-
server.setRequestHandler(ReadResourceRequestSchema, (request) => {
|
|
24
|
-
const result = handleReadResource(request);
|
|
25
|
-
return result;
|
|
26
|
-
});
|
|
27
|
-
/**
|
|
28
|
-
* List available IDS development tools
|
|
29
|
-
*/
|
|
30
|
-
server.setRequestHandler(ListToolsRequestSchema, () => {
|
|
31
|
-
return {
|
|
32
|
-
tools: toolDefinitions,
|
|
33
|
-
};
|
|
34
|
-
});
|
|
35
|
-
/**
|
|
36
|
-
* Handle IDS component library tool calls
|
|
37
|
-
*/
|
|
38
|
-
server.setRequestHandler(CallToolRequestSchema, (request) => {
|
|
39
|
-
const result = handleToolCall(request);
|
|
40
|
-
return result;
|
|
41
|
-
});
|
|
42
|
-
/**
|
|
43
|
-
* Start the server
|
|
44
|
-
*/
|
|
45
|
-
async function main() {
|
|
46
|
-
const transport = new StdioServerTransport();
|
|
47
|
-
await server.connect(transport);
|
|
48
|
-
console.error('IDS Component Library MCP Server running on stdio');
|
|
49
|
-
}
|
|
50
|
-
main().catch((error) => {
|
|
51
|
-
console.error('Server error:', error);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
});
|
package/dist/iressHandlers.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool handlers for Iress component-specific operations
|
|
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';
|
|
8
|
-
export function handleGetIressComponentInfo(args) {
|
|
9
|
-
const schema = z.object({
|
|
10
|
-
component_name: z.string(),
|
|
11
|
-
include_examples: z.boolean().default(true),
|
|
12
|
-
include_props: z.boolean().default(true),
|
|
13
|
-
});
|
|
14
|
-
const { component_name, include_examples, include_props } = schema.parse(args);
|
|
15
|
-
// Find the corresponding documentation file
|
|
16
|
-
const componentFile = mapIressComponentToFile(component_name);
|
|
17
|
-
if (!componentFile) {
|
|
18
|
-
return {
|
|
19
|
-
content: [
|
|
20
|
-
{
|
|
21
|
-
type: 'text',
|
|
22
|
-
text: `Component "${component_name}" not found. Make sure you're using the correct Iress component name (e.g., IressButton, IressInput, IressTable).`,
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
const filePath = path.join(DOCS_DIR, componentFile);
|
|
29
|
-
const content = readFileContent(filePath);
|
|
30
|
-
let response = `**${component_name} Component Documentation**\n\n`;
|
|
31
|
-
// Extract overview/description
|
|
32
|
-
const lines = content.split('\n');
|
|
33
|
-
const overviewStart = lines.findIndex((line) => line.toLowerCase().includes('overview'));
|
|
34
|
-
if (overviewStart !== -1) {
|
|
35
|
-
const overviewEnd = lines.findIndex((line, index) => index > overviewStart && line.startsWith('#'));
|
|
36
|
-
const overviewLines = lines.slice(overviewStart, overviewEnd !== -1 ? overviewEnd : overviewStart + 10);
|
|
37
|
-
response += `${overviewLines.join('\n')}\n\n`;
|
|
38
|
-
}
|
|
39
|
-
// Include props if requested
|
|
40
|
-
if (include_props) {
|
|
41
|
-
const propSections = content.match(/(mode|prop|Properties|API)[\s\S]*?(?=\n##|\n\[#|$)/gi) ??
|
|
42
|
-
[];
|
|
43
|
-
if (propSections.length > 0) {
|
|
44
|
-
response += `**Props & API:**\n${propSections
|
|
45
|
-
.slice(0, 3)
|
|
46
|
-
.join('\n\n')}\n\n`;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// Include examples if requested
|
|
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) ?? [];
|
|
53
|
-
const examples = [...codeBlocks, ...jsxBlocks];
|
|
54
|
-
if (examples.length > 0) {
|
|
55
|
-
response += `**Usage Examples:**\n${examples
|
|
56
|
-
.slice(0, 3)
|
|
57
|
-
.join('\n\n')}\n\n`;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
content: [
|
|
62
|
-
{
|
|
63
|
-
type: 'text',
|
|
64
|
-
text: response,
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
71
|
-
throw new Error(`Failed to read component documentation: ${errorMessage}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
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
|
-
export function handleAnalyzeComponentMentions(args) {
|
|
105
|
-
const schema = z.object({
|
|
106
|
-
text: z.string(),
|
|
107
|
-
detailed: z.boolean().default(false),
|
|
108
|
-
});
|
|
109
|
-
const { text, detailed } = schema.parse(args);
|
|
110
|
-
const componentMentions = extractIressComponents(text);
|
|
111
|
-
if (componentMentions.length === 0) {
|
|
112
|
-
return {
|
|
113
|
-
content: [
|
|
114
|
-
{
|
|
115
|
-
type: 'text',
|
|
116
|
-
text: "No Iress component mentions found in the provided text. Components should be mentioned with the 'Iress' prefix (e.g., IressButton, IressInput).",
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
let response = `**Found ${componentMentions.length} Iress component mention(s):**\n\n`;
|
|
122
|
-
for (const componentName of componentMentions) {
|
|
123
|
-
const componentFile = mapIressComponentToFile(componentName);
|
|
124
|
-
if (detailed && componentFile) {
|
|
125
|
-
response += formatComponentDetails(componentName, componentFile);
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
response += formatComponentSummary(componentName, componentFile);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (!detailed &&
|
|
132
|
-
componentMentions.some((name) => mapIressComponentToFile(name))) {
|
|
133
|
-
response +=
|
|
134
|
-
'\n*Use the `get_iress_component_info` tool with a specific component name for detailed information.*';
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
content: [
|
|
138
|
-
{
|
|
139
|
-
type: 'text',
|
|
140
|
-
text: response,
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
};
|
|
144
|
-
}
|
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Iress component handlers
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
5
|
-
import { handleGetIressComponentInfo, handleAnalyzeComponentMentions, } from './iressHandlers.js';
|
|
6
|
-
import * as utils from './utils.js';
|
|
7
|
-
// Mock the utils module
|
|
8
|
-
vi.mock('./utils.js', () => ({
|
|
9
|
-
mapIressComponentToFile: vi.fn(),
|
|
10
|
-
extractIressComponents: vi.fn(),
|
|
11
|
-
readFileContent: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
// Mock the config module
|
|
14
|
-
vi.mock('./config.js', () => ({
|
|
15
|
-
DOCS_DIR: '/mocked/docs/path',
|
|
16
|
-
}));
|
|
17
|
-
const mockUtils = vi.mocked(utils);
|
|
18
|
-
describe('iressHandlers', () => {
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
vi.clearAllMocks();
|
|
21
|
-
});
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
vi.restoreAllMocks();
|
|
24
|
-
});
|
|
25
|
-
describe('handleGetIressComponentInfo', () => {
|
|
26
|
-
const mockComponentContent = `# IressButton Component
|
|
27
|
-
|
|
28
|
-
## Overview
|
|
29
|
-
The IressButton component is a versatile button component for the Iress Design System.
|
|
30
|
-
|
|
31
|
-
## Props
|
|
32
|
-
- \`variant\`: string - The button variant (primary, secondary, etc.)
|
|
33
|
-
- \`size\`: string - The button size (small, medium, large)
|
|
34
|
-
- \`disabled\`: boolean - Whether the button is disabled
|
|
35
|
-
|
|
36
|
-
## Examples
|
|
37
|
-
\`\`\`jsx
|
|
38
|
-
<IressButton variant="primary" size="medium">
|
|
39
|
-
Click me
|
|
40
|
-
</IressButton>
|
|
41
|
-
\`\`\`
|
|
42
|
-
|
|
43
|
-
## API Reference
|
|
44
|
-
Additional API documentation here.
|
|
45
|
-
`;
|
|
46
|
-
it('should return component information with examples and props by default', () => {
|
|
47
|
-
const args = {
|
|
48
|
-
component_name: 'IressButton',
|
|
49
|
-
};
|
|
50
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
51
|
-
mockUtils.readFileContent.mockReturnValue(mockComponentContent);
|
|
52
|
-
const result = handleGetIressComponentInfo(args);
|
|
53
|
-
expect(mockUtils.mapIressComponentToFile).toHaveBeenCalledWith('IressButton');
|
|
54
|
-
expect(mockUtils.readFileContent).toHaveBeenCalledWith('/mocked/docs/path/components-button-docs.md');
|
|
55
|
-
expect(result.content).toHaveLength(1);
|
|
56
|
-
expect(result.content[0].type).toBe('text');
|
|
57
|
-
expect(result.content[0].text).toContain('**IressButton Component Documentation**');
|
|
58
|
-
expect(result.content[0].text).toContain('The IressButton component is a versatile button component');
|
|
59
|
-
expect(result.content[0].text).toContain('**Props & API:**');
|
|
60
|
-
expect(result.content[0].text).toContain('**Usage Examples:**');
|
|
61
|
-
expect(result.content[0].text).toContain('<IressButton variant="primary"');
|
|
62
|
-
});
|
|
63
|
-
it('should include examples when include_examples is true', () => {
|
|
64
|
-
const args = {
|
|
65
|
-
component_name: 'IressButton',
|
|
66
|
-
include_examples: true,
|
|
67
|
-
include_props: false,
|
|
68
|
-
};
|
|
69
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
70
|
-
mockUtils.readFileContent.mockReturnValue(mockComponentContent);
|
|
71
|
-
const result = handleGetIressComponentInfo(args);
|
|
72
|
-
expect(result.content[0].text).toContain('**Usage Examples:**');
|
|
73
|
-
expect(result.content[0].text).not.toContain('**Props & API:**');
|
|
74
|
-
});
|
|
75
|
-
it('should include props when include_props is true', () => {
|
|
76
|
-
const args = {
|
|
77
|
-
component_name: 'IressButton',
|
|
78
|
-
include_examples: false,
|
|
79
|
-
include_props: true,
|
|
80
|
-
};
|
|
81
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
82
|
-
mockUtils.readFileContent.mockReturnValue(mockComponentContent);
|
|
83
|
-
const result = handleGetIressComponentInfo(args);
|
|
84
|
-
expect(result.content[0].text).toContain('**Props & API:**');
|
|
85
|
-
expect(result.content[0].text).not.toContain('**Usage Examples:**');
|
|
86
|
-
});
|
|
87
|
-
it('should exclude examples and props when both flags are false', () => {
|
|
88
|
-
const args = {
|
|
89
|
-
component_name: 'IressButton',
|
|
90
|
-
include_examples: false,
|
|
91
|
-
include_props: false,
|
|
92
|
-
};
|
|
93
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
94
|
-
mockUtils.readFileContent.mockReturnValue(mockComponentContent);
|
|
95
|
-
const result = handleGetIressComponentInfo(args);
|
|
96
|
-
expect(result.content[0].text).not.toContain('**Usage Examples:**');
|
|
97
|
-
expect(result.content[0].text).not.toContain('**Props & API:**');
|
|
98
|
-
expect(result.content[0].text).toContain('**IressButton Component Documentation**');
|
|
99
|
-
});
|
|
100
|
-
it('should return error message when component is not found', () => {
|
|
101
|
-
const args = {
|
|
102
|
-
component_name: 'IressNonExistent',
|
|
103
|
-
};
|
|
104
|
-
mockUtils.mapIressComponentToFile.mockReturnValue(null);
|
|
105
|
-
const result = handleGetIressComponentInfo(args);
|
|
106
|
-
expect(result.content).toHaveLength(1);
|
|
107
|
-
expect(result.content[0].type).toBe('text');
|
|
108
|
-
expect(result.content[0].text).toContain('Component "IressNonExistent" not found');
|
|
109
|
-
expect(result.content[0].text).toContain("Make sure you're using the correct Iress component name");
|
|
110
|
-
});
|
|
111
|
-
it('should throw error when file reading fails', () => {
|
|
112
|
-
const args = {
|
|
113
|
-
component_name: 'IressButton',
|
|
114
|
-
};
|
|
115
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
116
|
-
mockUtils.readFileContent.mockImplementation(() => {
|
|
117
|
-
throw new Error('File not accessible');
|
|
118
|
-
});
|
|
119
|
-
expect(() => handleGetIressComponentInfo(args)).toThrow('Failed to read component documentation: File not accessible');
|
|
120
|
-
});
|
|
121
|
-
it('should validate input parameters using zod schema', () => {
|
|
122
|
-
const invalidArgs = {
|
|
123
|
-
component_name: 123, // Should be string
|
|
124
|
-
};
|
|
125
|
-
expect(() => handleGetIressComponentInfo(invalidArgs)).toThrow();
|
|
126
|
-
});
|
|
127
|
-
it('should handle missing optional parameters with defaults', () => {
|
|
128
|
-
const args = {
|
|
129
|
-
component_name: 'IressButton',
|
|
130
|
-
// include_examples and include_props not provided, should default to true
|
|
131
|
-
};
|
|
132
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
133
|
-
mockUtils.readFileContent.mockReturnValue(mockComponentContent);
|
|
134
|
-
const result = handleGetIressComponentInfo(args);
|
|
135
|
-
expect(result.content[0].text).toContain('**Usage Examples:**');
|
|
136
|
-
expect(result.content[0].text).toContain('**Props & API:**');
|
|
137
|
-
});
|
|
138
|
-
it('should limit examples and prop sections to 3 items each', () => {
|
|
139
|
-
const contentWithMultipleExamples = `# IressButton
|
|
140
|
-
|
|
141
|
-
## Overview
|
|
142
|
-
Button component
|
|
143
|
-
|
|
144
|
-
## Props
|
|
145
|
-
First prop section
|
|
146
|
-
## API
|
|
147
|
-
Second API section
|
|
148
|
-
## Properties
|
|
149
|
-
Third properties section
|
|
150
|
-
## Mode
|
|
151
|
-
Fourth mode section
|
|
152
|
-
|
|
153
|
-
\`\`\`jsx
|
|
154
|
-
Example 1
|
|
155
|
-
\`\`\`
|
|
156
|
-
|
|
157
|
-
\`\`\`jsx
|
|
158
|
-
Example 2
|
|
159
|
-
\`\`\`
|
|
160
|
-
|
|
161
|
-
\`\`\`jsx
|
|
162
|
-
Example 3
|
|
163
|
-
\`\`\`
|
|
164
|
-
|
|
165
|
-
\`\`\`jsx
|
|
166
|
-
Example 4
|
|
167
|
-
\`\`\`
|
|
168
|
-
|
|
169
|
-
<IressButton>Example 5</IressButton>
|
|
170
|
-
`;
|
|
171
|
-
const args = {
|
|
172
|
-
component_name: 'IressButton',
|
|
173
|
-
};
|
|
174
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
175
|
-
mockUtils.readFileContent.mockReturnValue(contentWithMultipleExamples);
|
|
176
|
-
const result = handleGetIressComponentInfo(args);
|
|
177
|
-
// Should limit to 3 prop sections and 3 examples
|
|
178
|
-
const propMatches = result.content[0].text.match(/First prop section|Second API section|Third properties section|Fourth mode section/g);
|
|
179
|
-
const exampleMatches = result.content[0].text.match(/Example [1-5]/g);
|
|
180
|
-
expect(propMatches?.length).toBeLessThanOrEqual(3);
|
|
181
|
-
expect(exampleMatches?.length).toBeLessThanOrEqual(3);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
describe('handleAnalyzeComponentMentions', () => {
|
|
185
|
-
it('should analyze text and find component mentions', () => {
|
|
186
|
-
const args = {
|
|
187
|
-
text: 'Use IressButton and IressInput components in your form.',
|
|
188
|
-
detailed: false,
|
|
189
|
-
};
|
|
190
|
-
mockUtils.extractIressComponents.mockReturnValue([
|
|
191
|
-
'IressButton',
|
|
192
|
-
'IressInput',
|
|
193
|
-
]);
|
|
194
|
-
// Mock the function to return files for both calls
|
|
195
|
-
mockUtils.mapIressComponentToFile.mockImplementation((name) => {
|
|
196
|
-
if (name === 'IressButton')
|
|
197
|
-
return 'components-button-docs.md';
|
|
198
|
-
if (name === 'IressInput')
|
|
199
|
-
return 'components-input-docs.md';
|
|
200
|
-
return null;
|
|
201
|
-
});
|
|
202
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
203
|
-
expect(mockUtils.extractIressComponents).toHaveBeenCalledWith('Use IressButton and IressInput components in your form.');
|
|
204
|
-
expect(result.content).toHaveLength(1);
|
|
205
|
-
expect(result.content[0].type).toBe('text');
|
|
206
|
-
expect(result.content[0].text).toContain('Found 2 Iress component mention(s)');
|
|
207
|
-
expect(result.content[0].text).toContain('**IressButton** ✅ Available');
|
|
208
|
-
expect(result.content[0].text).toContain('**IressInput** ✅ Available');
|
|
209
|
-
expect(result.content[0].text).toContain('*Use the `get_iress_component_info` tool with a specific component name for detailed information.*');
|
|
210
|
-
});
|
|
211
|
-
it('should provide detailed information when detailed flag is true', () => {
|
|
212
|
-
const args = {
|
|
213
|
-
text: 'Use IressButton component.',
|
|
214
|
-
detailed: true,
|
|
215
|
-
};
|
|
216
|
-
const mockFileContent = `# IressButton
|
|
217
|
-
A great button component for interactive elements.
|
|
218
|
-
## Props
|
|
219
|
-
- variant: string
|
|
220
|
-
`;
|
|
221
|
-
mockUtils.extractIressComponents.mockReturnValue(['IressButton']);
|
|
222
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
223
|
-
mockUtils.readFileContent.mockReturnValue(mockFileContent);
|
|
224
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
225
|
-
expect(result.content[0].text).toContain('**IressButton** ✅');
|
|
226
|
-
expect(result.content[0].text).toContain('File: components-button-docs.md');
|
|
227
|
-
expect(result.content[0].text).toContain('Description: A great button component');
|
|
228
|
-
});
|
|
229
|
-
it('should handle components that are not found', () => {
|
|
230
|
-
const args = {
|
|
231
|
-
text: 'Use IressNonExistent component.',
|
|
232
|
-
detailed: false,
|
|
233
|
-
};
|
|
234
|
-
mockUtils.extractIressComponents.mockReturnValue(['IressNonExistent']);
|
|
235
|
-
mockUtils.mapIressComponentToFile.mockReturnValue(null);
|
|
236
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
237
|
-
expect(result.content[0].text).toContain('**IressNonExistent** ❌ Not found');
|
|
238
|
-
});
|
|
239
|
-
it('should return appropriate message when no components are found', () => {
|
|
240
|
-
const args = {
|
|
241
|
-
text: 'This text has no component mentions.',
|
|
242
|
-
detailed: false,
|
|
243
|
-
};
|
|
244
|
-
mockUtils.extractIressComponents.mockReturnValue([]);
|
|
245
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
246
|
-
expect(result.content[0].text).toContain('No Iress component mentions found');
|
|
247
|
-
expect(result.content[0].text).toContain("Components should be mentioned with the 'Iress' prefix");
|
|
248
|
-
});
|
|
249
|
-
it('should handle file reading errors in detailed mode gracefully', () => {
|
|
250
|
-
const args = {
|
|
251
|
-
text: 'Use IressButton component.',
|
|
252
|
-
detailed: true,
|
|
253
|
-
};
|
|
254
|
-
mockUtils.extractIressComponents.mockReturnValue(['IressButton']);
|
|
255
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
256
|
-
mockUtils.readFileContent.mockImplementation(() => {
|
|
257
|
-
throw new Error('File read error');
|
|
258
|
-
});
|
|
259
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
260
|
-
expect(result.content[0].text).toContain('**IressButton** ❌');
|
|
261
|
-
expect(result.content[0].text).toContain('Error reading documentation');
|
|
262
|
-
});
|
|
263
|
-
it('should validate input parameters using zod schema', () => {
|
|
264
|
-
const invalidArgs = {
|
|
265
|
-
text: 123, // Should be string
|
|
266
|
-
};
|
|
267
|
-
expect(() => handleAnalyzeComponentMentions(invalidArgs)).toThrow();
|
|
268
|
-
});
|
|
269
|
-
it('should handle missing optional detailed parameter with default false', () => {
|
|
270
|
-
const args = {
|
|
271
|
-
text: 'Use IressButton component.',
|
|
272
|
-
// detailed not provided, should default to false
|
|
273
|
-
};
|
|
274
|
-
mockUtils.extractIressComponents.mockReturnValue(['IressButton']);
|
|
275
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
276
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
277
|
-
// Should use summary format (not detailed)
|
|
278
|
-
expect(result.content[0].text).toContain('**IressButton** ✅ Available');
|
|
279
|
-
expect(result.content[0].text).not.toContain('Description:');
|
|
280
|
-
});
|
|
281
|
-
it('should not show detailed info prompt when detailed is true', () => {
|
|
282
|
-
const args = {
|
|
283
|
-
text: 'Use IressButton component.',
|
|
284
|
-
detailed: true,
|
|
285
|
-
};
|
|
286
|
-
const mockFileContent = 'Button documentation';
|
|
287
|
-
mockUtils.extractIressComponents.mockReturnValue(['IressButton']);
|
|
288
|
-
mockUtils.mapIressComponentToFile.mockReturnValue('components-button-docs.md');
|
|
289
|
-
mockUtils.readFileContent.mockReturnValue(mockFileContent);
|
|
290
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
291
|
-
expect(result.content[0].text).not.toContain('*Use the `get_iress_component_info` tool with a specific component name for detailed information.*');
|
|
292
|
-
});
|
|
293
|
-
it('should handle mixed found and not found components', () => {
|
|
294
|
-
const args = {
|
|
295
|
-
text: 'Use IressButton and IressNonExistent components.',
|
|
296
|
-
detailed: false,
|
|
297
|
-
};
|
|
298
|
-
mockUtils.extractIressComponents.mockReturnValue([
|
|
299
|
-
'IressButton',
|
|
300
|
-
'IressNonExistent',
|
|
301
|
-
]);
|
|
302
|
-
// Mock the function to return different results for each component
|
|
303
|
-
mockUtils.mapIressComponentToFile.mockImplementation((name) => {
|
|
304
|
-
if (name === 'IressButton')
|
|
305
|
-
return 'components-button-docs.md';
|
|
306
|
-
if (name === 'IressNonExistent')
|
|
307
|
-
return null;
|
|
308
|
-
return null;
|
|
309
|
-
});
|
|
310
|
-
const result = handleAnalyzeComponentMentions(args);
|
|
311
|
-
expect(result.content[0].text).toContain('**IressButton** ✅ Available');
|
|
312
|
-
expect(result.content[0].text).toContain('**IressNonExistent** ❌ Not found');
|
|
313
|
-
expect(result.content[0].text).toContain('*Use the `get_iress_component_info` tool with a specific component name for detailed information.*');
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
});
|
package/dist/resourceHandlers.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resource handlers for MCP server
|
|
3
|
-
*/
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import { getMarkdownFiles, readFileContent } from './utils.js';
|
|
6
|
-
import { DOCS_DIR } from './config.js';
|
|
7
|
-
export function handleListResources() {
|
|
8
|
-
const markdownFiles = getMarkdownFiles();
|
|
9
|
-
// Categorize resources for better organization
|
|
10
|
-
const categorizedResources = markdownFiles.map((file) => {
|
|
11
|
-
let category = 'Other';
|
|
12
|
-
let name = file;
|
|
13
|
-
if (file.startsWith('components-')) {
|
|
14
|
-
category = 'Components';
|
|
15
|
-
name = file.replace('components-', '').replace('-docs.md', '');
|
|
16
|
-
}
|
|
17
|
-
else if (file.startsWith('foundations-')) {
|
|
18
|
-
category = 'Foundations';
|
|
19
|
-
name = file.replace('foundations-', '').replace('-docs.md', '');
|
|
20
|
-
}
|
|
21
|
-
else if (file.startsWith('resources-')) {
|
|
22
|
-
category = 'Resources';
|
|
23
|
-
name = file.replace('resources-', '').replace('-docs.md', '');
|
|
24
|
-
}
|
|
25
|
-
else if (file.includes('introduction')) {
|
|
26
|
-
category = 'Getting Started';
|
|
27
|
-
name = 'Introduction';
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
uri: `file://${path.join(DOCS_DIR, file)}`,
|
|
31
|
-
name: `${category}: ${name}`,
|
|
32
|
-
description: `IDS ${category.toLowerCase()} documentation for ${name}`,
|
|
33
|
-
mimeType: 'text/markdown',
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
|
-
return {
|
|
37
|
-
resources: categorizedResources,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
export function handleReadResource(request) {
|
|
41
|
-
const url = new URL(request.params.uri);
|
|
42
|
-
if (url.protocol !== 'file:') {
|
|
43
|
-
throw new Error(`Unsupported protocol: ${url.protocol}`);
|
|
44
|
-
}
|
|
45
|
-
const filePath = url.pathname;
|
|
46
|
-
// Ensure the file is within our docs directory
|
|
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');
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
const content = readFileContent(filePath);
|
|
53
|
-
return {
|
|
54
|
-
contents: [
|
|
55
|
-
{
|
|
56
|
-
uri: request.params.uri,
|
|
57
|
-
mimeType: 'text/markdown',
|
|
58
|
-
text: content,
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
65
|
-
throw new Error(`Failed to read file: ${errorMessage}`);
|
|
66
|
-
}
|
|
67
|
-
}
|