@dreamtree-org/twreact-ui 1.1.49 → 1.1.51

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.
@@ -0,0 +1,234 @@
1
+ // dreamtree-ui MCP server — transport-agnostic core
2
+ // ------------------------------------------------------------------------
3
+ // `createServer({ version, catalog })` builds the configured MCP Server with
4
+ // every tool / resource / prompt handler wired up. It is data-source-agnostic:
5
+ // `catalog` is any object exposing
6
+ // buildCatalog, findComponent, searchCatalog, listDocNames, readDoc, readSkill
7
+ // — which both the live catalog (mcp/catalog.mjs, reads src/ + doc/ live) and
8
+ // the shipped snapshot catalog (mcp/catalog-snapshot.mjs, reads a frozen JSON)
9
+ // provide. The transport (stdio) and boot live in the thin entry points
10
+ // (mcp/server.mjs for the repo, the `mcp` subcommand of bin/cli.mjs for
11
+ // consumers) so the SAME handler logic serves both — no copying.
12
+ //
13
+ // TOOLS
14
+ // list_components() → grouped catalog (core/feedback/nav/utility + hooks/utils)
15
+ // get_component(name) → props, variants, sizes, examples, a11y notes, family exports
16
+ // search_components(query) → ranked matches across names/props/examples
17
+ // RESOURCES
18
+ // dreamtree://skill → the consumer AI-usage guide
19
+ // dreamtree://docs/<Name> → the per-component manual
20
+ // PROMPT
21
+ // compose_ui → primes an agent to build UI with dreamtree-ui
22
+
23
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
24
+ import {
25
+ ListToolsRequestSchema,
26
+ CallToolRequestSchema,
27
+ ListResourcesRequestSchema,
28
+ ReadResourceRequestSchema,
29
+ ListPromptsRequestSchema,
30
+ GetPromptRequestSchema,
31
+ } from "@modelcontextprotocol/sdk/types.js";
32
+
33
+ export const PKG = "@dreamtree-org/twreact-ui";
34
+
35
+ // ---- formatting helpers ----------------------------------------------------
36
+
37
+ function asText(obj) {
38
+ return { content: [{ type: "text", text: typeof obj === "string" ? obj : JSON.stringify(obj, null, 2) }] };
39
+ }
40
+
41
+ function componentSummary(c) {
42
+ return {
43
+ name: c.name,
44
+ group: c.group,
45
+ familyExports: c.familyExports,
46
+ hasDoc: c.hasDoc,
47
+ description: c.description,
48
+ };
49
+ }
50
+
51
+ function fullComponent(c) {
52
+ return {
53
+ name: c.name,
54
+ group: c.group,
55
+ familyExports: c.familyExports,
56
+ import: `import { ${[c.name, ...c.familyExports].join(", ")} } from "${PKG}";`,
57
+ description: c.description,
58
+ props: c.props,
59
+ examples: c.examples,
60
+ accessibility:
61
+ "Interactive components are keyboard-operable, expose ARIA roles/labels, " +
62
+ "show a focus-visible ring, and support dark mode via the `dark:` variant. " +
63
+ "See docs/agents/03-coding-standards.md §7.",
64
+ conventions:
65
+ "forwardRef + className(merged via cn) + ...rest are forwarded to the root " +
66
+ "primitive. Variants: primary|secondary|outline|ghost|destructive|success|warning. " +
67
+ "Sizes: xs|sm|md|lg|xl. Theme via tailwind.config.js tokens, never a color prop.",
68
+ };
69
+ }
70
+
71
+ const TOOLS = [
72
+ {
73
+ name: "list_components",
74
+ description:
75
+ "List every exported component, hook, and util in @dreamtree-org/twreact-ui, " +
76
+ "grouped (core/feedback/navigation/utility + hooks + utils). Use this first to " +
77
+ "discover what the library offers before composing UI.",
78
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
79
+ },
80
+ {
81
+ name: "get_component",
82
+ description:
83
+ "Get the full spec for one component/hook/util: import statement, props table " +
84
+ "(name/type/default/description), variants & sizes, usage examples, family exports, " +
85
+ "and accessibility/convention notes. Accepts the component name or a family-export " +
86
+ "name (e.g. 'useToast' resolves to 'Toast').",
87
+ inputSchema: {
88
+ type: "object",
89
+ properties: { name: { type: "string", description: "Component/hook/util name, e.g. 'Button', 'useTheme', 'useToast'." } },
90
+ required: ["name"],
91
+ additionalProperties: false,
92
+ },
93
+ },
94
+ {
95
+ name: "search_components",
96
+ description:
97
+ "Search the library by keyword across component names, family exports, descriptions, " +
98
+ "prop names, and examples. Returns ranked matches. Use when you know the capability " +
99
+ "you need ('date', 'upload', 'modal') but not the component name.",
100
+ inputSchema: {
101
+ type: "object",
102
+ properties: { query: { type: "string", description: "Keyword(s), e.g. 'date', 'toast', 'multi select'." } },
103
+ required: ["query"],
104
+ additionalProperties: false,
105
+ },
106
+ },
107
+ ];
108
+
109
+ const SKILL_URI = "dreamtree://skill";
110
+ const docName = (name) => `dreamtree://docs/${name}`;
111
+
112
+ // Build the configured (but not yet connected) MCP Server. `catalog` supplies
113
+ // the data; `version` is reported in the server handshake.
114
+ export function createServer({ version, catalog }) {
115
+ const server = new Server(
116
+ { name: "dreamtree-ui", version },
117
+ { capabilities: { tools: {}, resources: {}, prompts: {} } }
118
+ );
119
+
120
+ // --- tools ---
121
+
122
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
123
+
124
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
125
+ const { name, arguments: args = {} } = req.params;
126
+
127
+ if (name === "list_components") {
128
+ const c = catalog.buildCatalog();
129
+ return asText({
130
+ package: PKG,
131
+ counts: c.counts,
132
+ components: c.components.map(componentSummary),
133
+ hooks: c.hooks.map(componentSummary),
134
+ utils: c.utils.map(componentSummary),
135
+ store: c.store.map(componentSummary),
136
+ });
137
+ }
138
+
139
+ if (name === "get_component") {
140
+ const target = catalog.findComponent(args.name);
141
+ if (!target) {
142
+ const c = catalog.buildCatalog();
143
+ const names = [...c.components, ...c.hooks, ...c.utils, ...c.store].map((x) => x.name);
144
+ return {
145
+ isError: true,
146
+ content: [{ type: "text", text: `No component named "${args.name}". Available: ${names.join(", ")}` }],
147
+ };
148
+ }
149
+ return asText(fullComponent(target));
150
+ }
151
+
152
+ if (name === "search_components") {
153
+ const hits = catalog.searchCatalog(args.query);
154
+ return asText({
155
+ query: args.query,
156
+ matches: hits.map((h) => ({ name: h.name, group: h.group, score: h._score, description: h.description })),
157
+ });
158
+ }
159
+
160
+ return { isError: true, content: [{ type: "text", text: `Unknown tool: ${name}` }] };
161
+ });
162
+
163
+ // --- resources ---
164
+
165
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
166
+ const resources = [
167
+ {
168
+ uri: SKILL_URI,
169
+ name: "dreamtree-ui AI usage guide",
170
+ description: "How to install, wire, and use the library — the consumer-facing AI reference.",
171
+ mimeType: "text/markdown",
172
+ },
173
+ ...catalog.listDocNames().map((n) => ({
174
+ uri: docName(n),
175
+ name: `${n} — component manual`,
176
+ description: `Props, examples, and notes for <${n}>.`,
177
+ mimeType: "text/markdown",
178
+ })),
179
+ ];
180
+ return { resources };
181
+ });
182
+
183
+ server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
184
+ const { uri } = req.params;
185
+ if (uri === SKILL_URI) {
186
+ const text = catalog.readSkill();
187
+ if (text == null) throw new Error("ai-skills/dreamtree-ui.md not found");
188
+ return { contents: [{ uri, mimeType: "text/markdown", text }] };
189
+ }
190
+ const m = uri.match(/^dreamtree:\/\/docs\/(.+)$/);
191
+ if (m) {
192
+ const text = catalog.readDoc(m[1]);
193
+ if (text == null) throw new Error(`No doc for "${m[1]}"`);
194
+ return { contents: [{ uri, mimeType: "text/markdown", text }] };
195
+ }
196
+ throw new Error(`Unknown resource: ${uri}`);
197
+ });
198
+
199
+ // --- prompt ---
200
+
201
+ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
202
+ prompts: [
203
+ {
204
+ name: "compose_ui",
205
+ description: "Prime yourself to build a UI using @dreamtree-org/twreact-ui components correctly.",
206
+ arguments: [
207
+ { name: "task", description: "What you want to build (e.g. 'a settings form with a save button').", required: false },
208
+ ],
209
+ },
210
+ ],
211
+ }));
212
+
213
+ server.setRequestHandler(GetPromptRequestSchema, async (req) => {
214
+ const task = req.params.arguments?.task?.trim();
215
+ const c = catalog.buildCatalog();
216
+ const roster = c.components.map((x) => x.name).join(", ");
217
+ const text =
218
+ `You are composing a UI with **${PKG}** (a React 18 + Tailwind component library).\n\n` +
219
+ `Rules:\n` +
220
+ `- Reach for a library component before hand-rolling a <div> + Tailwind. Available components: ${roster}. ` +
221
+ `Hooks: ${c.hooks.map((h) => h.name).join(", ")}. Utils: ${c.utils.map((u) => u.name).join(", ")}.\n` +
222
+ `- Before using a component, call the get_component tool to confirm its exact props (names, variants, sizes, defaults).\n` +
223
+ `- Use the shared vocabulary: variant = primary|secondary|outline|ghost|destructive|success|warning; size = xs|sm|md|lg|xl. Never pass a raw color prop.\n` +
224
+ `- Wrap the tree in <ThemeProvider> when using dark mode or useTheme; <StoreProvider> only if using useMixins.\n` +
225
+ `- The consumer's tailwind.config.js content[] must include ./node_modules/${PKG}/dist/**/*.{js,mjs}.\n` +
226
+ `- Read the dreamtree://skill resource for full wiring + examples.\n` +
227
+ (task ? `\nTask: ${task}\n` : "");
228
+ return {
229
+ messages: [{ role: "user", content: { type: "text", text } }],
230
+ };
231
+ });
232
+
233
+ return server;
234
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamtree-org/twreact-ui",
3
- "version": "1.1.49",
3
+ "version": "1.1.51",
4
4
  "description": "A comprehensive React + Tailwind components library for building modern web apps",
5
5
  "author": {
6
6
  "name": "Partha Preetham Krishna",
@@ -17,6 +17,10 @@
17
17
  "files": [
18
18
  "dist",
19
19
  "bin/cli.mjs",
20
+ "mcp/server-core.mjs",
21
+ "mcp/catalog-core.mjs",
22
+ "mcp/catalog-snapshot.mjs",
23
+ "mcp/catalog.snapshot.json",
20
24
  "ai-skills",
21
25
  "package.json",
22
26
  "README.md"
@@ -41,8 +45,7 @@
41
45
  "mcp:smoke": "node mcp/smoke.mjs",
42
46
  "mcp:snapshot": "node scripts/gen-mcp-snapshot.mjs",
43
47
  "mcp:snapshot:check": "node scripts/check-mcp-snapshot.mjs",
44
- "mcp:pkg:smoke": "node packages/mcp/smoke.mjs",
45
- "mcp:version:align": "node scripts/align-mcp-version.mjs",
48
+ "mcp:dist:smoke": "node scripts/mcp-dist-smoke.mjs",
46
49
  "prepublishOnly": "npm run mcp:snapshot && npm run mcp:snapshot:check",
47
50
  "skill:check": "node mcp/skill-check.mjs",
48
51
  "init:smoke": "node bin/smoke.mjs",
@@ -58,8 +61,7 @@
58
61
  "release:patch": "npm run release && npm run version:patch",
59
62
  "release:minor": "npm run release && npm run version:minor",
60
63
  "release:major": "npm run release && npm run version:major",
61
- "release:prerelease": "npm run release && npm run version:prerelease",
62
- "release:mcp": "npm run mcp:snapshot && npm run mcp:snapshot:check && npm run mcp:pkg:smoke && npm run mcp:version:align && npm publish packages/mcp --access public"
64
+ "release:prerelease": "npm run release && npm run version:prerelease"
63
65
  },
64
66
  "keywords": [
65
67
  "react",
@@ -88,6 +90,7 @@
88
90
  },
89
91
  "dependencies": {
90
92
  "@hookform/resolvers": "^3.10.0",
93
+ "@modelcontextprotocol/sdk": "^1.29.0",
91
94
  "@reduxjs/toolkit": "^2.11.2",
92
95
  "axios": "^1.13.4",
93
96
  "clsx": "^1.2.1",
@@ -105,7 +108,6 @@
105
108
  "@babel/preset-react": "^7.28.5",
106
109
  "@babel/preset-typescript": "^7.28.0",
107
110
  "@babel/runtime": "^7.28.6",
108
- "@modelcontextprotocol/sdk": "^1.29.0",
109
111
  "@rollup/plugin-babel": "^6.1.0",
110
112
  "@rollup/plugin-commonjs": "^25.0.8",
111
113
  "@rollup/plugin-node-resolve": "^15.3.1",