@ncds/ui-admin-mcp 1.0.0-alpha.10
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/README.md +113 -0
- package/bin/components.bundle.js +1 -0
- package/bin/definitions/compliance-rules.json +64 -0
- package/bin/definitions/instructions.md +164 -0
- package/bin/definitions/js-api.json +165 -0
- package/bin/definitions/rules.json +59 -0
- package/bin/definitions/token-descriptions.json +27 -0
- package/bin/definitions/tool-definitions.json +58 -0
- package/bin/server.d.ts +1 -0
- package/bin/server.js +217 -0
- package/bin/server.mjs +8 -0
- package/bin/tools/getComponentProps.d.ts +4 -0
- package/bin/tools/getComponentProps.js +20 -0
- package/bin/tools/getDesignTokens.d.ts +13 -0
- package/bin/tools/getDesignTokens.js +20 -0
- package/bin/tools/listComponents.d.ts +16 -0
- package/bin/tools/listComponents.js +24 -0
- package/bin/tools/listIcons.d.ts +22 -0
- package/bin/tools/listIcons.js +23 -0
- package/bin/tools/ping.d.ts +17 -0
- package/bin/tools/ping.js +20 -0
- package/bin/tools/renderToHtml.d.ts +23 -0
- package/bin/tools/renderToHtml.js +267 -0
- package/bin/tools/searchComponent.d.ts +4 -0
- package/bin/tools/searchComponent.js +33 -0
- package/bin/tools/searchIcon.d.ts +7 -0
- package/bin/tools/searchIcon.js +19 -0
- package/bin/tools/validateHtml.d.ts +18 -0
- package/bin/tools/validateHtml.js +85 -0
- package/bin/types.d.ts +123 -0
- package/bin/types.js +5 -0
- package/bin/utils/bemValidator.d.ts +36 -0
- package/bin/utils/bemValidator.js +198 -0
- package/bin/utils/compliance.d.ts +52 -0
- package/bin/utils/compliance.js +199 -0
- package/bin/utils/dataLoader.d.ts +35 -0
- package/bin/utils/dataLoader.js +192 -0
- package/bin/utils/domEnvironment.d.ts +9 -0
- package/bin/utils/domEnvironment.js +75 -0
- package/bin/utils/fuzzyMatch.d.ts +21 -0
- package/bin/utils/fuzzyMatch.js +110 -0
- package/bin/utils/logger.d.ts +18 -0
- package/bin/utils/logger.js +27 -0
- package/bin/utils/response.d.ts +28 -0
- package/bin/utils/response.js +39 -0
- package/bin/utils/tokenValidator.d.ts +24 -0
- package/bin/utils/tokenValidator.js +162 -0
- package/bin/version.d.ts +4 -0
- package/bin/version.js +7 -0
- package/data/_icons.json +12401 -0
- package/data/_meta.json +12 -0
- package/data/_tokens.json +661 -0
- package/data/badge-group.json +295 -0
- package/data/badge.json +246 -0
- package/data/bread-crumb.json +87 -0
- package/data/button-group.json +94 -0
- package/data/button.json +259 -0
- package/data/carousel-arrow.json +87 -0
- package/data/carousel-number-group.json +87 -0
- package/data/checkbox.json +99 -0
- package/data/combo-box.json +173 -0
- package/data/date-picker.json +123 -0
- package/data/divider.json +91 -0
- package/data/dot.json +103 -0
- package/data/dropdown.json +258 -0
- package/data/empty-state.json +227 -0
- package/data/featured-icon.json +139 -0
- package/data/file-input.json +315 -0
- package/data/horizontal-tab.json +329 -0
- package/data/image-file-input.json +339 -0
- package/data/input-base.json +299 -0
- package/data/modal.json +143 -0
- package/data/notification.json +194 -0
- package/data/number-input.json +295 -0
- package/data/pagination.json +101 -0
- package/data/password-input.json +263 -0
- package/data/progress-bar.json +109 -0
- package/data/progress-circle.json +96 -0
- package/data/radio.json +86 -0
- package/data/range-date-picker-with-buttons.json +273 -0
- package/data/range-date-picker.json +259 -0
- package/data/select-box.json +193 -0
- package/data/select.json +132 -0
- package/data/slider.json +100 -0
- package/data/spinner.json +93 -0
- package/data/switch.json +156 -0
- package/data/tag.json +159 -0
- package/data/textarea.json +96 -0
- package/data/toggle.json +102 -0
- package/data/tooltip.json +185 -0
- package/data/vertical-tab.json +314 -0
- package/package.json +61 -0
- package/templates/.mcp.json.example +8 -0
- package/templates/README.md +30 -0
package/bin/server.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
/**
|
|
7
|
+
* MCP 서버 진입점 — 모든 데이터 소유, tool 등록, transport 연결
|
|
8
|
+
*
|
|
9
|
+
* 이 파일만 Action(부수효과)을 포함한다. tool 핸들러는 모두 Calculation.
|
|
10
|
+
*/
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
14
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
15
|
+
const zod_1 = require("zod");
|
|
16
|
+
const dataLoader_js_1 = require("./utils/dataLoader.js");
|
|
17
|
+
const logger_js_1 = require("./utils/logger.js");
|
|
18
|
+
const listComponents_js_1 = require("./tools/listComponents.js");
|
|
19
|
+
const searchComponent_js_1 = require("./tools/searchComponent.js");
|
|
20
|
+
const getComponentProps_js_1 = require("./tools/getComponentProps.js");
|
|
21
|
+
const validateHtml_js_1 = require("./tools/validateHtml.js");
|
|
22
|
+
const ping_js_1 = require("./tools/ping.js");
|
|
23
|
+
const listIcons_js_1 = require("./tools/listIcons.js");
|
|
24
|
+
const searchIcon_js_1 = require("./tools/searchIcon.js");
|
|
25
|
+
const renderToHtml_js_1 = require("./tools/renderToHtml.js");
|
|
26
|
+
const response_js_1 = require("./utils/response.js");
|
|
27
|
+
const getDesignTokens_js_1 = require("./tools/getDesignTokens.js");
|
|
28
|
+
const version_js_1 = require("./version.js");
|
|
29
|
+
const domEnvironment_js_1 = require("./utils/domEnvironment.js");
|
|
30
|
+
// ── definitions/ 로딩 헬퍼 (Action) ─────────────────────────────────────────
|
|
31
|
+
/** tool-definitions.json을 1회 로딩하여 descriptions + capabilities를 분리 반환 */
|
|
32
|
+
const loadToolDefinitions = (definitionsDir) => {
|
|
33
|
+
const raw = fs_1.default.readFileSync(path_1.default.resolve(definitionsDir, 'tool-definitions.json'), 'utf-8');
|
|
34
|
+
const data = JSON.parse(raw);
|
|
35
|
+
// JSON 구조 검증 — 타입 단언만으로 신뢰하지 않음 (§ 2.5)
|
|
36
|
+
const tools = data.tools;
|
|
37
|
+
if (!tools || typeof tools !== 'object') {
|
|
38
|
+
throw new Error('tool-definitions.json에 tools 키가 없거나 올바르지 않습니다');
|
|
39
|
+
}
|
|
40
|
+
const descriptions = {};
|
|
41
|
+
for (const [name, def] of Object.entries(tools)) {
|
|
42
|
+
if (def.description)
|
|
43
|
+
descriptions[name] = def.description;
|
|
44
|
+
}
|
|
45
|
+
const capabilities = data.capabilities;
|
|
46
|
+
if (!Array.isArray(capabilities)) {
|
|
47
|
+
throw new Error('tool-definitions.json에 capabilities 배열이 없습니다');
|
|
48
|
+
}
|
|
49
|
+
return { descriptions, capabilities };
|
|
50
|
+
};
|
|
51
|
+
/** rules.json을 로딩하여 flat 배열 + pingReminder 반환 */
|
|
52
|
+
const loadRules = (definitionsDir) => {
|
|
53
|
+
const raw = fs_1.default.readFileSync(path_1.default.join(definitionsDir, 'rules.json'), 'utf-8');
|
|
54
|
+
const data = JSON.parse(raw);
|
|
55
|
+
const RULE_KEYS = [
|
|
56
|
+
'workflow',
|
|
57
|
+
'componentSelection',
|
|
58
|
+
'version',
|
|
59
|
+
'cdn',
|
|
60
|
+
'react',
|
|
61
|
+
'forbidden',
|
|
62
|
+
'customArea',
|
|
63
|
+
'compliance',
|
|
64
|
+
'category',
|
|
65
|
+
];
|
|
66
|
+
const flat = [];
|
|
67
|
+
for (const key of RULE_KEYS) {
|
|
68
|
+
const arr = data[key];
|
|
69
|
+
if (!Array.isArray(arr)) {
|
|
70
|
+
throw new Error(`rules.json에 ${key} 배열이 없습니다`);
|
|
71
|
+
}
|
|
72
|
+
flat.push(...arr);
|
|
73
|
+
}
|
|
74
|
+
const pingReminder = typeof data.pingReminder === 'string' ? data.pingReminder : '';
|
|
75
|
+
return { flat, pingReminder };
|
|
76
|
+
};
|
|
77
|
+
// ── 진입점 ───────────────────────────────────────────────────────────────────
|
|
78
|
+
const main = async () => {
|
|
79
|
+
const definitionsDir = path_1.default.resolve(__dirname, 'definitions');
|
|
80
|
+
// ── definitions/ 로딩 (main() 안에서 실행하여 catch에 포함) ──
|
|
81
|
+
const { descriptions, capabilities } = loadToolDefinitions(definitionsDir);
|
|
82
|
+
const { flat: rules, pingReminder } = loadRules(definitionsDir);
|
|
83
|
+
const instructions = (0, dataLoader_js_1.loadInstructions)(definitionsDir);
|
|
84
|
+
const complianceRules = (0, dataLoader_js_1.loadComplianceRules)(definitionsDir);
|
|
85
|
+
const jsApiMap = (0, dataLoader_js_1.loadJsApi)(definitionsDir);
|
|
86
|
+
// ── 데이터 로딩 ──
|
|
87
|
+
const componentMap = (0, dataLoader_js_1.loadComponentsFromDir)(dataLoader_js_1.DEFAULT_DATA_DIR);
|
|
88
|
+
const { cdn: cdnMeta, icon: iconMeta } = (0, dataLoader_js_1.loadMeta)(dataLoader_js_1.DEFAULT_DATA_DIR);
|
|
89
|
+
const iconData = (0, dataLoader_js_1.loadIconData)(dataLoader_js_1.DEFAULT_DATA_DIR);
|
|
90
|
+
const tokenData = (0, dataLoader_js_1.loadTokenData)(dataLoader_js_1.DEFAULT_DATA_DIR);
|
|
91
|
+
const bundlePath = path_1.default.resolve(__dirname, '..', 'bin', 'components.bundle.js');
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
93
|
+
const bundle = require(bundlePath);
|
|
94
|
+
logger_js_1.logger.info('컴포넌트 번들 로딩 완료');
|
|
95
|
+
// 아이콘 번들 로딩 — renderToHtml에서 아이콘 이름 문자열을 실제 React 컴포넌트로 resolve
|
|
96
|
+
let iconBundle = {};
|
|
97
|
+
try {
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
99
|
+
iconBundle = require('@ncds/ui-admin-icon');
|
|
100
|
+
logger_js_1.logger.info('아이콘 번들 로딩 완료');
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
logger_js_1.logger.warn('아이콘 번들 로딩 실패 — 아이콘 resolve 비활성화');
|
|
104
|
+
}
|
|
105
|
+
// ── DOM + React 런타임 초기화 (유틸로 추출 § 3.9) ──
|
|
106
|
+
const reactRuntime = (0, domEnvironment_js_1.setupDomEnvironment)();
|
|
107
|
+
logger_js_1.logger.info('DOM + React 런타임 초기화 완료');
|
|
108
|
+
// ── 파생 데이터 사전 계산 (code-guide § 5.1 반복 계산 제거) ──
|
|
109
|
+
const rootClassMap = (0, validateHtml_js_1.buildRootClassMap)(componentMap);
|
|
110
|
+
const tokenValueMap = (0, validateHtml_js_1.buildTokenValueMap)(tokenData);
|
|
111
|
+
const groupedComponents = (0, listComponents_js_1.buildGroupedComponents)(componentMap);
|
|
112
|
+
const iconSummary = (0, listIcons_js_1.buildIconSummary)(iconData);
|
|
113
|
+
const listComponentsResponse = (0, listComponents_js_1.buildListComponentsResponse)(groupedComponents);
|
|
114
|
+
const listIconsResponse = (0, listIcons_js_1.buildListIconsResponse)(iconSummary);
|
|
115
|
+
// ── MCP 서버 생성 + tool 등록 ──
|
|
116
|
+
const server = new mcp_js_1.McpServer({ name: 'ncds-ui-admin', version: version_js_1.VERSION }, { instructions });
|
|
117
|
+
// ping 호출 추적 — 미호출 시 다른 tool 응답에 핵심 rules 주입 (세션 레벨 상태, let 의도적 사용)
|
|
118
|
+
let pinged = false;
|
|
119
|
+
const withPingReminder = (response) => {
|
|
120
|
+
if (pinged || !pingReminder)
|
|
121
|
+
return response;
|
|
122
|
+
return (0, response_js_1.appendPingReminder)(response, pingReminder);
|
|
123
|
+
};
|
|
124
|
+
server.registerTool('ping', { description: descriptions['ping'] }, () => {
|
|
125
|
+
pinged = true;
|
|
126
|
+
return (0, ping_js_1.ping)({ componentMap, cdnMeta, iconMeta, version: version_js_1.VERSION, rules, capabilities });
|
|
127
|
+
});
|
|
128
|
+
server.registerTool('list_icons', { description: descriptions['list_icons'] }, () => withPingReminder((0, listIcons_js_1.listIcons)(listIconsResponse)));
|
|
129
|
+
server.registerTool('search_icon', {
|
|
130
|
+
description: descriptions['search_icon'],
|
|
131
|
+
inputSchema: { query: zod_1.z.string().describe('Search keyword (e.g. "search", "alert", "arrow")') },
|
|
132
|
+
}, ({ query }) => withPingReminder((0, searchIcon_js_1.searchIcon)(iconData, query)));
|
|
133
|
+
server.registerTool('list_components', { description: descriptions['list_components'] }, () => withPingReminder((0, listComponents_js_1.listComponents)(listComponentsResponse)));
|
|
134
|
+
server.registerTool('search_component', {
|
|
135
|
+
description: descriptions['search_component'],
|
|
136
|
+
inputSchema: { query: zod_1.z.string().describe('Search keyword (Korean/English, case-insensitive)') },
|
|
137
|
+
}, ({ query }) => withPingReminder((0, searchComponent_js_1.searchComponent)(componentMap, query)));
|
|
138
|
+
server.registerTool('get_component_props', {
|
|
139
|
+
description: descriptions['get_component_props'],
|
|
140
|
+
inputSchema: { name: zod_1.z.string().min(1).describe('Component name (e.g. "button", "password-input")') },
|
|
141
|
+
}, ({ name }) => withPingReminder((0, getComponentProps_js_1.getComponentProps)(componentMap, name)));
|
|
142
|
+
server.registerTool('validate_html', {
|
|
143
|
+
description: descriptions['validate_html'],
|
|
144
|
+
inputSchema: {
|
|
145
|
+
html: zod_1.z
|
|
146
|
+
.string()
|
|
147
|
+
.min(1)
|
|
148
|
+
.describe('HTML markup to validate (e.g. \'<button class="ncua-btn ncua-btn--primary"></button>\')'),
|
|
149
|
+
},
|
|
150
|
+
}, ({ html }) => withPingReminder((0, validateHtml_js_1.validateHtml)({ componentMap, rootClassMap, html, cdnMeta, tokenData, complianceRules, tokenValueMap })));
|
|
151
|
+
server.registerTool('render_to_html', {
|
|
152
|
+
description: descriptions['render_to_html'],
|
|
153
|
+
inputSchema: {
|
|
154
|
+
name: zod_1.z.string().min(1).describe('Component name (e.g. "button", "modal", "password-input")'),
|
|
155
|
+
props: zod_1.z
|
|
156
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
157
|
+
.optional()
|
|
158
|
+
.describe('Component props (e.g. { label: "OK", hierarchy: "primary" })'),
|
|
159
|
+
},
|
|
160
|
+
}, ({ name, props }) => withPingReminder((0, renderToHtml_js_1.renderToHtml)({
|
|
161
|
+
componentMap,
|
|
162
|
+
bundle,
|
|
163
|
+
iconBundle,
|
|
164
|
+
cdnMeta,
|
|
165
|
+
iconMeta,
|
|
166
|
+
reactRuntime,
|
|
167
|
+
jsApiMap,
|
|
168
|
+
name,
|
|
169
|
+
props: props,
|
|
170
|
+
})));
|
|
171
|
+
server.registerTool('render_to_html_batch', {
|
|
172
|
+
description: descriptions['render_to_html_batch'],
|
|
173
|
+
inputSchema: {
|
|
174
|
+
components: zod_1.z
|
|
175
|
+
.array(zod_1.z.object({
|
|
176
|
+
name: zod_1.z.string().min(1).describe('Component name'),
|
|
177
|
+
props: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional().describe('Component props'),
|
|
178
|
+
}))
|
|
179
|
+
.min(1)
|
|
180
|
+
.max(30)
|
|
181
|
+
.describe('Array of components to render (max 30)'),
|
|
182
|
+
},
|
|
183
|
+
}, ({ components }) => {
|
|
184
|
+
const results = components.map(({ name, props }) => (0, renderToHtml_js_1.renderToHtml)({
|
|
185
|
+
componentMap,
|
|
186
|
+
bundle,
|
|
187
|
+
iconBundle,
|
|
188
|
+
cdnMeta,
|
|
189
|
+
iconMeta,
|
|
190
|
+
reactRuntime,
|
|
191
|
+
jsApiMap,
|
|
192
|
+
name,
|
|
193
|
+
props: props,
|
|
194
|
+
}));
|
|
195
|
+
const parsed = results.map((r) => {
|
|
196
|
+
const text = r.content[0].text;
|
|
197
|
+
return r.isError ? { error: JSON.parse(text) } : JSON.parse(text);
|
|
198
|
+
});
|
|
199
|
+
return withPingReminder((0, response_js_1.successResponse)(parsed));
|
|
200
|
+
});
|
|
201
|
+
server.registerTool('get_design_tokens', {
|
|
202
|
+
description: descriptions['get_design_tokens'],
|
|
203
|
+
inputSchema: {
|
|
204
|
+
category: zod_1.z
|
|
205
|
+
.string()
|
|
206
|
+
.optional()
|
|
207
|
+
.describe('Token category filter (e.g. "color", "typography", "shadow", "spacing"). Omit to get all tokens.'),
|
|
208
|
+
},
|
|
209
|
+
}, ({ category }) => withPingReminder((0, getDesignTokens_js_1.getDesignTokens)({ tokenData, category })));
|
|
210
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
211
|
+
await server.connect(transport);
|
|
212
|
+
logger_js_1.logger.info(`NCUA MCP 서버 시작됨 (ncds-ui-admin v${version_js_1.VERSION})`);
|
|
213
|
+
};
|
|
214
|
+
main().catch((err) => {
|
|
215
|
+
process.stderr.write(`[ERROR] 서버 시작 실패: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
});
|
package/bin/server.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ComponentData } from '../types.js';
|
|
2
|
+
import { type McpToolResponse } from '../utils/response.js';
|
|
3
|
+
/** get_component_props tool — 컴포넌트의 props 스펙을 JSON으로 반환 */
|
|
4
|
+
export declare const getComponentProps: (componentMap: Map<string, ComponentData>, name: string) => McpToolResponse;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getComponentProps = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* get_component_props tool — 컴포넌트 props 스펙 반환 (순수 함수)
|
|
6
|
+
*/
|
|
7
|
+
const dataLoader_js_1 = require("../utils/dataLoader.js");
|
|
8
|
+
const response_js_1 = require("../utils/response.js");
|
|
9
|
+
/** get_component_props tool — 컴포넌트의 props 스펙을 JSON으로 반환 */
|
|
10
|
+
const getComponentProps = (componentMap, name) => {
|
|
11
|
+
const normalized = (0, response_js_1.normalizeName)(name);
|
|
12
|
+
const component = (0, dataLoader_js_1.getComponent)(componentMap, normalized);
|
|
13
|
+
if (!component)
|
|
14
|
+
return (0, response_js_1.componentNotFoundResponse)(normalized);
|
|
15
|
+
return (0, response_js_1.successResponse)({
|
|
16
|
+
props: component.props,
|
|
17
|
+
...(component.usageExamples && { usageExamples: component.usageExamples }),
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
exports.getComponentProps = getComponentProps;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_design_tokens tool — 디자인 토큰(CSS 변수) 조회
|
|
3
|
+
*
|
|
4
|
+
* 커스텀 영역 작성 시 에이전트가 실제 존재하는 토큰만 사용하도록
|
|
5
|
+
* 빌드타임 추출된 토큰 목록을 카테고리별로 제공한다.
|
|
6
|
+
*/
|
|
7
|
+
import type { TokenData } from '../types.js';
|
|
8
|
+
import { type McpToolResponse } from '../utils/response.js';
|
|
9
|
+
export interface GetDesignTokensParams {
|
|
10
|
+
tokenData: TokenData;
|
|
11
|
+
category?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const getDesignTokens: ({ tokenData, category }: GetDesignTokensParams) => McpToolResponse;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDesignTokens = void 0;
|
|
4
|
+
const response_js_1 = require("../utils/response.js");
|
|
5
|
+
const getDesignTokens = ({ tokenData, category }) => {
|
|
6
|
+
if (!category) {
|
|
7
|
+
return (0, response_js_1.successResponse)(tokenData);
|
|
8
|
+
}
|
|
9
|
+
if (!tokenData.categories.includes(category)) {
|
|
10
|
+
return (0, response_js_1.errorResponse)('INVALID_TOKEN_CATEGORY', `Category '${category}' not found. Available: ${tokenData.categories.join(', ')}`, 'Use get_design_tokens without category to see all available categories and tokens.');
|
|
11
|
+
}
|
|
12
|
+
const filteredGroups = tokenData.groups.filter((group) => group.category === category);
|
|
13
|
+
const filteredCount = filteredGroups.reduce((sum, group) => sum + group.tokens.length, 0);
|
|
14
|
+
return (0, response_js_1.successResponse)({
|
|
15
|
+
totalCount: filteredCount,
|
|
16
|
+
categories: [category],
|
|
17
|
+
groups: filteredGroups,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
exports.getDesignTokens = getDesignTokens;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_components tool — 사전 계산된 카테고리별 컴포넌트 목록 반환 (순수 함수)
|
|
3
|
+
*/
|
|
4
|
+
import type { ComponentData } from '../types.js';
|
|
5
|
+
import { type McpToolResponse } from '../utils/response.js';
|
|
6
|
+
/** 카테고리별 컴포넌트 그룹 타입 */
|
|
7
|
+
export type GroupedComponents = Record<string, Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
}>>;
|
|
11
|
+
/** componentMap에서 카테고리별 그룹을 사전 계산 — server.ts에서 1회 호출 */
|
|
12
|
+
export declare const buildGroupedComponents: (componentMap: Map<string, ComponentData>) => GroupedComponents;
|
|
13
|
+
/** GroupedComponents를 사전 직렬화 — server.ts에서 1회 호출 */
|
|
14
|
+
export declare const buildListComponentsResponse: (grouped: GroupedComponents) => McpToolResponse;
|
|
15
|
+
/** list_components tool — 사전 직렬화된 응답을 그대로 반환 */
|
|
16
|
+
export declare const listComponents: (prebuilt: McpToolResponse) => McpToolResponse;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listComponents = exports.buildListComponentsResponse = exports.buildGroupedComponents = void 0;
|
|
4
|
+
const response_js_1 = require("../utils/response.js");
|
|
5
|
+
/** componentMap에서 카테고리별 그룹을 사전 계산 — server.ts에서 1회 호출 */
|
|
6
|
+
const buildGroupedComponents = (componentMap) => {
|
|
7
|
+
const sorted = [...componentMap.values()]
|
|
8
|
+
.map((c) => ({ name: c.name, category: c.category, description: c.description }))
|
|
9
|
+
.sort((a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name));
|
|
10
|
+
const grouped = {};
|
|
11
|
+
for (const c of sorted) {
|
|
12
|
+
if (!grouped[c.category])
|
|
13
|
+
grouped[c.category] = [];
|
|
14
|
+
grouped[c.category].push({ name: c.name, description: c.description });
|
|
15
|
+
}
|
|
16
|
+
return grouped;
|
|
17
|
+
};
|
|
18
|
+
exports.buildGroupedComponents = buildGroupedComponents;
|
|
19
|
+
/** GroupedComponents를 사전 직렬화 — server.ts에서 1회 호출 */
|
|
20
|
+
const buildListComponentsResponse = (grouped) => (0, response_js_1.successResponse)(grouped);
|
|
21
|
+
exports.buildListComponentsResponse = buildListComponentsResponse;
|
|
22
|
+
/** list_components tool — 사전 직렬화된 응답을 그대로 반환 */
|
|
23
|
+
const listComponents = (prebuilt) => prebuilt;
|
|
24
|
+
exports.listComponents = listComponents;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_icons tool — 사전 계산된 아이콘 요약 반환 (순수 함수)
|
|
3
|
+
*
|
|
4
|
+
* 아이콘 이름을 전부 반환하면 토큰 낭비이므로,
|
|
5
|
+
* 요약 정보만 반환하고 search_icon으로 검색을 유도한다.
|
|
6
|
+
*/
|
|
7
|
+
import type { IconData } from '../types.js';
|
|
8
|
+
import { type McpToolResponse } from '../utils/response.js';
|
|
9
|
+
/** 아이콘 요약 데이터 타입 */
|
|
10
|
+
export interface IconSummary {
|
|
11
|
+
totalCount: number;
|
|
12
|
+
fillCount: number;
|
|
13
|
+
uniqueIcons: number;
|
|
14
|
+
hint: string;
|
|
15
|
+
sample: string[];
|
|
16
|
+
}
|
|
17
|
+
/** iconData에서 요약을 사전 계산 — server.ts에서 1회 호출 */
|
|
18
|
+
export declare const buildIconSummary: (iconData: IconData) => IconSummary;
|
|
19
|
+
/** IconSummary를 사전 직렬화 — server.ts에서 1회 호출 */
|
|
20
|
+
export declare const buildListIconsResponse: (summary: IconSummary) => McpToolResponse;
|
|
21
|
+
/** list_icons tool — 사전 직렬화된 응답을 그대로 반환 */
|
|
22
|
+
export declare const listIcons: (prebuilt: McpToolResponse) => McpToolResponse;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listIcons = exports.buildListIconsResponse = exports.buildIconSummary = void 0;
|
|
4
|
+
const response_js_1 = require("../utils/response.js");
|
|
5
|
+
const ICON_SAMPLE_SIZE = 20;
|
|
6
|
+
/** iconData에서 요약을 사전 계산 — server.ts에서 1회 호출 */
|
|
7
|
+
const buildIconSummary = (iconData) => {
|
|
8
|
+
const prefixes = new Set(iconData.icons.map((i) => i.name.replace(/Fill$/, '')));
|
|
9
|
+
return {
|
|
10
|
+
totalCount: iconData.totalCount,
|
|
11
|
+
fillCount: iconData.fillCount,
|
|
12
|
+
uniqueIcons: prefixes.size,
|
|
13
|
+
hint: '아이콘이 많으므로 search_icon tool로 키워드 검색을 권장합니다. 예: search_icon("arrow"), search_icon("check")',
|
|
14
|
+
sample: iconData.icons.slice(0, ICON_SAMPLE_SIZE).map((i) => i.name),
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
exports.buildIconSummary = buildIconSummary;
|
|
18
|
+
/** IconSummary를 사전 직렬화 — server.ts에서 1회 호출 */
|
|
19
|
+
const buildListIconsResponse = (summary) => (0, response_js_1.successResponse)(summary);
|
|
20
|
+
exports.buildListIconsResponse = buildListIconsResponse;
|
|
21
|
+
/** list_icons tool — 사전 직렬화된 응답을 그대로 반환 */
|
|
22
|
+
const listIcons = (prebuilt) => prebuilt;
|
|
23
|
+
exports.listIcons = listIcons;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ping tool — NCUA MCP 서버 health check + capabilities/rules 제공 (순수 함수)
|
|
3
|
+
*/
|
|
4
|
+
import type { ComponentData, Capability } from '../types.js';
|
|
5
|
+
import type { CdnMeta, IconMeta } from '../utils/dataLoader.js';
|
|
6
|
+
import { type McpToolResponse } from '../utils/response.js';
|
|
7
|
+
/** ping tool 파라미터 — server.ts에서 모든 데이터를 소유하고 전달한다 */
|
|
8
|
+
export interface PingParams {
|
|
9
|
+
componentMap: Map<string, ComponentData>;
|
|
10
|
+
cdnMeta: CdnMeta | null;
|
|
11
|
+
iconMeta: IconMeta | null;
|
|
12
|
+
version: string;
|
|
13
|
+
rules: string[];
|
|
14
|
+
capabilities: Capability[];
|
|
15
|
+
}
|
|
16
|
+
/** ping tool — 서버 상태, capabilities, rules를 반환 */
|
|
17
|
+
export declare const ping: (params: PingParams) => McpToolResponse;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ping = void 0;
|
|
4
|
+
const response_js_1 = require("../utils/response.js");
|
|
5
|
+
/** ping tool — 서버 상태, capabilities, rules를 반환 */
|
|
6
|
+
const ping = (params) => {
|
|
7
|
+
const { componentMap, cdnMeta, iconMeta, version, rules, capabilities } = params;
|
|
8
|
+
return (0, response_js_1.successResponse)({
|
|
9
|
+
status: 'ok',
|
|
10
|
+
name: 'ncds-ui-admin',
|
|
11
|
+
description: 'NCDS UI Admin component library',
|
|
12
|
+
version,
|
|
13
|
+
componentCount: componentMap.size,
|
|
14
|
+
cdn: cdnMeta ?? undefined,
|
|
15
|
+
icon: iconMeta ?? undefined,
|
|
16
|
+
capabilities,
|
|
17
|
+
rules,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
exports.ping = ping;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* render_to_html tool — 컴포넌트 속성을 전달하면 정확한 HTML + React 매핑을 반환 (순수 함수)
|
|
3
|
+
*
|
|
4
|
+
* DOM 환경과 React/ReactDOM은 server.ts에서 초기화하고 파라미터로 전달한다.
|
|
5
|
+
* 이 파일에는 fs, path, require, let이 없다.
|
|
6
|
+
*/
|
|
7
|
+
import type { ComponentData, ReactRuntime, JsApiInfo } from '../types.js';
|
|
8
|
+
import type { CdnMeta, IconMeta } from '../utils/dataLoader.js';
|
|
9
|
+
import { type McpToolResponse } from '../utils/response.js';
|
|
10
|
+
/** render_to_html tool 파라미터 */
|
|
11
|
+
export interface RenderToHtmlParams {
|
|
12
|
+
componentMap: Map<string, ComponentData>;
|
|
13
|
+
bundle: Record<string, unknown>;
|
|
14
|
+
iconBundle: Record<string, unknown>;
|
|
15
|
+
cdnMeta: CdnMeta | null;
|
|
16
|
+
iconMeta: IconMeta | null;
|
|
17
|
+
reactRuntime: ReactRuntime;
|
|
18
|
+
jsApiMap: Map<string, JsApiInfo>;
|
|
19
|
+
name: string;
|
|
20
|
+
props?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/** render_to_html tool — props로 React 컴포넌트를 렌더링하여 HTML + React 매핑 반환 */
|
|
23
|
+
export declare const renderToHtml: (params: RenderToHtmlParams) => McpToolResponse;
|