alus-ui-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +58 -0
  2. package/dist/index.js +1221 -0
  3. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # alus-ui-mcp
2
+
3
+ > MCP stdio server for the [alus-ui](https://www.npmjs.com/package/alus-ui) Svelte 5 component library.
4
+
5
+ Gives LLMs (Claude, Cursor, etc.) direct access to alus-ui component source, demos, exports, and utilities via the [Model Context Protocol](https://modelcontextprotocol.io).
6
+
7
+ ## Usage
8
+
9
+ ### npx (no install)
10
+
11
+ ```bash
12
+ npx alus-ui-mcp
13
+ ```
14
+
15
+ ### Claude Code
16
+
17
+ Add to `.mcp.json` at your project root:
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "alus-ui": {
23
+ "type": "stdio",
24
+ "command": "npx",
25
+ "args": ["alus-ui-mcp"]
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ ### Remote HTTP
32
+
33
+ The production Cloudflare deployment exposes `/mcp`. Point your client to:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "alus-ui": {
39
+ "url": "https://alus.lkmn.link/mcp"
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Tools
46
+
47
+ | Tool | Description |
48
+ |---|---|
49
+ | `alus_list_components` | Browse all 150+ components by category |
50
+ | `alus_get_component` | Read full `.svelte` + `index.ts` source |
51
+ | `alus_search_components` | Full-text search across all source files |
52
+ | `alus_get_component_demo` | Read showcase demo page |
53
+ | `alus_list_exports` | Show full public API (`components/index.ts`) |
54
+ | `alus_get_utils` | Read a11y/form utility module source |
55
+
56
+ ## License
57
+
58
+ MIT — part of the [alus](https://github.com/Hanivan/alus) monorepo.
package/dist/index.js ADDED
@@ -0,0 +1,1221 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // ../../node_modules/.pnpm/@tmcp+adapter-valibot@0.1.6_tmcp@1.19.4_typescript@5.9.3__valibot@1.4.1_typescript@5.9.3_/node_modules/@tmcp/adapter-valibot/src/index.js
9
+ import { JsonSchemaAdapter } from "tmcp/adapter";
10
+
11
+ // ../../node_modules/.pnpm/@valibot+to-json-schema@1.7.0_valibot@1.4.1_typescript@5.9.3_/node_modules/@valibot/to-json-schema/dist/index.mjs
12
+ function addError(errors, message) {
13
+ if (errors) {
14
+ errors.push(message);
15
+ return errors;
16
+ }
17
+ return [message];
18
+ }
19
+ var ESCAPE_REGEX = /[.*+?^${}()|[\]\\]/g;
20
+ function escapeRegExp(string2) {
21
+ return string2.replace(ESCAPE_REGEX, "\\$&");
22
+ }
23
+ function handleError(message, config) {
24
+ switch (config?.errorMode) {
25
+ case "ignore":
26
+ break;
27
+ case "warn":
28
+ console.warn(message);
29
+ break;
30
+ default:
31
+ throw new Error(message);
32
+ }
33
+ }
34
+ function isJsonConstValue(value) {
35
+ return typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) || typeof value === "string";
36
+ }
37
+ function isJsonEnumValues(values) {
38
+ return values.every(isJsonConstValue);
39
+ }
40
+ function convertAction(jsonSchema, valibotAction, config) {
41
+ if (config?.ignoreActions?.includes(valibotAction.type)) return jsonSchema;
42
+ let errors;
43
+ switch (valibotAction.type) {
44
+ case "base64":
45
+ jsonSchema.contentEncoding = "base64";
46
+ break;
47
+ case "bic":
48
+ case "cuid2":
49
+ case "decimal":
50
+ case "digits":
51
+ case "domain":
52
+ case "emoji":
53
+ case "hash":
54
+ case "hexadecimal":
55
+ case "hex_color":
56
+ case "isrc":
57
+ case "iso_time_second":
58
+ case "iso_week":
59
+ case "mac":
60
+ case "mac48":
61
+ case "mac64":
62
+ case "nanoid":
63
+ case "octal":
64
+ case "slug":
65
+ case "ulid":
66
+ if (jsonSchema.pattern) errors = addError(errors, `The "${valibotAction.type}" action is not supported in combination with another regex action.`);
67
+ else jsonSchema.pattern = valibotAction.requirement.source;
68
+ break;
69
+ case "description":
70
+ jsonSchema.description = valibotAction.description;
71
+ break;
72
+ case "email":
73
+ case "rfc_email":
74
+ jsonSchema.format = "email";
75
+ break;
76
+ case "ends_with":
77
+ if (jsonSchema.pattern) errors = addError(errors, `The "${valibotAction.type}" action is not supported in combination with another regex action.`);
78
+ else jsonSchema.pattern = `${escapeRegExp(valibotAction.requirement)}$`;
79
+ break;
80
+ case "empty":
81
+ if (jsonSchema.type === "array") jsonSchema.maxItems = 0;
82
+ else {
83
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
84
+ jsonSchema.maxLength = 0;
85
+ }
86
+ break;
87
+ case "entries":
88
+ jsonSchema.minProperties = valibotAction.requirement;
89
+ jsonSchema.maxProperties = valibotAction.requirement;
90
+ break;
91
+ case "examples":
92
+ if (Array.isArray(jsonSchema.examples)) jsonSchema.examples = [...jsonSchema.examples, ...valibotAction.examples];
93
+ else jsonSchema.examples = valibotAction.examples;
94
+ break;
95
+ case "gt_value":
96
+ if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "gt_value" action is not supported on type "${jsonSchema.type}".`);
97
+ if (config?.target === "openapi-3.0") {
98
+ errors = addError(errors, 'The "gt_value" action is not supported for OpenAPI 3.0.');
99
+ break;
100
+ }
101
+ jsonSchema.exclusiveMinimum = valibotAction.requirement;
102
+ break;
103
+ case "includes":
104
+ if (jsonSchema.pattern) errors = addError(errors, `The "${valibotAction.type}" action is not supported in combination with another regex action.`);
105
+ else jsonSchema.pattern = escapeRegExp(valibotAction.requirement);
106
+ break;
107
+ case "integer":
108
+ jsonSchema.type = "integer";
109
+ break;
110
+ case "ipv4":
111
+ jsonSchema.format = "ipv4";
112
+ break;
113
+ case "ipv6":
114
+ jsonSchema.format = "ipv6";
115
+ break;
116
+ case "iso_date":
117
+ jsonSchema.format = "date";
118
+ break;
119
+ case "iso_date_time":
120
+ case "iso_timestamp":
121
+ jsonSchema.format = "date-time";
122
+ break;
123
+ case "iso_time":
124
+ jsonSchema.format = "time";
125
+ break;
126
+ case "jws_compact":
127
+ if (jsonSchema.pattern) errors = addError(errors, `The "${valibotAction.type}" action is not supported in combination with another regex action.`);
128
+ else jsonSchema.pattern = valibotAction.requirement.source;
129
+ break;
130
+ case "length":
131
+ if (jsonSchema.type === "array") {
132
+ jsonSchema.minItems = valibotAction.requirement;
133
+ jsonSchema.maxItems = valibotAction.requirement;
134
+ } else {
135
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
136
+ jsonSchema.minLength = valibotAction.requirement;
137
+ jsonSchema.maxLength = valibotAction.requirement;
138
+ }
139
+ break;
140
+ case "lt_value":
141
+ if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "lt_value" action is not supported on type "${jsonSchema.type}".`);
142
+ if (config?.target === "openapi-3.0") {
143
+ errors = addError(errors, 'The "lt_value" action is not supported for OpenAPI 3.0.');
144
+ break;
145
+ }
146
+ jsonSchema.exclusiveMaximum = valibotAction.requirement;
147
+ break;
148
+ case "max_entries":
149
+ jsonSchema.maxProperties = valibotAction.requirement;
150
+ break;
151
+ case "max_length":
152
+ if (jsonSchema.type === "array") jsonSchema.maxItems = valibotAction.requirement;
153
+ else {
154
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
155
+ jsonSchema.maxLength = valibotAction.requirement;
156
+ }
157
+ break;
158
+ case "max_value":
159
+ if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "max_value" action is not supported on type "${jsonSchema.type}".`);
160
+ jsonSchema.maximum = valibotAction.requirement;
161
+ break;
162
+ case "metadata":
163
+ if (typeof valibotAction.metadata.title === "string") jsonSchema.title = valibotAction.metadata.title;
164
+ if (typeof valibotAction.metadata.description === "string") jsonSchema.description = valibotAction.metadata.description;
165
+ if (Array.isArray(valibotAction.metadata.examples)) if (Array.isArray(jsonSchema.examples)) jsonSchema.examples = [...jsonSchema.examples, ...valibotAction.metadata.examples];
166
+ else jsonSchema.examples = valibotAction.metadata.examples;
167
+ break;
168
+ case "min_entries":
169
+ jsonSchema.minProperties = valibotAction.requirement;
170
+ break;
171
+ case "min_length":
172
+ if (jsonSchema.type === "array") jsonSchema.minItems = valibotAction.requirement;
173
+ else {
174
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
175
+ jsonSchema.minLength = valibotAction.requirement;
176
+ }
177
+ break;
178
+ case "min_value":
179
+ if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "min_value" action is not supported on type "${jsonSchema.type}".`);
180
+ jsonSchema.minimum = valibotAction.requirement;
181
+ break;
182
+ case "multiple_of":
183
+ jsonSchema.multipleOf = valibotAction.requirement;
184
+ break;
185
+ case "non_empty":
186
+ if (jsonSchema.type === "array") jsonSchema.minItems = 1;
187
+ else {
188
+ if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
189
+ jsonSchema.minLength = 1;
190
+ }
191
+ break;
192
+ case "not_value":
193
+ if (!isJsonConstValue(valibotAction.requirement)) {
194
+ errors = addError(errors, 'The requirement of the "not_value" action is not JSON compatible.');
195
+ break;
196
+ }
197
+ if (config?.target === "openapi-3.0") jsonSchema.not = { enum: [valibotAction.requirement] };
198
+ else jsonSchema.not = { const: valibotAction.requirement };
199
+ break;
200
+ case "not_values":
201
+ if (!isJsonEnumValues(valibotAction.requirement)) {
202
+ errors = addError(errors, 'A requirement of the "not_values" action is not JSON compatible.');
203
+ break;
204
+ }
205
+ jsonSchema.not = { enum: valibotAction.requirement };
206
+ break;
207
+ case "regex":
208
+ if (valibotAction.requirement.flags) errors = addError(errors, "RegExp flags are not supported by JSON Schema.");
209
+ if (jsonSchema.pattern) errors = addError(errors, `The "${valibotAction.type}" action is not supported in combination with another regex action.`);
210
+ else jsonSchema.pattern = valibotAction.requirement.source;
211
+ break;
212
+ case "safe_integer":
213
+ jsonSchema.type = "integer";
214
+ if (typeof jsonSchema.minimum !== "number" || jsonSchema.minimum < Number.MIN_SAFE_INTEGER) jsonSchema.minimum = Number.MIN_SAFE_INTEGER;
215
+ if (typeof jsonSchema.maximum !== "number" || jsonSchema.maximum > Number.MAX_SAFE_INTEGER) jsonSchema.maximum = Number.MAX_SAFE_INTEGER;
216
+ break;
217
+ case "starts_with":
218
+ if (jsonSchema.pattern) errors = addError(errors, `The "${valibotAction.type}" action is not supported in combination with another regex action.`);
219
+ else jsonSchema.pattern = `^${escapeRegExp(valibotAction.requirement)}`;
220
+ break;
221
+ case "title":
222
+ jsonSchema.title = valibotAction.title;
223
+ break;
224
+ case "url":
225
+ jsonSchema.format = "uri";
226
+ break;
227
+ case "uuid":
228
+ jsonSchema.format = "uuid";
229
+ break;
230
+ case "value":
231
+ if (!isJsonConstValue(valibotAction.requirement)) {
232
+ errors = addError(errors, 'The requirement of the "value" action is not JSON compatible.');
233
+ break;
234
+ }
235
+ if (config?.target === "openapi-3.0") jsonSchema.enum = [valibotAction.requirement];
236
+ else jsonSchema.const = valibotAction.requirement;
237
+ break;
238
+ case "values":
239
+ if (!isJsonEnumValues(valibotAction.requirement)) {
240
+ errors = addError(errors, 'A requirement of the "values" action is not JSON compatible.');
241
+ break;
242
+ }
243
+ jsonSchema.enum = valibotAction.requirement;
244
+ break;
245
+ default:
246
+ errors = addError(errors, `The "${valibotAction.type}" action cannot be converted to JSON Schema.`);
247
+ }
248
+ if (config?.overrideAction) {
249
+ const actionOverride = config.overrideAction({
250
+ valibotAction,
251
+ jsonSchema,
252
+ errors
253
+ });
254
+ if (actionOverride) return { ...actionOverride };
255
+ }
256
+ if (errors) for (const message of errors) handleError(message, config);
257
+ return jsonSchema;
258
+ }
259
+ function flattenPipe(pipe2) {
260
+ return pipe2.flatMap((item) => "pipe" in item ? flattenPipe(item.pipe) : item);
261
+ }
262
+ var refCount = 0;
263
+ function convertSchema(jsonSchema, valibotSchema, config, context, skipRef = false) {
264
+ if (!skipRef) {
265
+ const referenceId = context.referenceMap.get(valibotSchema);
266
+ if (referenceId) {
267
+ jsonSchema.$ref = `#/$defs/${referenceId}`;
268
+ if (config?.overrideRef) {
269
+ const refOverride = config.overrideRef({
270
+ ...context,
271
+ referenceId,
272
+ valibotSchema,
273
+ jsonSchema
274
+ });
275
+ if (refOverride) jsonSchema.$ref = refOverride;
276
+ }
277
+ return jsonSchema;
278
+ }
279
+ }
280
+ if ("pipe" in valibotSchema) {
281
+ const flatPipe = flattenPipe(valibotSchema.pipe);
282
+ let startIndex = 0;
283
+ let stopIndex = flatPipe.length - 1;
284
+ if (config?.typeMode === "input") {
285
+ const inputStopIndex = flatPipe.slice(1).findIndex((item) => item.kind === "schema" || item.kind === "transformation" && (item.type === "find_item" || item.type === "parse_json" || item.type === "raw_transform" || item.type === "reduce_items" || item.type === "stringify_json" || item.type === "to_bigint" || item.type === "to_boolean" || item.type === "to_date" || item.type === "to_number" || item.type === "to_string" || item.type === "transform"));
286
+ if (inputStopIndex !== -1) stopIndex = inputStopIndex;
287
+ } else if (config?.typeMode === "output") {
288
+ const outputStartIndex = flatPipe.findLastIndex((item) => item.kind === "schema");
289
+ if (outputStartIndex !== -1) startIndex = outputStartIndex;
290
+ }
291
+ for (let index = startIndex; index <= stopIndex; index++) {
292
+ const valibotPipeItem = flatPipe[index];
293
+ if (valibotPipeItem.kind === "schema") {
294
+ if (index > startIndex) handleError('Set the "typeMode" config to "input" or "output" to convert pipelines with multiple schemas.', config);
295
+ jsonSchema = convertSchema(jsonSchema, valibotPipeItem, config, context, true);
296
+ } else jsonSchema = convertAction(jsonSchema, valibotPipeItem, config);
297
+ }
298
+ return jsonSchema;
299
+ }
300
+ let errors;
301
+ switch (valibotSchema.type) {
302
+ case "boolean":
303
+ jsonSchema.type = "boolean";
304
+ break;
305
+ case "null":
306
+ if (config?.target === "openapi-3.0") jsonSchema.enum = [null];
307
+ else jsonSchema.type = "null";
308
+ break;
309
+ case "number":
310
+ jsonSchema.type = "number";
311
+ break;
312
+ case "string":
313
+ jsonSchema.type = "string";
314
+ break;
315
+ case "array":
316
+ jsonSchema.type = "array";
317
+ jsonSchema.items = convertSchema({}, valibotSchema.item, config, context);
318
+ break;
319
+ case "tuple":
320
+ case "tuple_with_rest":
321
+ case "loose_tuple":
322
+ case "strict_tuple":
323
+ jsonSchema.type = "array";
324
+ if (config?.target === "openapi-3.0") {
325
+ jsonSchema.items = { anyOf: [] };
326
+ jsonSchema.minItems = valibotSchema.items.length;
327
+ for (const item of valibotSchema.items) jsonSchema.items.anyOf.push(convertSchema({}, item, config, context));
328
+ if (valibotSchema.type === "tuple_with_rest") jsonSchema.items.anyOf.push(convertSchema({}, valibotSchema.rest, config, context));
329
+ else if (valibotSchema.type === "strict_tuple" || valibotSchema.type === "tuple") jsonSchema.maxItems = valibotSchema.items.length;
330
+ } else if (config?.target === "draft-2020-12") {
331
+ jsonSchema.prefixItems = [];
332
+ jsonSchema.minItems = valibotSchema.items.length;
333
+ for (const item of valibotSchema.items) jsonSchema.prefixItems.push(convertSchema({}, item, config, context));
334
+ if (valibotSchema.type === "tuple_with_rest") jsonSchema.items = convertSchema({}, valibotSchema.rest, config, context);
335
+ else if (valibotSchema.type === "strict_tuple") jsonSchema.items = false;
336
+ } else {
337
+ jsonSchema.items = [];
338
+ jsonSchema.minItems = valibotSchema.items.length;
339
+ for (const item of valibotSchema.items) jsonSchema.items.push(convertSchema({}, item, config, context));
340
+ if (valibotSchema.type === "tuple_with_rest") jsonSchema.additionalItems = convertSchema({}, valibotSchema.rest, config, context);
341
+ else if (valibotSchema.type === "strict_tuple") jsonSchema.additionalItems = false;
342
+ }
343
+ break;
344
+ case "object":
345
+ case "object_with_rest":
346
+ case "loose_object":
347
+ case "strict_object":
348
+ jsonSchema.type = "object";
349
+ jsonSchema.properties = {};
350
+ jsonSchema.required = [];
351
+ for (const key in valibotSchema.entries) {
352
+ const entry = valibotSchema.entries[key];
353
+ jsonSchema.properties[key] = convertSchema({}, entry, config, context);
354
+ if (entry.type !== "exact_optional" && entry.type !== "nullish" && entry.type !== "optional") jsonSchema.required.push(key);
355
+ }
356
+ if (valibotSchema.type === "object_with_rest") jsonSchema.additionalProperties = convertSchema({}, valibotSchema.rest, config, context);
357
+ else if (valibotSchema.type === "strict_object") jsonSchema.additionalProperties = false;
358
+ break;
359
+ case "record":
360
+ if (config?.target === "openapi-3.0" && "pipe" in valibotSchema.key) errors = addError(errors, 'The "record" schema with a schema for the key that contains a "pipe" cannot be converted to JSON Schema.');
361
+ if (valibotSchema.key.type !== "string") errors = addError(errors, `The "record" schema with the "${valibotSchema.key.type}" schema for the key cannot be converted to JSON Schema.`);
362
+ jsonSchema.type = "object";
363
+ if (config?.target !== "openapi-3.0") jsonSchema.propertyNames = convertSchema({}, valibotSchema.key, config, context);
364
+ jsonSchema.additionalProperties = convertSchema({}, valibotSchema.value, config, context);
365
+ break;
366
+ case "any":
367
+ case "unknown":
368
+ break;
369
+ case "never":
370
+ jsonSchema.not = {};
371
+ break;
372
+ case "nullable":
373
+ case "nullish":
374
+ if (config?.target === "openapi-3.0") {
375
+ const innerSchema = convertSchema({}, valibotSchema.wrapped, config, context);
376
+ Object.assign(jsonSchema, innerSchema);
377
+ jsonSchema.nullable = true;
378
+ } else jsonSchema.anyOf = [convertSchema({}, valibotSchema.wrapped, config, context), { type: "null" }];
379
+ if (valibotSchema.default !== void 0) jsonSchema.default = typeof valibotSchema.default === "function" ? valibotSchema.default() : valibotSchema.default;
380
+ break;
381
+ case "exact_optional":
382
+ case "optional":
383
+ case "undefinedable":
384
+ jsonSchema = convertSchema(jsonSchema, valibotSchema.wrapped, config, context);
385
+ if (valibotSchema.default !== void 0) jsonSchema.default = typeof valibotSchema.default === "function" ? valibotSchema.default() : valibotSchema.default;
386
+ break;
387
+ case "literal":
388
+ if (typeof valibotSchema.literal !== "boolean" && typeof valibotSchema.literal !== "number" && typeof valibotSchema.literal !== "string") errors = addError(errors, 'The value of the "literal" schema is not JSON compatible.');
389
+ if (config?.target === "openapi-3.0") jsonSchema.enum = [valibotSchema.literal];
390
+ else jsonSchema.const = valibotSchema.literal;
391
+ break;
392
+ case "enum":
393
+ jsonSchema.enum = valibotSchema.options;
394
+ if (valibotSchema.options.every((option) => typeof option === "string")) jsonSchema.type = "string";
395
+ else if (valibotSchema.options.every((option) => typeof option === "number")) jsonSchema.type = "number";
396
+ else if (config?.target !== "openapi-3.0") jsonSchema.type = ["string", "number"];
397
+ break;
398
+ case "picklist": {
399
+ const hasInvalidOption = valibotSchema.options.some((option) => typeof option !== "number" && typeof option !== "string");
400
+ if (hasInvalidOption) errors = addError(errors, 'An option of the "picklist" schema is not JSON compatible.');
401
+ jsonSchema.enum = valibotSchema.options;
402
+ if (valibotSchema.options.every((option) => typeof option === "string")) jsonSchema.type = "string";
403
+ else if (valibotSchema.options.every((option) => typeof option === "number")) jsonSchema.type = "number";
404
+ else if (!hasInvalidOption && config?.target !== "openapi-3.0") jsonSchema.type = ["string", "number"];
405
+ break;
406
+ }
407
+ case "union":
408
+ jsonSchema.anyOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
409
+ break;
410
+ case "variant":
411
+ jsonSchema.oneOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
412
+ break;
413
+ case "intersect":
414
+ jsonSchema.allOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
415
+ break;
416
+ case "lazy": {
417
+ let wrappedValibotSchema = context.getterMap.get(valibotSchema.getter);
418
+ if (!wrappedValibotSchema) {
419
+ wrappedValibotSchema = valibotSchema.getter(void 0);
420
+ context.getterMap.set(valibotSchema.getter, wrappedValibotSchema);
421
+ }
422
+ let referenceId = context.referenceMap.get(wrappedValibotSchema);
423
+ if (!referenceId) {
424
+ referenceId = `${refCount++}`;
425
+ context.referenceMap.set(wrappedValibotSchema, referenceId);
426
+ context.definitions[referenceId] = convertSchema({}, wrappedValibotSchema, config, context, true);
427
+ }
428
+ jsonSchema.$ref = `#/$defs/${referenceId}`;
429
+ if (config?.overrideRef) {
430
+ const refOverride = config.overrideRef({
431
+ ...context,
432
+ referenceId,
433
+ valibotSchema: wrappedValibotSchema,
434
+ jsonSchema
435
+ });
436
+ if (refOverride) jsonSchema.$ref = refOverride;
437
+ }
438
+ break;
439
+ }
440
+ default:
441
+ errors = addError(errors, `The "${valibotSchema.type}" schema cannot be converted to JSON Schema.`);
442
+ }
443
+ if (config?.overrideSchema) {
444
+ const schemaOverride = config.overrideSchema({
445
+ ...context,
446
+ referenceId: context.referenceMap.get(valibotSchema),
447
+ valibotSchema,
448
+ jsonSchema,
449
+ errors
450
+ });
451
+ if (schemaOverride) return { ...schemaOverride };
452
+ }
453
+ if (errors) for (const message of errors) handleError(message, config);
454
+ return jsonSchema;
455
+ }
456
+ var store;
457
+ function getGlobalDefs() {
458
+ return store;
459
+ }
460
+ function toJsonSchema(schema6, config) {
461
+ const context = {
462
+ definitions: {},
463
+ referenceMap: /* @__PURE__ */ new Map(),
464
+ getterMap: /* @__PURE__ */ new Map()
465
+ };
466
+ const definitions = config?.definitions ?? getGlobalDefs();
467
+ if (definitions) {
468
+ for (const key in definitions) context.referenceMap.set(definitions[key], key);
469
+ for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
470
+ }
471
+ const jsonSchema = convertSchema({}, schema6, config, context);
472
+ const target = config?.target ?? "draft-07";
473
+ if (target === "draft-2020-12") jsonSchema.$schema = "https://json-schema.org/draft/2020-12/schema";
474
+ else if (target === "draft-07") jsonSchema.$schema = "http://json-schema.org/draft-07/schema#";
475
+ if (context.referenceMap.size) jsonSchema.$defs = context.definitions;
476
+ return jsonSchema;
477
+ }
478
+
479
+ // ../../node_modules/.pnpm/@tmcp+adapter-valibot@0.1.6_tmcp@1.19.4_typescript@5.9.3__valibot@1.4.1_typescript@5.9.3_/node_modules/@tmcp/adapter-valibot/src/index.js
480
+ function add_type_to_enums(json_schema) {
481
+ for (let key in json_schema) {
482
+ const property = json_schema[
483
+ /** @type {keyof json_schema} */
484
+ key
485
+ ];
486
+ if (property != null && typeof property === "object" && !Array.isArray(property)) {
487
+ if ("enum" in property && !("type" in property)) {
488
+ property.type = "string";
489
+ }
490
+ add_type_to_enums(property);
491
+ }
492
+ }
493
+ return json_schema;
494
+ }
495
+ var ValibotJsonSchemaAdapter = class extends JsonSchemaAdapter {
496
+ /**
497
+ * Converts a Valibot schema to JSON Schema format
498
+ * @param {GenericSchema} schema - The Valibot schema to convert
499
+ * @returns {Promise<ReturnType<typeof toJsonSchema>>} - The converted JSON Schema
500
+ */
501
+ async toJsonSchema(schema6) {
502
+ return add_type_to_enums(toJsonSchema(schema6));
503
+ }
504
+ };
505
+
506
+ // ../mcp-server/src/mcp/index.ts
507
+ import { McpServer } from "tmcp";
508
+
509
+ // ../mcp-server/src/mcp/handlers/tools/index.ts
510
+ var tools_exports = {};
511
+ __export(tools_exports, {
512
+ get_component: () => get_component,
513
+ get_component_demo: () => get_component_demo,
514
+ get_utils: () => get_utils,
515
+ list_components: () => list_components,
516
+ list_exports: () => list_exports,
517
+ search_components: () => search_components
518
+ });
519
+
520
+ // ../../node_modules/.pnpm/valibot@1.4.1_typescript@5.9.3/node_modules/valibot/dist/index.mjs
521
+ var store$4;
522
+ var DEFAULT_CONFIG = {
523
+ lang: void 0,
524
+ message: void 0,
525
+ abortEarly: void 0,
526
+ abortPipeEarly: void 0
527
+ };
528
+ // @__NO_SIDE_EFFECTS__
529
+ function getGlobalConfig(config$1) {
530
+ if (!config$1 && !store$4) return DEFAULT_CONFIG;
531
+ return {
532
+ lang: config$1?.lang ?? store$4?.lang,
533
+ message: config$1?.message,
534
+ abortEarly: config$1?.abortEarly ?? store$4?.abortEarly,
535
+ abortPipeEarly: config$1?.abortPipeEarly ?? store$4?.abortPipeEarly
536
+ };
537
+ }
538
+ var store$3;
539
+ // @__NO_SIDE_EFFECTS__
540
+ function getGlobalMessage(lang) {
541
+ return store$3?.get(lang);
542
+ }
543
+ var store$2;
544
+ // @__NO_SIDE_EFFECTS__
545
+ function getSchemaMessage(lang) {
546
+ return store$2?.get(lang);
547
+ }
548
+ var store$1;
549
+ // @__NO_SIDE_EFFECTS__
550
+ function getSpecificMessage(reference, lang) {
551
+ return store$1?.get(reference)?.get(lang);
552
+ }
553
+ // @__NO_SIDE_EFFECTS__
554
+ function _stringify(input) {
555
+ const type = typeof input;
556
+ if (type === "string") return `"${input}"`;
557
+ if (type === "number" || type === "bigint" || type === "boolean") return `${input}`;
558
+ if (type === "object" || type === "function") return (input && Object.getPrototypeOf(input)?.constructor?.name) ?? "null";
559
+ return type;
560
+ }
561
+ function _addIssue(context, label, dataset, config$1, other) {
562
+ const input = other && "input" in other ? other.input : dataset.value;
563
+ const expected = other?.expected ?? context.expects ?? null;
564
+ const received = other?.received ?? /* @__PURE__ */ _stringify(input);
565
+ const issue = {
566
+ kind: context.kind,
567
+ type: context.type,
568
+ input,
569
+ expected,
570
+ received,
571
+ message: `Invalid ${label}: ${expected ? `Expected ${expected} but r` : "R"}eceived ${received}`,
572
+ requirement: context.requirement,
573
+ path: other?.path,
574
+ issues: other?.issues,
575
+ lang: config$1.lang,
576
+ abortEarly: config$1.abortEarly,
577
+ abortPipeEarly: config$1.abortPipeEarly
578
+ };
579
+ const isSchema = context.kind === "schema";
580
+ const message$1 = other?.message ?? context.message ?? /* @__PURE__ */ getSpecificMessage(context.reference, issue.lang) ?? (isSchema ? /* @__PURE__ */ getSchemaMessage(issue.lang) : null) ?? config$1.message ?? /* @__PURE__ */ getGlobalMessage(issue.lang);
581
+ if (message$1 !== void 0) issue.message = typeof message$1 === "function" ? message$1(issue) : message$1;
582
+ if (isSchema) dataset.typed = false;
583
+ if (dataset.issues) dataset.issues.push(issue);
584
+ else dataset.issues = [issue];
585
+ }
586
+ var _standardCache = /* @__PURE__ */ new WeakMap();
587
+ // @__NO_SIDE_EFFECTS__
588
+ function _getStandardProps(context) {
589
+ let cached = _standardCache.get(context);
590
+ if (!cached) {
591
+ cached = {
592
+ version: 1,
593
+ vendor: "valibot",
594
+ validate(value$1) {
595
+ return context["~run"]({ value: value$1 }, /* @__PURE__ */ getGlobalConfig());
596
+ }
597
+ };
598
+ _standardCache.set(context, cached);
599
+ }
600
+ return cached;
601
+ }
602
+ // @__NO_SIDE_EFFECTS__
603
+ function _joinExpects(values$1, separator) {
604
+ const list = [...new Set(values$1)];
605
+ if (list.length > 1) return `(${list.join(` ${separator} `)})`;
606
+ return list[0] ?? "never";
607
+ }
608
+ var EMOJI_REGEX = new RegExp("^(?:[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|(?![\\p{Emoji_Modifier_Base}\\u{1F1E6}-\\u{1F1FF}])\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|(?![\\p{Emoji_Modifier_Base}\\u{1F1E6}-\\u{1F1FF}])\\p{Emoji_Presentation}))*)+$", "u");
609
+ // @__NO_SIDE_EFFECTS__
610
+ function description(description_) {
611
+ return {
612
+ kind: "metadata",
613
+ type: "description",
614
+ reference: description,
615
+ description: description_
616
+ };
617
+ }
618
+ // @__NO_SIDE_EFFECTS__
619
+ function integer(message$1) {
620
+ return {
621
+ kind: "validation",
622
+ type: "integer",
623
+ reference: integer,
624
+ async: false,
625
+ expects: null,
626
+ requirement: Number.isInteger,
627
+ message: message$1,
628
+ "~run"(dataset, config$1) {
629
+ if (dataset.typed && !this.requirement(dataset.value)) _addIssue(this, "integer", dataset, config$1);
630
+ return dataset;
631
+ }
632
+ };
633
+ }
634
+ // @__NO_SIDE_EFFECTS__
635
+ function maxValue(requirement, message$1) {
636
+ return {
637
+ kind: "validation",
638
+ type: "max_value",
639
+ reference: maxValue,
640
+ async: false,
641
+ expects: `<=${requirement instanceof Date ? requirement.toJSON() : /* @__PURE__ */ _stringify(requirement)}`,
642
+ requirement,
643
+ message: message$1,
644
+ "~run"(dataset, config$1) {
645
+ if (dataset.typed && !(dataset.value <= this.requirement)) _addIssue(this, "value", dataset, config$1, { received: dataset.value instanceof Date ? dataset.value.toJSON() : /* @__PURE__ */ _stringify(dataset.value) });
646
+ return dataset;
647
+ }
648
+ };
649
+ }
650
+ // @__NO_SIDE_EFFECTS__
651
+ function minLength(requirement, message$1) {
652
+ return {
653
+ kind: "validation",
654
+ type: "min_length",
655
+ reference: minLength,
656
+ async: false,
657
+ expects: `>=${requirement}`,
658
+ requirement,
659
+ message: message$1,
660
+ "~run"(dataset, config$1) {
661
+ if (dataset.typed && dataset.value.length < this.requirement) _addIssue(this, "length", dataset, config$1, { received: `${dataset.value.length}` });
662
+ return dataset;
663
+ }
664
+ };
665
+ }
666
+ // @__NO_SIDE_EFFECTS__
667
+ function minValue(requirement, message$1) {
668
+ return {
669
+ kind: "validation",
670
+ type: "min_value",
671
+ reference: minValue,
672
+ async: false,
673
+ expects: `>=${requirement instanceof Date ? requirement.toJSON() : /* @__PURE__ */ _stringify(requirement)}`,
674
+ requirement,
675
+ message: message$1,
676
+ "~run"(dataset, config$1) {
677
+ if (dataset.typed && !(dataset.value >= this.requirement)) _addIssue(this, "value", dataset, config$1, { received: dataset.value instanceof Date ? dataset.value.toJSON() : /* @__PURE__ */ _stringify(dataset.value) });
678
+ return dataset;
679
+ }
680
+ };
681
+ }
682
+ // @__NO_SIDE_EFFECTS__
683
+ function getFallback(schema6, dataset, config$1) {
684
+ return typeof schema6.fallback === "function" ? schema6.fallback(dataset, config$1) : schema6.fallback;
685
+ }
686
+ // @__NO_SIDE_EFFECTS__
687
+ function getDefault(schema6, dataset, config$1) {
688
+ return typeof schema6.default === "function" ? schema6.default(dataset, config$1) : schema6.default;
689
+ }
690
+ // @__NO_SIDE_EFFECTS__
691
+ function number(message$1) {
692
+ return {
693
+ kind: "schema",
694
+ type: "number",
695
+ reference: number,
696
+ expects: "number",
697
+ async: false,
698
+ message: message$1,
699
+ get "~standard"() {
700
+ return /* @__PURE__ */ _getStandardProps(this);
701
+ },
702
+ "~run"(dataset, config$1) {
703
+ if (typeof dataset.value === "number" && !isNaN(dataset.value)) dataset.typed = true;
704
+ else _addIssue(this, "type", dataset, config$1);
705
+ return dataset;
706
+ }
707
+ };
708
+ }
709
+ // @__NO_SIDE_EFFECTS__
710
+ function object(entries$1, message$1) {
711
+ return {
712
+ kind: "schema",
713
+ type: "object",
714
+ reference: object,
715
+ expects: "Object",
716
+ async: false,
717
+ entries: entries$1,
718
+ message: message$1,
719
+ get "~standard"() {
720
+ return /* @__PURE__ */ _getStandardProps(this);
721
+ },
722
+ "~run"(dataset, config$1) {
723
+ const input = dataset.value;
724
+ if (input && typeof input === "object") {
725
+ dataset.typed = true;
726
+ dataset.value = {};
727
+ for (const key in this.entries) {
728
+ const valueSchema = this.entries[key];
729
+ if (key in input || (valueSchema.type === "exact_optional" || valueSchema.type === "optional" || valueSchema.type === "nullish") && valueSchema.default !== void 0) {
730
+ const value$1 = key in input ? input[key] : /* @__PURE__ */ getDefault(valueSchema);
731
+ const valueDataset = valueSchema["~run"]({ value: value$1 }, config$1);
732
+ if (valueDataset.issues) {
733
+ const pathItem = {
734
+ type: "object",
735
+ origin: "value",
736
+ input,
737
+ key,
738
+ value: value$1
739
+ };
740
+ for (const issue of valueDataset.issues) {
741
+ if (issue.path) issue.path.unshift(pathItem);
742
+ else issue.path = [pathItem];
743
+ dataset.issues?.push(issue);
744
+ }
745
+ if (!dataset.issues) dataset.issues = valueDataset.issues;
746
+ if (config$1.abortEarly) {
747
+ dataset.typed = false;
748
+ break;
749
+ }
750
+ }
751
+ if (!valueDataset.typed) dataset.typed = false;
752
+ dataset.value[key] = valueDataset.value;
753
+ } else if (valueSchema.fallback !== void 0) dataset.value[key] = /* @__PURE__ */ getFallback(valueSchema);
754
+ else if (valueSchema.type !== "exact_optional" && valueSchema.type !== "optional" && valueSchema.type !== "nullish") {
755
+ _addIssue(this, "key", dataset, config$1, {
756
+ input: void 0,
757
+ expected: `"${key}"`,
758
+ path: [{
759
+ type: "object",
760
+ origin: "key",
761
+ input,
762
+ key,
763
+ value: input[key]
764
+ }]
765
+ });
766
+ if (config$1.abortEarly) break;
767
+ }
768
+ }
769
+ } else _addIssue(this, "type", dataset, config$1);
770
+ return dataset;
771
+ }
772
+ };
773
+ }
774
+ // @__NO_SIDE_EFFECTS__
775
+ function optional(wrapped, default_) {
776
+ return {
777
+ kind: "schema",
778
+ type: "optional",
779
+ reference: optional,
780
+ expects: `(${wrapped.expects} | undefined)`,
781
+ async: false,
782
+ wrapped,
783
+ default: default_,
784
+ get "~standard"() {
785
+ return /* @__PURE__ */ _getStandardProps(this);
786
+ },
787
+ "~run"(dataset, config$1) {
788
+ if (dataset.value === void 0) {
789
+ if (this.default !== void 0) dataset.value = /* @__PURE__ */ getDefault(this, dataset, config$1);
790
+ if (dataset.value === void 0) {
791
+ dataset.typed = true;
792
+ return dataset;
793
+ }
794
+ }
795
+ return this.wrapped["~run"](dataset, config$1);
796
+ }
797
+ };
798
+ }
799
+ // @__NO_SIDE_EFFECTS__
800
+ function picklist(options, message$1) {
801
+ return {
802
+ kind: "schema",
803
+ type: "picklist",
804
+ reference: picklist,
805
+ expects: /* @__PURE__ */ _joinExpects(options.map(_stringify), "|"),
806
+ async: false,
807
+ options,
808
+ message: message$1,
809
+ get "~standard"() {
810
+ return /* @__PURE__ */ _getStandardProps(this);
811
+ },
812
+ "~run"(dataset, config$1) {
813
+ if (this.options.includes(dataset.value)) dataset.typed = true;
814
+ else _addIssue(this, "type", dataset, config$1);
815
+ return dataset;
816
+ }
817
+ };
818
+ }
819
+ // @__NO_SIDE_EFFECTS__
820
+ function string(message$1) {
821
+ return {
822
+ kind: "schema",
823
+ type: "string",
824
+ reference: string,
825
+ expects: "string",
826
+ async: false,
827
+ message: message$1,
828
+ get "~standard"() {
829
+ return /* @__PURE__ */ _getStandardProps(this);
830
+ },
831
+ "~run"(dataset, config$1) {
832
+ if (typeof dataset.value === "string") dataset.typed = true;
833
+ else _addIssue(this, "type", dataset, config$1);
834
+ return dataset;
835
+ }
836
+ };
837
+ }
838
+ // @__NO_SIDE_EFFECTS__
839
+ function pipe(...pipe$1) {
840
+ return {
841
+ ...pipe$1[0],
842
+ pipe: pipe$1,
843
+ get "~standard"() {
844
+ return /* @__PURE__ */ _getStandardProps(this);
845
+ },
846
+ "~run"(dataset, config$1) {
847
+ for (const item of pipe$1) if (item.kind !== "metadata") {
848
+ if (dataset.issues && (item.kind === "schema" || item.kind === "transformation")) {
849
+ dataset.typed = false;
850
+ break;
851
+ }
852
+ if (!dataset.issues || !config$1.abortEarly && !config$1.abortPipeEarly) dataset = item["~run"](dataset, config$1);
853
+ }
854
+ return dataset;
855
+ }
856
+ };
857
+ }
858
+
859
+ // ../mcp-server/src/mcp/handlers/tools/list-components.ts
860
+ import { tool } from "tmcp/utils";
861
+
862
+ // ../mcp-server/src/constants.ts
863
+ import { resolve } from "path";
864
+ import { fileURLToPath } from "url";
865
+ var PKG_DIR = fileURLToPath(new URL("..", import.meta.url));
866
+ var ALUS_ROOT = process.env.ALUS_ROOT ?? resolve(PKG_DIR, "../..");
867
+ var COMPONENTS_DIR = `${ALUS_ROOT}/packages/alus/src/lib/components`;
868
+ var ROUTES_DIR = `${ALUS_ROOT}/src/routes/components`;
869
+ var UTILS_ROOT = `${ALUS_ROOT}/packages/alus/src/lib/utils`;
870
+ var CHARACTER_LIMIT = 25e3;
871
+ var CATEGORIES = [
872
+ "form",
873
+ "navigation",
874
+ "feedback",
875
+ "display",
876
+ "overlay",
877
+ "layout",
878
+ "interactive",
879
+ "utility"
880
+ ];
881
+
882
+ // ../mcp-server/src/lib/fs.ts
883
+ import { readdir, readFile } from "fs/promises";
884
+ async function list_all_components() {
885
+ const entries = [];
886
+ for (const category of CATEGORIES) {
887
+ const cat_dir = `${COMPONENTS_DIR}/${category}`;
888
+ let items;
889
+ try {
890
+ items = await readdir(cat_dir);
891
+ } catch {
892
+ continue;
893
+ }
894
+ for (const item of items) {
895
+ const comp_dir = `${cat_dir}/${item}`;
896
+ let files;
897
+ try {
898
+ files = await readdir(comp_dir);
899
+ } catch {
900
+ continue;
901
+ }
902
+ const source_files = files.filter((f) => f.endsWith(".svelte") || f.endsWith(".ts"));
903
+ if (!source_files.length) continue;
904
+ const name = item.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
905
+ entries.push({ name, category, dir: comp_dir, files: source_files });
906
+ }
907
+ }
908
+ return entries;
909
+ }
910
+ async function read_component_source(entry) {
911
+ const parts = [];
912
+ for (const file of entry.files) {
913
+ const content = await readFile(`${entry.dir}/${file}`, "utf-8");
914
+ parts.push(`// FILE: ${file}
915
+ ${content}`);
916
+ }
917
+ return parts.join("\n\n");
918
+ }
919
+ function truncate(text, hint) {
920
+ if (text.length <= CHARACTER_LIMIT) return text;
921
+ return text.slice(0, CHARACTER_LIMIT) + `
922
+
923
+ [... truncated. ${hint}]`;
924
+ }
925
+
926
+ // ../mcp-server/src/mcp/handlers/tools/list-components.ts
927
+ var schema = object({
928
+ category: optional(
929
+ picklist(CATEGORIES, "Must be one of the alus-ui component categories")
930
+ ),
931
+ response_format: optional(picklist(["markdown", "json"]), "markdown")
932
+ });
933
+ async function list_components_handler(params) {
934
+ const { category, response_format = "markdown" } = params;
935
+ const all = await list_all_components();
936
+ const filtered = category ? all.filter((c) => c.category === category) : all;
937
+ if (response_format === "json") {
938
+ return JSON.stringify(
939
+ {
940
+ total: filtered.length,
941
+ components: filtered.map((c) => ({
942
+ name: c.name,
943
+ category: c.category,
944
+ dir: c.dir.replace(`${COMPONENTS_DIR}/`, "")
945
+ }))
946
+ },
947
+ null,
948
+ 2
949
+ );
950
+ }
951
+ const grouped = {};
952
+ for (const c of filtered) {
953
+ (grouped[c.category] ??= []).push(c.name);
954
+ }
955
+ const lines = [`# alus-ui Components (${filtered.length} total)`, ""];
956
+ for (const [cat, names] of Object.entries(grouped)) {
957
+ lines.push(`## ${cat}`, "", names.map((n) => `- ${n}`).join("\n"), "");
958
+ }
959
+ return lines.join("\n");
960
+ }
961
+ function list_components(server2) {
962
+ server2.tool(
963
+ {
964
+ name: "alus_list_components",
965
+ description: "List all components in the alus-ui Svelte 5 library grouped by category. Call this first to discover component names before using alus_get_component. Optionally filter by category.",
966
+ schema,
967
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
968
+ },
969
+ async (params) => {
970
+ try {
971
+ return tool.text(await list_components_handler(params));
972
+ } catch (e) {
973
+ return tool.error(e.message);
974
+ }
975
+ }
976
+ );
977
+ }
978
+
979
+ // ../mcp-server/src/mcp/handlers/tools/get-component.ts
980
+ import { tool as tool2 } from "tmcp/utils";
981
+ var schema2 = object({
982
+ name: pipe(
983
+ string(),
984
+ description("Component name, case-insensitive (e.g. 'Button', 'accordion', 'date-picker')")
985
+ ),
986
+ category: optional(picklist(CATEGORIES, "Narrow search when name is ambiguous"))
987
+ });
988
+ function get_component(server2) {
989
+ server2.tool(
990
+ {
991
+ name: "alus_get_component",
992
+ description: "Read the full source of an alus-ui component (.svelte + index.ts). Use alus_list_components first to find valid names. Supports partial, case-insensitive matching (e.g. 'button', 'Button', 'date-picker').",
993
+ schema: schema2,
994
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
995
+ },
996
+ async ({ name, category }) => {
997
+ try {
998
+ const all = await list_all_components();
999
+ const needle = name.toLowerCase().replace(/[-_\s]/g, "");
1000
+ let matches = all.filter(
1001
+ (c) => c.name.toLowerCase().replace(/[-_\s]/g, "") === needle
1002
+ );
1003
+ if (category) matches = matches.filter((c) => c.category === category);
1004
+ if (!matches.length) {
1005
+ const similar = all.filter(
1006
+ (c) => c.name.toLowerCase().includes(needle) || needle.includes(c.name.toLowerCase())
1007
+ ).map((c) => `${c.name} (${c.category})`).slice(0, 5).join(", ");
1008
+ return tool2.text(
1009
+ `Component '${name}' not found.${similar ? ` Similar: ${similar}` : " Use alus_list_components to browse."}`
1010
+ );
1011
+ }
1012
+ const entry = matches[0];
1013
+ const src = await read_component_source(entry);
1014
+ return tool2.text(
1015
+ truncate(
1016
+ `# ${entry.name} (${entry.category})
1017
+
1018
+ ${src}`,
1019
+ "Use alus_search_components for targeted lookup."
1020
+ )
1021
+ );
1022
+ } catch (e) {
1023
+ return tool2.error(e.message);
1024
+ }
1025
+ }
1026
+ );
1027
+ }
1028
+
1029
+ // ../mcp-server/src/mcp/handlers/tools/search-components.ts
1030
+ import { tool as tool3 } from "tmcp/utils";
1031
+ import { readFile as readFile2 } from "fs/promises";
1032
+ var schema3 = object({
1033
+ query: pipe(string(), minLength(2), description("Case-insensitive search string")),
1034
+ category: optional(picklist(CATEGORIES)),
1035
+ limit: optional(pipe(number(), integer(), minValue(1), maxValue(50)), 20),
1036
+ response_format: optional(picklist(["markdown", "json"]), "markdown")
1037
+ });
1038
+ function search_components(server2) {
1039
+ server2.tool(
1040
+ {
1041
+ name: "alus_search_components",
1042
+ description: "Full-text search across all alus-ui component source files. Useful for finding which component uses a specific prop, ARIA pattern, utility function, or type. Returns matches with \xB12 lines of context.",
1043
+ schema: schema3,
1044
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
1045
+ },
1046
+ async ({ query, category, limit = 20, response_format = "markdown" }) => {
1047
+ try {
1048
+ const all = await list_all_components();
1049
+ const pool = category ? all.filter((c) => c.category === category) : all;
1050
+ const needle = query.toLowerCase();
1051
+ const hits = [];
1052
+ for (const entry of pool) {
1053
+ if (hits.length >= limit) break;
1054
+ for (const file of entry.files) {
1055
+ if (hits.length >= limit) break;
1056
+ const content = await readFile2(`${entry.dir}/${file}`, "utf-8");
1057
+ const lines2 = content.split("\n");
1058
+ for (let i = 0; i < lines2.length; i++) {
1059
+ if (lines2[i].toLowerCase().includes(needle)) {
1060
+ const start = Math.max(0, i - 2);
1061
+ const end = Math.min(lines2.length - 1, i + 2);
1062
+ hits.push({
1063
+ component: entry.name,
1064
+ category: entry.category,
1065
+ file,
1066
+ line: i + 1,
1067
+ context: lines2.slice(start, end + 1).join("\n")
1068
+ });
1069
+ if (hits.length >= limit) break;
1070
+ }
1071
+ }
1072
+ }
1073
+ }
1074
+ if (!hits.length) return tool3.text(`No results for '${query}'.`);
1075
+ if (response_format === "json") {
1076
+ return tool3.text(JSON.stringify({ query, total: hits.length, hits }, null, 2));
1077
+ }
1078
+ const lines = [`# Search: '${query}' \u2014 ${hits.length} hit(s)`, ""];
1079
+ for (const h of hits) {
1080
+ lines.push(
1081
+ `## ${h.component} (${h.category}) \xB7 ${h.file}:${h.line}`,
1082
+ "```svelte",
1083
+ h.context,
1084
+ "```",
1085
+ ""
1086
+ );
1087
+ }
1088
+ return tool3.text(truncate(lines.join("\n"), "Narrow with category or a more specific query."));
1089
+ } catch (e) {
1090
+ return tool3.error(e.message);
1091
+ }
1092
+ }
1093
+ );
1094
+ }
1095
+
1096
+ // ../mcp-server/src/mcp/handlers/tools/get-component-demo.ts
1097
+ import { tool as tool4 } from "tmcp/utils";
1098
+ import { readFile as readFile3, readdir as readdir2 } from "fs/promises";
1099
+ var schema4 = object({
1100
+ name: pipe(
1101
+ string(),
1102
+ description("Component route folder name, lowercase hyphenated (e.g. 'button', 'date-picker')")
1103
+ )
1104
+ });
1105
+ function get_component_demo(server2) {
1106
+ server2.tool(
1107
+ {
1108
+ name: "alus_get_component_demo",
1109
+ description: "Read the SvelteKit showcase demo page for a component. Shows real usage with props, events, and the Japanese Creative aesthetic. Path: src/routes/components/{name}/+page.svelte.",
1110
+ schema: schema4,
1111
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
1112
+ },
1113
+ async ({ name }) => {
1114
+ try {
1115
+ const demo_path = `${ROUTES_DIR}/${name.toLowerCase()}/+page.svelte`;
1116
+ let content;
1117
+ try {
1118
+ content = await readFile3(demo_path, "utf-8");
1119
+ } catch {
1120
+ let available = [];
1121
+ try {
1122
+ available = await readdir2(ROUTES_DIR);
1123
+ } catch {
1124
+ }
1125
+ const hint = available.length ? ` Available: ${available.slice(0, 10).join(", ")}${available.length > 10 ? "\u2026" : ""}` : "";
1126
+ return tool4.text(`Demo not found for '${name}'.${hint}`);
1127
+ }
1128
+ return tool4.text(
1129
+ truncate(
1130
+ `# Demo: ${name}
1131
+ \`\`\`svelte
1132
+ ${content}
1133
+ \`\`\``,
1134
+ "Use alus_get_component for source."
1135
+ )
1136
+ );
1137
+ } catch (e) {
1138
+ return tool4.error(e.message);
1139
+ }
1140
+ }
1141
+ );
1142
+ }
1143
+
1144
+ // ../mcp-server/src/mcp/handlers/tools/list-exports.ts
1145
+ import { tool as tool5 } from "tmcp/utils";
1146
+ import { readFile as readFile4 } from "fs/promises";
1147
+ function list_exports(server2) {
1148
+ server2.tool(
1149
+ {
1150
+ name: "alus_list_exports",
1151
+ description: "Return the full contents of packages/alus/src/lib/components/index.ts \u2014 the canonical public API of alus-ui with exact import paths, exported types, and context helpers.",
1152
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
1153
+ },
1154
+ async () => {
1155
+ try {
1156
+ const content = await readFile4(`${COMPONENTS_DIR}/index.ts`, "utf-8");
1157
+ return tool5.text(`\`\`\`typescript
1158
+ ${content}
1159
+ \`\`\``);
1160
+ } catch (e) {
1161
+ return tool5.error(e.message);
1162
+ }
1163
+ }
1164
+ );
1165
+ }
1166
+
1167
+ // ../mcp-server/src/mcp/handlers/tools/get-utils.ts
1168
+ import { tool as tool6 } from "tmcp/utils";
1169
+ import { readFile as readFile5 } from "fs/promises";
1170
+ var MODULES = ["aria", "focus", "id", "keyboard", "index", "form/state"];
1171
+ var schema5 = object({
1172
+ module: picklist(MODULES, "Utility module \u2014 one of: aria, focus, id, keyboard, index, form/state")
1173
+ });
1174
+ function get_utils(server2) {
1175
+ server2.tool(
1176
+ {
1177
+ name: "alus_get_utils",
1178
+ description: "Read source of an alus-ui utility module (a11y helpers, form state). Available: aria, focus, id, keyboard, index, form/state.",
1179
+ schema: schema5,
1180
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
1181
+ },
1182
+ async ({ module }) => {
1183
+ try {
1184
+ const path = module === "index" ? `${UTILS_ROOT}/a11y/index.ts` : module === "form/state" ? `${UTILS_ROOT}/form/state.ts` : `${UTILS_ROOT}/a11y/${module}.ts`;
1185
+ const content = await readFile5(path, "utf-8");
1186
+ return tool6.text(`\`\`\`typescript
1187
+ ${content}
1188
+ \`\`\``);
1189
+ } catch (e) {
1190
+ return tool6.error(e.message);
1191
+ }
1192
+ }
1193
+ );
1194
+ }
1195
+
1196
+ // ../mcp-server/src/mcp/handlers/index.ts
1197
+ function setup_tools(server2) {
1198
+ for (const tool7 in tools_exports) {
1199
+ tools_exports[tool7](server2);
1200
+ }
1201
+ }
1202
+
1203
+ // ../mcp-server/src/mcp/index.ts
1204
+ var server = new McpServer(
1205
+ {
1206
+ name: "alus-ui MCP",
1207
+ version: "0.0.1",
1208
+ description: "MCP server for the alus-ui Svelte 5 component library"
1209
+ },
1210
+ {
1211
+ adapter: new ValibotJsonSchemaAdapter(),
1212
+ capabilities: { tools: {} },
1213
+ instructions: "This MCP server provides direct access to alus-ui \u2014 an unstyled, accessible Svelte 5 component library. Use it to browse components, read source, search patterns, and find usage examples. Always call alus_list_components first to discover available components."
1214
+ }
1215
+ ).withContext();
1216
+ setup_tools(server);
1217
+
1218
+ // src/index.ts
1219
+ import { StdioTransport } from "@tmcp/transport-stdio";
1220
+ var transport = new StdioTransport(server);
1221
+ transport.listen();
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "alus-ui-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP stdio server for the alus-ui Svelte 5 component library — gives LLMs direct access to component source, demos, exports, and utilities",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "author": {
8
+ "name": "Hanivan Rizky",
9
+ "email": "hanivan20@gmail.com"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/Hanivan/alus.git"
14
+ },
15
+ "homepage": "https://github.com/Hanivan/alus#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/Hanivan/alus/issues"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "model-context-protocol",
22
+ "svelte",
23
+ "svelte5",
24
+ "ui-components",
25
+ "alus-ui",
26
+ "llm",
27
+ "claude",
28
+ "cursor",
29
+ "ai"
30
+ ],
31
+ "bin": {
32
+ "alus-mcp": "./dist/index.js"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "!dist/**/*.test.*",
37
+ "!dist/**/*.spec.*"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev:build": "tsup --watch",
42
+ "dev": "tsx watch src/index.ts",
43
+ "start": "tsx src/index.ts",
44
+ "prepublishOnly": "npm run build",
45
+ "release": "release-it",
46
+ "release:dry": "release-it --dry-run",
47
+ "release:patch": "release-it patch",
48
+ "release:minor": "release-it minor",
49
+ "release:major": "release-it major"
50
+ },
51
+ "dependencies": {
52
+ "@alus-ui/mcp-server": "workspace:*",
53
+ "@tmcp/transport-stdio": "latest",
54
+ "tmcp": "latest"
55
+ },
56
+ "devDependencies": {
57
+ "@release-it/conventional-changelog": "latest",
58
+ "publint": "latest",
59
+ "release-it": "latest",
60
+ "tsup": "latest",
61
+ "tsx": "latest",
62
+ "typescript": "^6.0.2"
63
+ },
64
+ "publishConfig": {
65
+ "access": "public"
66
+ },
67
+ "engines": {
68
+ "node": ">=18.0.0",
69
+ "pnpm": ">=8.0.0"
70
+ }
71
+ }