@sky.ui/mcp 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.
- package/LICENSE.md +139 -0
- package/README.md +182 -0
- package/data/chart-api-sections.json +4185 -0
- package/data/component-tier.json +25 -0
- package/data/design-guidelines/p0-guidelines.json +13381 -0
- package/data/reactivity-readme-snapshot.json +1 -0
- package/data/theme-authoring-contract.json +598 -0
- package/data/utils-suggestion-snapshot.json +1 -0
- package/dist/cache.d.ts +3 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +15 -0
- package/dist/cache.js.map +1 -0
- package/dist/catalog.d.ts +60 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +343 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cem.d.ts +26 -0
- package/dist/cem.d.ts.map +1 -0
- package/dist/cem.js +348 -0
- package/dist/cem.js.map +1 -0
- package/dist/chart-usage-tool.d.ts +20 -0
- package/dist/chart-usage-tool.d.ts.map +1 -0
- package/dist/chart-usage-tool.js +153 -0
- package/dist/chart-usage-tool.js.map +1 -0
- package/dist/component-docs-tool.d.ts +45 -0
- package/dist/component-docs-tool.d.ts.map +1 -0
- package/dist/component-docs-tool.js +217 -0
- package/dist/component-docs-tool.js.map +1 -0
- package/dist/component-method-filter.d.ts +3 -0
- package/dist/component-method-filter.d.ts.map +1 -0
- package/dist/component-method-filter.js +32 -0
- package/dist/component-method-filter.js.map +1 -0
- package/dist/component-tier.d.ts +20 -0
- package/dist/component-tier.d.ts.map +1 -0
- package/dist/component-tier.js +59 -0
- package/dist/component-tier.js.map +1 -0
- package/dist/component-usage-tool.d.ts +20 -0
- package/dist/component-usage-tool.d.ts.map +1 -0
- package/dist/component-usage-tool.js +90 -0
- package/dist/component-usage-tool.js.map +1 -0
- package/dist/design-guidelines/a11y-engine.d.ts +22 -0
- package/dist/design-guidelines/a11y-engine.d.ts.map +1 -0
- package/dist/design-guidelines/a11y-engine.js +78 -0
- package/dist/design-guidelines/a11y-engine.js.map +1 -0
- package/dist/design-guidelines/compatibility-engine.d.ts +20 -0
- package/dist/design-guidelines/compatibility-engine.d.ts.map +1 -0
- package/dist/design-guidelines/compatibility-engine.js +57 -0
- package/dist/design-guidelines/compatibility-engine.js.map +1 -0
- package/dist/design-guidelines/component-guideline-engine.d.ts +19 -0
- package/dist/design-guidelines/component-guideline-engine.d.ts.map +1 -0
- package/dist/design-guidelines/component-guideline-engine.js +40 -0
- package/dist/design-guidelines/component-guideline-engine.js.map +1 -0
- package/dist/design-guidelines/composition-engine.d.ts +10 -0
- package/dist/design-guidelines/composition-engine.d.ts.map +1 -0
- package/dist/design-guidelines/composition-engine.js +29 -0
- package/dist/design-guidelines/composition-engine.js.map +1 -0
- package/dist/design-guidelines/pattern-engine.d.ts +20 -0
- package/dist/design-guidelines/pattern-engine.d.ts.map +1 -0
- package/dist/design-guidelines/pattern-engine.js +58 -0
- package/dist/design-guidelines/pattern-engine.js.map +1 -0
- package/dist/design-guidelines/recommendation-engine.d.ts +11 -0
- package/dist/design-guidelines/recommendation-engine.d.ts.map +1 -0
- package/dist/design-guidelines/recommendation-engine.js +88 -0
- package/dist/design-guidelines/recommendation-engine.js.map +1 -0
- package/dist/design-guidelines/repository.d.ts +19 -0
- package/dist/design-guidelines/repository.d.ts.map +1 -0
- package/dist/design-guidelines/repository.js +71 -0
- package/dist/design-guidelines/repository.js.map +1 -0
- package/dist/design-guidelines/review-engine.d.ts +20 -0
- package/dist/design-guidelines/review-engine.d.ts.map +1 -0
- package/dist/design-guidelines/review-engine.js +179 -0
- package/dist/design-guidelines/review-engine.js.map +1 -0
- package/dist/design-guidelines/schema.d.ts +256 -0
- package/dist/design-guidelines/schema.d.ts.map +1 -0
- package/dist/design-guidelines/schema.js +124 -0
- package/dist/design-guidelines/schema.js.map +1 -0
- package/dist/design-guidelines/token-engine.d.ts +23 -0
- package/dist/design-guidelines/token-engine.d.ts.map +1 -0
- package/dist/design-guidelines/token-engine.js +119 -0
- package/dist/design-guidelines/token-engine.js.map +1 -0
- package/dist/docs-read.d.ts +28 -0
- package/dist/docs-read.d.ts.map +1 -0
- package/dist/docs-read.js +102 -0
- package/dist/docs-read.js.map +1 -0
- package/dist/docs.d.ts +73 -0
- package/dist/docs.d.ts.map +1 -0
- package/dist/docs.js +323 -0
- package/dist/docs.js.map +1 -0
- package/dist/example-site-doc-enrichment.d.ts +27 -0
- package/dist/example-site-doc-enrichment.d.ts.map +1 -0
- package/dist/example-site-doc-enrichment.js +171 -0
- package/dist/example-site-doc-enrichment.js.map +1 -0
- package/dist/example-site-fetch.d.ts +44 -0
- package/dist/example-site-fetch.d.ts.map +1 -0
- package/dist/example-site-fetch.js +255 -0
- package/dist/example-site-fetch.js.map +1 -0
- package/dist/framework-wrappers.d.ts +46 -0
- package/dist/framework-wrappers.d.ts.map +1 -0
- package/dist/framework-wrappers.js +131 -0
- package/dist/framework-wrappers.js.map +1 -0
- package/dist/mcp-response-truth.d.ts +18 -0
- package/dist/mcp-response-truth.d.ts.map +1 -0
- package/dist/mcp-response-truth.js +45 -0
- package/dist/mcp-response-truth.js.map +1 -0
- package/dist/mcp-runtime-status.d.ts +37 -0
- package/dist/mcp-runtime-status.d.ts.map +1 -0
- package/dist/mcp-runtime-status.js +96 -0
- package/dist/mcp-runtime-status.js.map +1 -0
- package/dist/mcp-stdio-entry.d.ts +3 -0
- package/dist/mcp-stdio-entry.d.ts.map +1 -0
- package/dist/mcp-stdio-entry.js +35 -0
- package/dist/mcp-stdio-entry.js.map +1 -0
- package/dist/mcp-tool-errors.d.ts +35 -0
- package/dist/mcp-tool-errors.d.ts.map +1 -0
- package/dist/mcp-tool-errors.js +42 -0
- package/dist/mcp-tool-errors.js.map +1 -0
- package/dist/parse-component-ast.d.ts +112 -0
- package/dist/parse-component-ast.d.ts.map +1 -0
- package/dist/parse-component-ast.js +695 -0
- package/dist/parse-component-ast.js.map +1 -0
- package/dist/post-endpoint-server.d.ts +19 -0
- package/dist/post-endpoint-server.d.ts.map +1 -0
- package/dist/post-endpoint-server.js +777 -0
- package/dist/post-endpoint-server.js.map +1 -0
- package/dist/reactivity-info.d.ts +22 -0
- package/dist/reactivity-info.d.ts.map +1 -0
- package/dist/reactivity-info.js +99 -0
- package/dist/reactivity-info.js.map +1 -0
- package/dist/reactivity-layer-tool.d.ts +18 -0
- package/dist/reactivity-layer-tool.d.ts.map +1 -0
- package/dist/reactivity-layer-tool.js +58 -0
- package/dist/reactivity-layer-tool.js.map +1 -0
- package/dist/reactivity-readme-topics.d.ts +46 -0
- package/dist/reactivity-readme-topics.d.ts.map +1 -0
- package/dist/reactivity-readme-topics.js +206 -0
- package/dist/reactivity-readme-topics.js.map +1 -0
- package/dist/read-only-tool-allowlist.d.ts +7 -0
- package/dist/read-only-tool-allowlist.d.ts.map +1 -0
- package/dist/read-only-tool-allowlist.js +17 -0
- package/dist/read-only-tool-allowlist.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +786 -0
- package/dist/server.js.map +1 -0
- package/dist/source-read.d.ts +31 -0
- package/dist/source-read.d.ts.map +1 -0
- package/dist/source-read.js +213 -0
- package/dist/source-read.js.map +1 -0
- package/dist/theme-authoring/contract-schema.d.ts +191 -0
- package/dist/theme-authoring/contract-schema.d.ts.map +1 -0
- package/dist/theme-authoring/contract-schema.js +49 -0
- package/dist/theme-authoring/contract-schema.js.map +1 -0
- package/dist/theme-authoring/repository.d.ts +18 -0
- package/dist/theme-authoring/repository.d.ts.map +1 -0
- package/dist/theme-authoring/repository.js +55 -0
- package/dist/theme-authoring/repository.js.map +1 -0
- package/dist/theme-tool.d.ts +26 -0
- package/dist/theme-tool.d.ts.map +1 -0
- package/dist/theme-tool.js +312 -0
- package/dist/theme-tool.js.map +1 -0
- package/dist/utils-guide-topics.d.ts +39 -0
- package/dist/utils-guide-topics.d.ts.map +1 -0
- package/dist/utils-guide-topics.js +202 -0
- package/dist/utils-guide-topics.js.map +1 -0
- package/dist/utils-info.d.ts +75 -0
- package/dist/utils-info.d.ts.map +1 -0
- package/dist/utils-info.js +219 -0
- package/dist/utils-info.js.map +1 -0
- package/dist/utils-suggestion-grounding.d.ts +59 -0
- package/dist/utils-suggestion-grounding.d.ts.map +1 -0
- package/dist/utils-suggestion-grounding.js +267 -0
- package/dist/utils-suggestion-grounding.js.map +1 -0
- package/docs/agent-recipe-example-site.md +91 -0
- package/docs/ai-design-mcp-blueprint.md +75 -0
- package/docs/cross-model-mcp-playbook.md +127 -0
- package/docs/example-site-and-mcp-training.md +82 -0
- package/docs/mcp-capability-status.md +51 -0
- package/docs/mcp-tooling-roadmap.md +36 -0
- package/docs/sky-chart-option-api.md +47 -0
- package/docs/starter-prompt.md +17 -0
- package/docs/theme-config-guide.md +178 -0
- package/docs/utils-usage-guide.md +110 -0
- package/docs/vue-wrapper-v-model.md +36 -0
- package/package.json +63 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import * as z from 'zod/v4';
|
|
5
|
+
import { getMainPackageVersion, loadSkyComponentsCached, normalizeComponentKey, resolveComponentEntry, resolveMainPackageRoot } from './catalog.js';
|
|
6
|
+
import { proInstallLine } from './component-tier.js';
|
|
7
|
+
import { isCemManifestPresent, readCustomElementsManifestText } from './cem.js';
|
|
8
|
+
import { getDocsPage, listDocsPaths } from './docs-read.js';
|
|
9
|
+
import { handleGetChartUsage } from './chart-usage-tool.js';
|
|
10
|
+
import { handleGetComponentUsage } from './component-usage-tool.js';
|
|
11
|
+
import { handleGetSkyComponentDocs } from './component-docs-tool.js';
|
|
12
|
+
import { handleGetReactivityLayer } from './reactivity-layer-tool.js';
|
|
13
|
+
import { handleGetTheme } from './theme-tool.js';
|
|
14
|
+
import { searchComponentsByApiBatch, searchSkyComponents } from './docs.js';
|
|
15
|
+
import { McpErrorCode, mcpErrorJson, mcpToolErr } from './mcp-tool-errors.js';
|
|
16
|
+
import { withSkyUiMcpMeta } from './mcp-response-truth.js';
|
|
17
|
+
import { checkUtilityClass, getUtilityVariantPrefixes, searchUtilityClasses, utilityEngineSource } from './utils-suggestion-grounding.js';
|
|
18
|
+
import { realpathSync } from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
const instructions = 'Sky UI MCP helps users build with Sky UI — not inspect internal implementation. Free: @sky.ui/core|vue|react. Pro: @sky.ui.pro/core|vue|react (install @sky.ui.pro/vue or @sky.ui.pro/react — free deps install automatically). Use get_project_guide (kind installation|setup) for install and bundler setup. Use sky_components (operation list|search|search_by_api) for discovery. get_sky_component_docs for component API. get_component_usage for lit/react/vue snippets. get_reactivity_layer for @sky.ui/reactivity. get_chart_usage for sky-chart (pro). get_theme (operation guide|fields|field|variables) to build userTheme on sky-theme-provider — start with guide. get_docs for allowlisted guides. utility_classes for @sky.ui/utils class names. Prefer utility classes for layout unless the user asks otherwise. Responses include _skyUiMcp.truthLayer; follow agentMust. Read-only.';
|
|
22
|
+
/** Optional flags: MCP clients often send JSON `null` for omitted fields; Zod `.optional()` rejects `null`. */
|
|
23
|
+
const optionalBooleanArg = () => z.boolean().nullish();
|
|
24
|
+
export function assertCoreDependencyAvailable() {
|
|
25
|
+
const mainRoot = resolveMainPackageRoot();
|
|
26
|
+
if (mainRoot)
|
|
27
|
+
return;
|
|
28
|
+
throw new Error([
|
|
29
|
+
'Missing required dependency: @sky.ui/core',
|
|
30
|
+
'Install it alongside @sky.ui/mcp before starting the server.',
|
|
31
|
+
'Example:',
|
|
32
|
+
' npm install @sky.ui/mcp @sky.ui/core'
|
|
33
|
+
].join('\n'));
|
|
34
|
+
}
|
|
35
|
+
function compact(input) {
|
|
36
|
+
return input.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
37
|
+
}
|
|
38
|
+
function parseFramework(input) {
|
|
39
|
+
if (!input)
|
|
40
|
+
return 'core';
|
|
41
|
+
const v = compact(input);
|
|
42
|
+
if (['core', 'webcomponent', 'webcomponents', 'vanilla', 'wc'].includes(v))
|
|
43
|
+
return 'core';
|
|
44
|
+
if (['lit', 'litelement'].includes(v))
|
|
45
|
+
return 'lit';
|
|
46
|
+
if (['react', 'reactjs', 'jsx'].includes(v))
|
|
47
|
+
return 'react';
|
|
48
|
+
if (['vue', 'vue3', 'sfc'].includes(v))
|
|
49
|
+
return 'vue';
|
|
50
|
+
if (['reactivity', 'reactive', 'signals', 'reactiveutils'].includes(v))
|
|
51
|
+
return 'reactivity';
|
|
52
|
+
if (v.startsWith('reactiv'))
|
|
53
|
+
return 'reactivity';
|
|
54
|
+
if (v.startsWith('rea'))
|
|
55
|
+
return 'react';
|
|
56
|
+
if (v.startsWith('vu'))
|
|
57
|
+
return 'vue';
|
|
58
|
+
if (v.startsWith('li'))
|
|
59
|
+
return 'lit';
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
function parseBundler(input) {
|
|
63
|
+
if (!input)
|
|
64
|
+
return null;
|
|
65
|
+
const v = compact(input);
|
|
66
|
+
if (['vite', 'vit'].includes(v))
|
|
67
|
+
return 'vite';
|
|
68
|
+
if (['webpack', 'webpak', 'wp'].includes(v))
|
|
69
|
+
return 'webpack';
|
|
70
|
+
if (['rollup', 'roll'].includes(v))
|
|
71
|
+
return 'rollup';
|
|
72
|
+
if (['rolldown', 'rdown', 'rdown'].includes(v))
|
|
73
|
+
return 'rolldown';
|
|
74
|
+
if (['parcel', 'prcl'].includes(v))
|
|
75
|
+
return 'parcel';
|
|
76
|
+
if (v.startsWith('web'))
|
|
77
|
+
return 'webpack';
|
|
78
|
+
if (v.startsWith('rolld'))
|
|
79
|
+
return 'rolldown';
|
|
80
|
+
if (v.startsWith('roll'))
|
|
81
|
+
return 'rollup';
|
|
82
|
+
if (v.startsWith('par'))
|
|
83
|
+
return 'parcel';
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function installationGuide(framework) {
|
|
87
|
+
const lines = [];
|
|
88
|
+
lines.push('Sky UI installation guide');
|
|
89
|
+
lines.push('');
|
|
90
|
+
lines.push('1) Install dependencies from monorepo root:');
|
|
91
|
+
lines.push(' npm install');
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push('2) Build needed packages:');
|
|
94
|
+
lines.push(' npm run build:main');
|
|
95
|
+
if (framework === 'react')
|
|
96
|
+
lines.push(' npm run build:react');
|
|
97
|
+
if (framework === 'vue')
|
|
98
|
+
lines.push(' npm run build:vue');
|
|
99
|
+
if (framework === 'reactivity')
|
|
100
|
+
lines.push(' npm run build:reactivity');
|
|
101
|
+
lines.push('');
|
|
102
|
+
if (framework === 'reactivity') {
|
|
103
|
+
lines.push('3) Add @sky.ui/reactivity to apps that need the lightweight reactive runtime:');
|
|
104
|
+
lines.push(' npm install @sky.ui/reactivity');
|
|
105
|
+
lines.push(' (In this monorepo, workspace linking already exposes it after npm install.)');
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('4) Import primitives:');
|
|
108
|
+
lines.push(" import { reactive, ref, computed, watch, effect } from '@sky.ui/reactivity';");
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push('5) API surface: get_reactivity_layer (operation list_topics then get_topic) or get_docs packages/reactivity/README.md.');
|
|
111
|
+
lines.push('');
|
|
112
|
+
lines.push('Tip: get_project_guide with kind setup and framework reactivity (any bundler) for generic ESM/bundler notes.');
|
|
113
|
+
return lines.join('\n');
|
|
114
|
+
}
|
|
115
|
+
if (framework === 'core' || framework === 'lit') {
|
|
116
|
+
lines.push('3) Use component side-effect imports:');
|
|
117
|
+
lines.push(" import '@sky.ui/core/sky-button';");
|
|
118
|
+
lines.push('');
|
|
119
|
+
lines.push('4) Render custom element tags directly (Lit/vanilla):');
|
|
120
|
+
lines.push(' <sky-button>Click</sky-button>');
|
|
121
|
+
}
|
|
122
|
+
else if (framework === 'react') {
|
|
123
|
+
lines.push('3) Use React wrapper imports:');
|
|
124
|
+
lines.push(" import { SkyButton } from '@sky.ui/react/sky-button';");
|
|
125
|
+
lines.push('');
|
|
126
|
+
lines.push('4) Render wrapper component:');
|
|
127
|
+
lines.push(' <SkyButton>Click</SkyButton>');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
lines.push('3) Use Vue wrapper imports:');
|
|
131
|
+
lines.push(" import { SkyButton } from '@sky.ui/vue/sky-button';");
|
|
132
|
+
lines.push('');
|
|
133
|
+
lines.push('4) Register/consume in Vue component templates.');
|
|
134
|
+
}
|
|
135
|
+
lines.push('');
|
|
136
|
+
lines.push('Pro components (@sky.ui.pro/*): install one wrapper — free packages are npm dependencies.');
|
|
137
|
+
lines.push(` ${proInstallLine(framework === 'react' ? 'react' : framework === 'vue' ? 'vue' : 'main')}`);
|
|
138
|
+
lines.push(' Pro imports: @sky.ui.pro/core/<tag>, @sky.ui.pro/vue/<tag>, @sky.ui.pro/react/<tag>');
|
|
139
|
+
lines.push('');
|
|
140
|
+
lines.push('Tip: run get_project_guide with kind setup for bundler-specific plugin setup.');
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
function setupGuide(framework, bundler) {
|
|
144
|
+
if (framework === 'reactivity') {
|
|
145
|
+
return [
|
|
146
|
+
'Sky UI setup guide (@sky.ui/reactivity)',
|
|
147
|
+
'',
|
|
148
|
+
'No Sky UI-specific Vite/Webpack/Rollup plugin is required for @sky.ui/reactivity.',
|
|
149
|
+
'It is a small ESM package: configure your bundler like any other dependency (resolve package.json `exports`).',
|
|
150
|
+
'',
|
|
151
|
+
'Monorepo: from the repo root run `npm install` and `npm run build:reactivity` before consuming it from test apps.',
|
|
152
|
+
'',
|
|
153
|
+
'Use get_reactivity_layer (operation list_topics then get_topic) or get_docs with packages/reactivity/README.md for the full guide.'
|
|
154
|
+
].join('\n');
|
|
155
|
+
}
|
|
156
|
+
const lines = [];
|
|
157
|
+
lines.push(`Sky UI setup guide (${framework} + ${bundler})`);
|
|
158
|
+
lines.push('');
|
|
159
|
+
if (bundler === 'vite') {
|
|
160
|
+
if (framework === 'react') {
|
|
161
|
+
lines.push("Use `SkyUIReactVitePlugin` from `@sky.ui/react/vite` in `vite.config`.");
|
|
162
|
+
lines.push('Then use React wrappers in JSX.');
|
|
163
|
+
}
|
|
164
|
+
else if (framework === 'vue') {
|
|
165
|
+
lines.push("Use `SkyUIVueVitePlugin` from `@sky.ui/vue/vite` in `vite.config`.");
|
|
166
|
+
lines.push('Then use Vue wrappers in SFC templates.');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
lines.push("Use `SkyUIMainVitePlugin({ mode: 'auto-import' })` from `@sky.ui/core/vite`.");
|
|
170
|
+
lines.push('Then use `<sky-*>` tags in HTML/Lit templates.');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (bundler === 'webpack') {
|
|
174
|
+
if (framework === 'react') {
|
|
175
|
+
lines.push("Use `SkyUIReactWebpackPlugin()` from `@sky.ui/react/webpack`.");
|
|
176
|
+
lines.push('Add wrapper imports in app code.');
|
|
177
|
+
}
|
|
178
|
+
else if (framework === 'vue') {
|
|
179
|
+
lines.push("Use `SkyUIVueWebpackPlugin()` from `@sky.ui/vue/webpack`.");
|
|
180
|
+
lines.push('Use Vue component resolver plugin for auto imports if desired.');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
lines.push("Use `SkyUIMainWebpackPlugin()` from `@sky.ui/core/webpack`.");
|
|
184
|
+
lines.push("Add `@sky.ui/core/auto-import-loader` in webpack config for auto imports.");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else if (bundler === 'rollup' || bundler === 'rolldown') {
|
|
188
|
+
if (framework === 'react') {
|
|
189
|
+
lines.push("Use `SkyUIReactRollupPlugin()` from `@sky.ui/react/rollup`.");
|
|
190
|
+
}
|
|
191
|
+
else if (framework === 'vue') {
|
|
192
|
+
lines.push("Use `SkyUIVueRollupPlugin()` from `@sky.ui/vue/rollup`.");
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
lines.push("Use `SkyUIMainRollupPlugin({ mode: 'auto-import', entryHtml: 'index.html' })` from `@sky.ui/core/rollup`.");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
lines.push('Parcel generally works with manual imports.');
|
|
200
|
+
if (framework === 'core' || framework === 'lit') {
|
|
201
|
+
lines.push("Import core components explicitly, e.g. `import '@sky.ui/core/sky-button';`");
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
lines.push(`Import wrapper component modules from @sky.ui/${framework}.`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push('Tip: inspect `test/` apps in this repo for working reference configs.');
|
|
209
|
+
return lines.join('\n');
|
|
210
|
+
}
|
|
211
|
+
export function createSkyUiMcpServer() {
|
|
212
|
+
const server = new McpServer({ name: 'sky-ui', version: '1.0.0' }, { instructions });
|
|
213
|
+
server.registerTool('get_project_guide', {
|
|
214
|
+
title: 'Installation or bundler setup guide',
|
|
215
|
+
description: 'kind=installation: Sky UI install steps for core/lit/react/vue/reactivity. kind=setup: bundler-specific setup (vite/webpack/rollup/rolldown/parcel); bundler is ignored when framework resolves to reactivity.',
|
|
216
|
+
inputSchema: z.discriminatedUnion('kind', [
|
|
217
|
+
z.object({
|
|
218
|
+
kind: z.literal('installation'),
|
|
219
|
+
framework: z
|
|
220
|
+
.string()
|
|
221
|
+
.optional()
|
|
222
|
+
.describe('Target framework (aliases: core/vanilla/webcomponents, lit, react, vue, reactivity/reactive/signals)')
|
|
223
|
+
}),
|
|
224
|
+
z.object({
|
|
225
|
+
kind: z.literal('setup'),
|
|
226
|
+
framework: z
|
|
227
|
+
.string()
|
|
228
|
+
.optional()
|
|
229
|
+
.describe('Target framework (aliases accepted, default: core). Use reactivity for @sky.ui/reactivity.'),
|
|
230
|
+
bundler: z
|
|
231
|
+
.string()
|
|
232
|
+
.optional()
|
|
233
|
+
.describe('Bundler/runtime (vite/webpack/rollup/rolldown/parcel; aliases). Required when framework is not reactivity.')
|
|
234
|
+
})
|
|
235
|
+
])
|
|
236
|
+
}, async (input) => {
|
|
237
|
+
if (input.kind === 'installation') {
|
|
238
|
+
const fw = parseFramework(input.framework);
|
|
239
|
+
if (!fw) {
|
|
240
|
+
return mcpToolErr(McpErrorCode.INSTALL_GUIDE_INVALID_FRAMEWORK, `Unknown framework: ${input.framework}`, {
|
|
241
|
+
supported: ['core', 'lit', 'react', 'vue', 'reactivity']
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const text = installationGuide(fw);
|
|
245
|
+
return { content: [{ type: 'text', text }] };
|
|
246
|
+
}
|
|
247
|
+
const fw = parseFramework(input.framework);
|
|
248
|
+
if (fw === 'reactivity') {
|
|
249
|
+
const text = setupGuide('reactivity', 'vite');
|
|
250
|
+
return { content: [{ type: 'text', text }] };
|
|
251
|
+
}
|
|
252
|
+
const b = parseBundler(input.bundler);
|
|
253
|
+
if (!fw || !b) {
|
|
254
|
+
return mcpToolErr(McpErrorCode.SETUP_GUIDE_INVALID_INPUT, 'Unknown framework or bundler input', {
|
|
255
|
+
input: { framework: input.framework, bundler: input.bundler },
|
|
256
|
+
supported: {
|
|
257
|
+
framework: ['core', 'lit', 'react', 'vue', 'reactivity'],
|
|
258
|
+
bundler: ['vite', 'webpack', 'rollup', 'rolldown', 'parcel']
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
const text = setupGuide(fw, b);
|
|
263
|
+
return { content: [{ type: 'text', text }] };
|
|
264
|
+
});
|
|
265
|
+
server.registerTool('sky_components', {
|
|
266
|
+
title: 'Sky UI component discovery',
|
|
267
|
+
description: 'operation=list: paginated catalog. operation=search: keyword search on names + summaries. operation=search_by_api: one or more API keywords (props/events/slots/methods).',
|
|
268
|
+
inputSchema: z.discriminatedUnion('operation', [
|
|
269
|
+
z.object({
|
|
270
|
+
operation: z.literal('list'),
|
|
271
|
+
offset: z.number().int().min(0).optional().describe('0-based index (default 0)'),
|
|
272
|
+
limit: z.number().int().min(1).max(500).optional().describe('Page size (default 100)')
|
|
273
|
+
}),
|
|
274
|
+
z.object({
|
|
275
|
+
operation: z.literal('search'),
|
|
276
|
+
query: z.string().describe('Space-separated keywords, e.g. "table pivot"'),
|
|
277
|
+
limit: z.number().int().min(1).max(50).optional().describe('Max hits (default 20)')
|
|
278
|
+
}),
|
|
279
|
+
z.object({
|
|
280
|
+
operation: z.literal('search_by_api'),
|
|
281
|
+
queries: z.array(z.string()).min(1).max(20).describe('API keywords, e.g. ["disabled","loading"]'),
|
|
282
|
+
limit_per_query: z.number().int().min(1).max(50).optional().describe('Max hits per query (default 10)')
|
|
283
|
+
})
|
|
284
|
+
])
|
|
285
|
+
}, async (input) => {
|
|
286
|
+
if (input.operation === 'list') {
|
|
287
|
+
const loaded = loadSkyComponentsCached();
|
|
288
|
+
if (!loaded.ok) {
|
|
289
|
+
return mcpToolErr(McpErrorCode.COMPONENT_CATALOG_FAILED, loaded.error);
|
|
290
|
+
}
|
|
291
|
+
const off = input.offset ?? 0;
|
|
292
|
+
const lim = input.limit ?? 100;
|
|
293
|
+
const total = loaded.components.length;
|
|
294
|
+
const slice = loaded.components.slice(off, off + lim);
|
|
295
|
+
const body = {
|
|
296
|
+
source: loaded.path,
|
|
297
|
+
total,
|
|
298
|
+
offset: off,
|
|
299
|
+
limit: lim,
|
|
300
|
+
returned: slice.length,
|
|
301
|
+
nextOffset: off + slice.length < total ? off + slice.length : null,
|
|
302
|
+
mainVersion: getMainPackageVersion(),
|
|
303
|
+
customElementsManifest: isCemManifestPresent()
|
|
304
|
+
? 'packages/main/dist/custom-elements.json (run npm run build:main after clone)'
|
|
305
|
+
: null,
|
|
306
|
+
components: slice.map((c) => ({
|
|
307
|
+
name: c.name,
|
|
308
|
+
tier: c.tier,
|
|
309
|
+
import: c.npmImport,
|
|
310
|
+
vueImport: c.vueImport,
|
|
311
|
+
reactImport: c.reactImport
|
|
312
|
+
}))
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
content: [
|
|
316
|
+
{ type: 'text', text: JSON.stringify(withSkyUiMcpMeta(body, 'api_source'), null, 2) }
|
|
317
|
+
]
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (input.operation === 'search') {
|
|
321
|
+
const lim = input.limit ?? 20;
|
|
322
|
+
const result = searchSkyComponents(input.query, lim);
|
|
323
|
+
if (!result.ok) {
|
|
324
|
+
return mcpToolErr(McpErrorCode.COMPONENT_SEARCH_FAILED, result.error);
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
content: [
|
|
328
|
+
{
|
|
329
|
+
type: 'text',
|
|
330
|
+
text: JSON.stringify(withSkyUiMcpMeta({ query: input.query, limit: lim, hits: result.hits }, 'heuristic_search'), null, 2)
|
|
331
|
+
}
|
|
332
|
+
]
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
const lim = input.limit_per_query ?? 10;
|
|
336
|
+
const r = searchComponentsByApiBatch(input.queries, lim);
|
|
337
|
+
if (!r.ok) {
|
|
338
|
+
return mcpToolErr(McpErrorCode.COMPONENT_API_SEARCH_FAILED, r.error);
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
content: [
|
|
342
|
+
{
|
|
343
|
+
type: 'text',
|
|
344
|
+
text: JSON.stringify(withSkyUiMcpMeta({ limitPerQuery: lim, results: r.results }, 'heuristic_search'), null, 2)
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
server.registerTool('get_theme', {
|
|
350
|
+
title: 'Build userTheme for sky-theme-provider',
|
|
351
|
+
description: 'Start with operation=guide (userTheme shape + workflow). operation=fields lists entries; operation=field returns examplePatch; operation=match_intent maps user phrasing to field_ids; operation=compose merges patches; operation=variables lists --sky-* CSS names.',
|
|
352
|
+
inputSchema: z.discriminatedUnion('operation', [
|
|
353
|
+
z.object({
|
|
354
|
+
operation: z.literal('guide').describe('Start here: userTheme shape, merge rules, groups, minimal example')
|
|
355
|
+
}),
|
|
356
|
+
z.object({
|
|
357
|
+
operation: z.literal('fields'),
|
|
358
|
+
group: z
|
|
359
|
+
.string()
|
|
360
|
+
.optional()
|
|
361
|
+
.describe('Filter: color, surface, overlay, typography, density, shape, effects, motion, stacking, opacity')
|
|
362
|
+
}),
|
|
363
|
+
z.object({
|
|
364
|
+
operation: z.literal('field'),
|
|
365
|
+
field_id: z.string().describe('Field id from fields catalog, e.g. color_active')
|
|
366
|
+
}),
|
|
367
|
+
z.object({
|
|
368
|
+
operation: z.literal('variables'),
|
|
369
|
+
max_names: z.number().int().min(10).max(500).optional().describe('Cap on --sky-* names (default 200)')
|
|
370
|
+
}),
|
|
371
|
+
z.object({
|
|
372
|
+
operation: z.literal('match_intent'),
|
|
373
|
+
phrase: z.string().describe('User wording, e.g. "brand color", "more padding", "frosted glass"')
|
|
374
|
+
}),
|
|
375
|
+
z.object({
|
|
376
|
+
operation: z.literal('compose'),
|
|
377
|
+
field_ids: z
|
|
378
|
+
.array(z.string())
|
|
379
|
+
.min(1)
|
|
380
|
+
.describe('Field ids from fields or match_intent — merges examplePatch into one userTheme object')
|
|
381
|
+
})
|
|
382
|
+
])
|
|
383
|
+
}, async (input) => handleGetTheme(input));
|
|
384
|
+
server.registerTool('get_docs', {
|
|
385
|
+
title: 'Read allowed repository documentation file',
|
|
386
|
+
description: 'Returns markdown/text for allowlisted paths under the Sky UI monorepo (e.g. packages/mcp/README.md, packages/mcp/docs/sky-chart-option-api.md). Safe path-only reads.',
|
|
387
|
+
inputSchema: {
|
|
388
|
+
path: z.string().describe('Repo-relative path, e.g. packages/mcp/README.md'),
|
|
389
|
+
max_bytes: z.number().int().min(1_000).max(800_000).optional()
|
|
390
|
+
}
|
|
391
|
+
}, async ({ path: docPath, max_bytes }) => {
|
|
392
|
+
const r = getDocsPage(docPath, { max_bytes: max_bytes ?? undefined });
|
|
393
|
+
if (!r.ok) {
|
|
394
|
+
return mcpToolErr(McpErrorCode.DOCS_READ_FAILED, r.error, { allowed: listDocsPaths() });
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
content: [
|
|
398
|
+
{
|
|
399
|
+
type: 'text',
|
|
400
|
+
text: JSON.stringify(withSkyUiMcpMeta({
|
|
401
|
+
code: 'OK',
|
|
402
|
+
path: r.path,
|
|
403
|
+
mimeType: r.mimeType,
|
|
404
|
+
truncated: r.truncated,
|
|
405
|
+
content: r.content
|
|
406
|
+
}, 'static_reference'), null, 2)
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
};
|
|
410
|
+
});
|
|
411
|
+
server.registerTool('get_sky_component_docs', {
|
|
412
|
+
title: 'Get Sky UI component documentation',
|
|
413
|
+
description: 'Structured component API: summary, properties, slots, cssParts, events, methods, examples, and type definitions. Use name for one component or names[] for batch. Optional surface returns one member list (props|events|slots|methods). include_deprecations adds deprecation signals. Example-site enrichment applies when configured. Pair sky-chart with get_docs packages/mcp/docs/sky-chart-option-api.md.',
|
|
414
|
+
inputSchema: z
|
|
415
|
+
.object({
|
|
416
|
+
name: z.string().optional().describe('Single component name, e.g. sky-table or table'),
|
|
417
|
+
names: z
|
|
418
|
+
.array(z.string())
|
|
419
|
+
.min(1)
|
|
420
|
+
.max(50)
|
|
421
|
+
.optional()
|
|
422
|
+
.describe('Batch: multiple component names in one call'),
|
|
423
|
+
surface: z
|
|
424
|
+
.enum(['props', 'events', 'slots', 'methods'])
|
|
425
|
+
.optional()
|
|
426
|
+
.describe('Return only one API surface instead of the full doc'),
|
|
427
|
+
include_deprecations: optionalBooleanArg().describe('If true, include deprecations payload inferred from documentation text'),
|
|
428
|
+
max_example_chars: z.number().int().min(500).max(100_000).nullish().describe('Max characters per @example body (default 12000)'),
|
|
429
|
+
include_raw_lead: optionalBooleanArg().describe('If true, include rawLeadTrivia (JSDoc + decorators text before class keyword)'),
|
|
430
|
+
include_internal_lifecycle_methods: optionalBooleanArg().describe('If true, include browser/Lit lifecycle methods in the methods array. Default false.')
|
|
431
|
+
})
|
|
432
|
+
.superRefine((val, ctx) => {
|
|
433
|
+
const hasName = Boolean(val.name?.trim());
|
|
434
|
+
const hasNames = Boolean(val.names?.length);
|
|
435
|
+
if (hasName === hasNames) {
|
|
436
|
+
ctx.addIssue({
|
|
437
|
+
code: 'custom',
|
|
438
|
+
message: 'Provide exactly one of name (single) or names (batch).'
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
})
|
|
442
|
+
}, async (input) => handleGetSkyComponentDocs(input));
|
|
443
|
+
server.registerTool('get_component_usage', {
|
|
444
|
+
title: 'Component import path and usage snippet',
|
|
445
|
+
description: 'Returns lit/react/vue import paths and copy-paste starter snippets. React/Vue include wrapper metadata (Pascal name, barrel vs subpath, conventions). Optional import_style for react/vue: per_component | barrel | auto_import_note.',
|
|
446
|
+
inputSchema: {
|
|
447
|
+
framework: z.string().describe('Target framework: lit, react, or vue (aliases accepted)'),
|
|
448
|
+
name: z.string().describe('Component name, e.g. sky-button or button'),
|
|
449
|
+
import_style: z
|
|
450
|
+
.enum(['per_component', 'barrel', 'auto_import_note'])
|
|
451
|
+
.optional()
|
|
452
|
+
.describe('React/Vue only. Default per_component.')
|
|
453
|
+
}
|
|
454
|
+
}, async (input) => {
|
|
455
|
+
const result = handleGetComponentUsage(input);
|
|
456
|
+
return result;
|
|
457
|
+
});
|
|
458
|
+
server.registerTool('get_reactivity_layer', {
|
|
459
|
+
title: '@sky.ui/reactivity layer guide',
|
|
460
|
+
description: 'operation=list_topics: README section index. operation=get_topic: one section by id or alias. operation=package: named exports from @sky.ui/reactivity entry.',
|
|
461
|
+
inputSchema: z.discriminatedUnion('operation', [
|
|
462
|
+
z.object({ operation: z.literal('list_topics') }),
|
|
463
|
+
z.object({
|
|
464
|
+
operation: z.literal('get_topic'),
|
|
465
|
+
topic: z.string().min(1).describe('Topic id or alias (e.g. ref, sky-for); use list_topics first.'),
|
|
466
|
+
max_chars: z.number().int().min(2_000).max(400_000).optional()
|
|
467
|
+
}),
|
|
468
|
+
z.object({
|
|
469
|
+
operation: z.literal('package'),
|
|
470
|
+
export_substring: z.string().optional().describe('Filter named exports (case-insensitive substring)')
|
|
471
|
+
})
|
|
472
|
+
])
|
|
473
|
+
}, async (input) => handleGetReactivityLayer(input));
|
|
474
|
+
server.registerTool('get_chart_usage', {
|
|
475
|
+
title: 'sky-chart types and usage',
|
|
476
|
+
description: 'operation=list_types: supported host chart types. operation=get_type: API sections + starter snippet for a type (optional framework lit|react|vue). operation=option_guide: compact EChartsOption mental model. Pair with get_sky_component_docs(name: sky-chart) for live props/events.',
|
|
477
|
+
inputSchema: z.discriminatedUnion('operation', [
|
|
478
|
+
z.object({ operation: z.literal('list_types') }),
|
|
479
|
+
z.object({
|
|
480
|
+
operation: z.literal('get_type'),
|
|
481
|
+
chart_type: z.string().describe('Chart type key, e.g. bar, line, pie, radar, brush'),
|
|
482
|
+
framework: z.enum(['lit', 'react', 'vue']).optional().describe('Snippet framework (default lit)'),
|
|
483
|
+
import_style: z.enum(['per_component', 'barrel', 'auto_import_note']).optional()
|
|
484
|
+
}),
|
|
485
|
+
z.object({
|
|
486
|
+
operation: z.literal('option_guide'),
|
|
487
|
+
max_bytes: z.number().int().min(1_000).max(800_000).optional()
|
|
488
|
+
})
|
|
489
|
+
])
|
|
490
|
+
}, async (input) => handleGetChartUsage(input));
|
|
491
|
+
server.registerTool('utility_classes', {
|
|
492
|
+
title: '@sky.ui/utils — discover and validate utility class names',
|
|
493
|
+
description: 'User-facing class grounding only: variant_prefixes (responsive/state prefixes), search_classes (prefix browse), check_class (validate one token). Setup and config: get_project_guide + get_docs packages/mcp/docs/utils-usage-guide.md.',
|
|
494
|
+
inputSchema: z.discriminatedUnion('operation', [
|
|
495
|
+
z.object({ operation: z.literal('variant_prefixes') }),
|
|
496
|
+
z.object({
|
|
497
|
+
operation: z.literal('search_classes'),
|
|
498
|
+
starts_with: z.string().min(2).describe('Prefix on base utility names (min 2 chars)'),
|
|
499
|
+
limit: z.number().int().min(1).max(500).nullish(),
|
|
500
|
+
offset: z.number().int().min(0).nullish()
|
|
501
|
+
}),
|
|
502
|
+
z.object({
|
|
503
|
+
operation: z.literal('check_class'),
|
|
504
|
+
class_token: z
|
|
505
|
+
.string()
|
|
506
|
+
.min(1)
|
|
507
|
+
.describe('One utility token with variants, e.g. hover:p-4, sm:bg-red-500')
|
|
508
|
+
})
|
|
509
|
+
])
|
|
510
|
+
}, async (input) => {
|
|
511
|
+
if (input.operation === 'variant_prefixes') {
|
|
512
|
+
const r = await getUtilityVariantPrefixes();
|
|
513
|
+
if (!r.ok) {
|
|
514
|
+
return mcpToolErr(McpErrorCode.UTILS_SUGGESTION_FAILED, r.error);
|
|
515
|
+
}
|
|
516
|
+
const text = JSON.stringify(withSkyUiMcpMeta({ code: 'OK', variants: r.variants, count: r.count, disclaimer: r.disclaimer }, 'deterministic'), null, 2);
|
|
517
|
+
return { content: [{ type: 'text', text }] };
|
|
518
|
+
}
|
|
519
|
+
if (input.operation === 'search_classes') {
|
|
520
|
+
const r = await searchUtilityClasses({
|
|
521
|
+
starts_with: input.starts_with,
|
|
522
|
+
limit: input.limit ?? 80,
|
|
523
|
+
offset: input.offset ?? 0
|
|
524
|
+
});
|
|
525
|
+
if (!r.ok) {
|
|
526
|
+
return mcpToolErr(McpErrorCode.UTILS_SUGGESTION_FAILED, r.error);
|
|
527
|
+
}
|
|
528
|
+
const text = JSON.stringify(withSkyUiMcpMeta({
|
|
529
|
+
code: 'OK',
|
|
530
|
+
starts_with: r.starts_with,
|
|
531
|
+
limit: r.limit,
|
|
532
|
+
offset: r.offset,
|
|
533
|
+
totalMatches: r.totalMatches,
|
|
534
|
+
returned: r.returned,
|
|
535
|
+
classes: r.classes,
|
|
536
|
+
disclaimer: r.disclaimer
|
|
537
|
+
}, 'deterministic'), null, 2);
|
|
538
|
+
return { content: [{ type: 'text', text }] };
|
|
539
|
+
}
|
|
540
|
+
const raw = input.class_token.trim();
|
|
541
|
+
const parts = raw.split(/\s+/).filter(Boolean);
|
|
542
|
+
if (parts.length > 1 && !raw.includes(':')) {
|
|
543
|
+
const checks = await Promise.all(parts.map((p) => checkUtilityClass(p)));
|
|
544
|
+
const failed = checks.find((c) => !c.ok);
|
|
545
|
+
if (failed && !failed.ok) {
|
|
546
|
+
return mcpToolErr(McpErrorCode.UTILS_SUGGESTION_FAILED, failed.error);
|
|
547
|
+
}
|
|
548
|
+
const tokens = checks.filter((c) => c.ok);
|
|
549
|
+
const text = JSON.stringify(withSkyUiMcpMeta({
|
|
550
|
+
code: 'OK',
|
|
551
|
+
operation: 'check_class',
|
|
552
|
+
input: raw,
|
|
553
|
+
tokenCount: tokens.length,
|
|
554
|
+
engineSource: utilityEngineSource(),
|
|
555
|
+
tokens,
|
|
556
|
+
allKnownInCatalog: tokens.every((t) => t.knownInCatalog),
|
|
557
|
+
tip: 'Pass one class at a time when using variant prefixes (e.g. sm:hover:flex).'
|
|
558
|
+
}, 'deterministic'), null, 2);
|
|
559
|
+
return { content: [{ type: 'text', text }] };
|
|
560
|
+
}
|
|
561
|
+
const r = await checkUtilityClass(input.class_token);
|
|
562
|
+
if (!r.ok) {
|
|
563
|
+
return mcpToolErr(McpErrorCode.UTILS_SUGGESTION_FAILED, r.error);
|
|
564
|
+
}
|
|
565
|
+
const { ok: _ok2, ...body2 } = r;
|
|
566
|
+
const text = JSON.stringify(withSkyUiMcpMeta({ code: 'OK', operation: 'check_class', engineSource: utilityEngineSource(), ...body2 }, 'deterministic'), null, 2);
|
|
567
|
+
return { content: [{ type: 'text', text }] };
|
|
568
|
+
});
|
|
569
|
+
server.registerPrompt('sky_tool_router', {
|
|
570
|
+
title: 'Map user intent to Sky UI MCP tools',
|
|
571
|
+
description: 'Quick reference: which MCP tool to call for common questions (read-only; does not modify user projects).',
|
|
572
|
+
argsSchema: {}
|
|
573
|
+
}, async () => {
|
|
574
|
+
const body = [
|
|
575
|
+
'**Discovery**',
|
|
576
|
+
'- Catalog / keyword search / API search → `sky_components` (operation list | search | search_by_api)',
|
|
577
|
+
'',
|
|
578
|
+
'**Documentation**',
|
|
579
|
+
'- Full structured doc → `get_sky_component_docs` with `name`',
|
|
580
|
+
'- Batch docs → `get_sky_component_docs` with `names[]`',
|
|
581
|
+
'- One API surface → `get_sky_component_docs` with `surface` props|events|slots|methods',
|
|
582
|
+
'- Deprecations → `get_sky_component_docs` with `include_deprecations: true`',
|
|
583
|
+
'- Import + starter snippet → `get_component_usage` (lit | react | vue)',
|
|
584
|
+
'- Example-site agent recipe → `get_docs` with `packages/mcp/docs/agent-recipe-example-site.md`',
|
|
585
|
+
'- sky-chart → `get_chart_usage` then `get_sky_component_docs` with name `sky-chart`',
|
|
586
|
+
'',
|
|
587
|
+
'**Theme / userTheme**',
|
|
588
|
+
'- Start → `get_theme` operation **guide** (shape, merge rules, minimal example)',
|
|
589
|
+
'- Catalog → `get_theme` operation **fields** (what each entry does + JSON paths); optional group',
|
|
590
|
+
'- One entry + example JSON → `get_theme` operation **field** + field_id',
|
|
591
|
+
'- Map user phrasing → field ids → `get_theme` operation **match_intent** + phrase',
|
|
592
|
+
'- Merge several fields → `get_theme` operation **compose** + field_ids',
|
|
593
|
+
'- Emitted CSS var names → `get_theme` operation **variables**',
|
|
594
|
+
'- Prose companion → `get_docs` with `packages/mcp/docs/theme-config-guide.md`',
|
|
595
|
+
'- Cross-model routing → `get_docs` with `packages/mcp/docs/cross-model-mcp-playbook.md`',
|
|
596
|
+
'',
|
|
597
|
+
'**@sky.ui/reactivity**',
|
|
598
|
+
'- Topics → `get_reactivity_layer` (operation list_topics | get_topic | package)',
|
|
599
|
+
'- Full README → `get_docs` with `packages/reactivity/README.md`',
|
|
600
|
+
'- Install/setup → `get_project_guide` with framework `reactivity`',
|
|
601
|
+
'',
|
|
602
|
+
'**sky-chart**',
|
|
603
|
+
'- Types + snippets → `get_chart_usage` (operation list_types | get_type | option_guide)',
|
|
604
|
+
'- Live props/events → `get_sky_component_docs` with name `sky-chart`',
|
|
605
|
+
'',
|
|
606
|
+
'**@sky.ui/utils**',
|
|
607
|
+
'- Setup → `get_docs` with `packages/mcp/docs/utils-usage-guide.md` + `get_project_guide` (kind setup)',
|
|
608
|
+
'- Class names → `utility_classes` (variant_prefixes | search_classes | check_class)',
|
|
609
|
+
'',
|
|
610
|
+
'**Project setup**',
|
|
611
|
+
'- Install + bundler setup → `get_project_guide` (kind installation | setup)',
|
|
612
|
+
'',
|
|
613
|
+
'Epistemic: follow `_skyUiMcp.agentMust` before citing outputs as facts.',
|
|
614
|
+
'Resource: `sky-ui://catalog/tools` for machine-readable tool list.'
|
|
615
|
+
].join('\n');
|
|
616
|
+
return {
|
|
617
|
+
description: 'Sky UI MCP tool routing',
|
|
618
|
+
messages: [{ role: 'user', content: { type: 'text', text: body } }]
|
|
619
|
+
};
|
|
620
|
+
});
|
|
621
|
+
server.registerPrompt('sky_lit_component', {
|
|
622
|
+
title: 'Lit + Sky UI component starter',
|
|
623
|
+
description: 'User message template for adding a Sky UI web component with correct import and tag usage.',
|
|
624
|
+
argsSchema: {
|
|
625
|
+
component: z.string().describe('Component name, e.g. sky-button or button')
|
|
626
|
+
}
|
|
627
|
+
}, async ({ component }) => {
|
|
628
|
+
const loaded = loadSkyComponentsCached();
|
|
629
|
+
const resolved = loaded.ok ? resolveComponentEntry(component, loaded.components) : null;
|
|
630
|
+
const fallbackKey = normalizeComponentKey(component);
|
|
631
|
+
const imp = resolved?.entry.npmImport ?? `@sky.ui/core/${fallbackKey}`;
|
|
632
|
+
const tag = resolved?.entry.name ?? fallbackKey;
|
|
633
|
+
const body = [
|
|
634
|
+
`Add the Sky UI component **${tag}** to a Lit project.`,
|
|
635
|
+
``,
|
|
636
|
+
`- Import: \`import '${imp}';\` (side-effect import registers the custom element)`,
|
|
637
|
+
`- Use the tag \`<${tag}>...</${tag}>\` in Lit \`html\` templates.`,
|
|
638
|
+
`- Call **get_sky_component_docs** with name "${component}" for properties, slots, events, and examples.`,
|
|
639
|
+
`- Official docs: use the \`documentation\` field in that response when set.`
|
|
640
|
+
].join('\n');
|
|
641
|
+
return {
|
|
642
|
+
description: `Starter instructions for ${tag}`,
|
|
643
|
+
messages: [{ role: 'user', content: { type: 'text', text: body } }]
|
|
644
|
+
};
|
|
645
|
+
});
|
|
646
|
+
server.registerResource('sky-ui-tools-catalog', 'sky-ui://catalog/tools', {
|
|
647
|
+
title: 'Sky UI MCP tools (summary)',
|
|
648
|
+
description: 'Machine-readable list of tool names and short descriptions for routing.',
|
|
649
|
+
mimeType: 'application/json'
|
|
650
|
+
}, async () => {
|
|
651
|
+
const tools = [
|
|
652
|
+
{ name: 'get_project_guide', description: 'Installation (kind) or bundler setup (kind+framework+bundler)' },
|
|
653
|
+
{ name: 'sky_components', description: 'List | keyword search | API batch search (operation discriminant)' },
|
|
654
|
+
{ name: 'get_sky_component_docs', description: 'Structured component API; optional surface, batch names[], deprecations' },
|
|
655
|
+
{ name: 'get_component_usage', description: 'Lit/react/vue import paths and starter snippets' },
|
|
656
|
+
{ name: 'get_reactivity_layer', description: 'Reactivity README list_topics | get_topic | package exports' },
|
|
657
|
+
{ name: 'get_chart_usage', description: 'sky-chart list_types | get_type | option_guide' },
|
|
658
|
+
{ name: 'get_theme', description: 'userTheme authoring: guide | fields | field | variables' },
|
|
659
|
+
{ name: 'get_docs', description: 'Read allowlisted repo documentation files' },
|
|
660
|
+
{
|
|
661
|
+
name: 'utility_classes',
|
|
662
|
+
description: '@sky.ui/utils variant_prefixes | search_classes | check_class'
|
|
663
|
+
}
|
|
664
|
+
];
|
|
665
|
+
return {
|
|
666
|
+
contents: [
|
|
667
|
+
{
|
|
668
|
+
uri: 'sky-ui://catalog/tools',
|
|
669
|
+
mimeType: 'application/json',
|
|
670
|
+
text: JSON.stringify({ tools }, null, 2)
|
|
671
|
+
}
|
|
672
|
+
]
|
|
673
|
+
};
|
|
674
|
+
});
|
|
675
|
+
server.registerResource('sky-ui-component-catalog', 'sky-ui://catalog/components', {
|
|
676
|
+
title: 'Sky UI component catalog',
|
|
677
|
+
description: 'JSON list of @sky.ui/core and @sky.ui.pro/core component subpaths and tier-aware imports',
|
|
678
|
+
mimeType: 'application/json'
|
|
679
|
+
}, async () => {
|
|
680
|
+
const loaded = loadSkyComponentsCached();
|
|
681
|
+
if (!loaded.ok) {
|
|
682
|
+
return {
|
|
683
|
+
contents: [
|
|
684
|
+
{
|
|
685
|
+
uri: 'sky-ui://catalog/components',
|
|
686
|
+
mimeType: 'application/json',
|
|
687
|
+
text: mcpErrorJson(McpErrorCode.COMPONENT_CATALOG_FAILED, loaded.error)
|
|
688
|
+
}
|
|
689
|
+
]
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
const payload = {
|
|
693
|
+
source: loaded.path,
|
|
694
|
+
customElementsManifest: isCemManifestPresent(),
|
|
695
|
+
components: loaded.components
|
|
696
|
+
};
|
|
697
|
+
return {
|
|
698
|
+
contents: [
|
|
699
|
+
{
|
|
700
|
+
uri: 'sky-ui://catalog/components',
|
|
701
|
+
mimeType: 'application/json',
|
|
702
|
+
text: JSON.stringify(payload, null, 2)
|
|
703
|
+
}
|
|
704
|
+
]
|
|
705
|
+
};
|
|
706
|
+
});
|
|
707
|
+
server.registerResource('sky-ui-custom-elements-manifest', 'sky-ui://manifest/custom-elements.json', {
|
|
708
|
+
title: 'Sky UI Custom Elements Manifest',
|
|
709
|
+
description: 'Merged custom-elements.json from @sky.ui/core and @sky.ui.pro/core (after npm run build:main / build:main-pro). Standard schema for web component tooling.',
|
|
710
|
+
mimeType: 'application/json'
|
|
711
|
+
}, async () => {
|
|
712
|
+
const raw = readCustomElementsManifestText();
|
|
713
|
+
if (!raw) {
|
|
714
|
+
return {
|
|
715
|
+
contents: [
|
|
716
|
+
{
|
|
717
|
+
uri: 'sky-ui://manifest/custom-elements.json',
|
|
718
|
+
mimeType: 'application/json',
|
|
719
|
+
text: JSON.stringify({
|
|
720
|
+
error: 'Manifest not found. From the monorepo root run: npm run build:main'
|
|
721
|
+
})
|
|
722
|
+
}
|
|
723
|
+
]
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
return {
|
|
727
|
+
contents: [
|
|
728
|
+
{
|
|
729
|
+
uri: 'sky-ui://manifest/custom-elements.json',
|
|
730
|
+
mimeType: 'application/json',
|
|
731
|
+
text: raw
|
|
732
|
+
}
|
|
733
|
+
]
|
|
734
|
+
};
|
|
735
|
+
});
|
|
736
|
+
return server;
|
|
737
|
+
}
|
|
738
|
+
/** Opt-in stderr lines for stdio transport (stdout is reserved for MCP JSON-RPC). */
|
|
739
|
+
function skyUiMcpStdioLogEnabled() {
|
|
740
|
+
const v = process.env.SKY_UI_MCP_STDIO_LOG?.trim().toLowerCase();
|
|
741
|
+
return v === '1' || v === 'true' || v === 'yes';
|
|
742
|
+
}
|
|
743
|
+
/** stdio MCP server (used by `mcp-stdio-entry` bin and tests). */
|
|
744
|
+
export async function startSkyUiMcpStdio() {
|
|
745
|
+
assertCoreDependencyAvailable();
|
|
746
|
+
const server = createSkyUiMcpServer();
|
|
747
|
+
const transport = new StdioServerTransport();
|
|
748
|
+
if (skyUiMcpStdioLogEnabled()) {
|
|
749
|
+
console.error('[sky-ui-mcp] stdio server starting (waiting for MCP client on stdin). ' +
|
|
750
|
+
'If this process exits instantly with no error, stdin was closed—run from your editor MCP config, not a pipe or tool that closes stdin.');
|
|
751
|
+
}
|
|
752
|
+
process.stdin.on('end', () => {
|
|
753
|
+
if (skyUiMcpStdioLogEnabled()) {
|
|
754
|
+
console.error('[sky-ui-mcp] stdin closed; exiting (no MCP session).');
|
|
755
|
+
}
|
|
756
|
+
process.exit(0);
|
|
757
|
+
});
|
|
758
|
+
await server.connect(transport);
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Legacy: `node …/dist/server.js` (not recommended — use `sky-ui-mcp` / `mcp-stdio-entry.js`).
|
|
762
|
+
* Must stay false when this module is imported (e.g. post-endpoint-server).
|
|
763
|
+
*/
|
|
764
|
+
function isRunAsServerScriptDirectly() {
|
|
765
|
+
if (typeof process === 'undefined' || !process.argv[1])
|
|
766
|
+
return false;
|
|
767
|
+
const selfPath = path.resolve(fileURLToPath(import.meta.url));
|
|
768
|
+
const argvPath = path.resolve(process.argv[1]);
|
|
769
|
+
if (selfPath === argvPath)
|
|
770
|
+
return true;
|
|
771
|
+
if (process.platform === 'win32' && selfPath.toLowerCase() === argvPath.toLowerCase())
|
|
772
|
+
return true;
|
|
773
|
+
try {
|
|
774
|
+
return realpathSync.native(selfPath) === realpathSync.native(argvPath);
|
|
775
|
+
}
|
|
776
|
+
catch {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (isRunAsServerScriptDirectly()) {
|
|
781
|
+
startSkyUiMcpStdio().catch((err) => {
|
|
782
|
+
console.error(err);
|
|
783
|
+
process.exit(1);
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
//# sourceMappingURL=server.js.map
|