@mosvera/mcp 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ deterministic provider payloads that other tools can consume.
18
18
 
19
19
  The easiest path for non-command-line users is the Mosvera MCP Bundle:
20
20
 
21
- 1. Download `mosvera-mcp-0.1.2.mcpb` from the latest
21
+ 1. Download `mosvera-mcp-0.1.4.mcpb` from the latest
22
22
  [GitHub release](https://github.com/mosvera/mcp/releases).
23
23
  2. Double-click the file, drag it into Claude Desktop, or install it from
24
24
  Claude Desktop Settings → Extensions → Advanced settings → Install
@@ -38,6 +38,21 @@ On first run, Mosvera seeds four public demo aesthetics into the registry:
38
38
  `quiet-editorial`, `technical-manual`, `cinematic-lab`, and
39
39
  `claymation-playful-builder`.
40
40
 
41
+ ## Language
42
+
43
+ Mosvera uses a small term stack on purpose:
44
+
45
+ - A **named aesthetic** is the user-facing intent, like
46
+ `executive-editorial`.
47
+ - A **composition document** is the technical Mosvera document that resolves
48
+ that intent.
49
+ - An **aesthetic pack** is a portable `.mosvera.json` file for sharing a named
50
+ aesthetic and its registry dependencies.
51
+ - A **local registry** is the folder where your templates, palettes,
52
+ modifiers, composition documents, manifests, and merge strategies live.
53
+ - **Tokens** and provider **payloads** are compiled outputs for other tools to
54
+ consume.
55
+
41
56
  ## Install With npm
42
57
 
43
58
  Use npm when you are wiring Mosvera into another MCP host or a developer
@@ -83,6 +98,14 @@ Resolve the claymation-playful-builder aesthetic and show me the canonical model
83
98
  Compile quiet-editorial into CSS variables.
84
99
  ```
85
100
 
101
+ ```text
102
+ Export quiet-editorial as an aesthetic pack.
103
+ ```
104
+
105
+ ```text
106
+ Preview importing this aesthetic pack into my registry.
107
+ ```
108
+
86
109
  ```text
87
110
  Save a new aesthetic called executive-editorial based on quiet-editorial-base with a more compact, board-ready voice.
88
111
  ```
@@ -102,6 +125,9 @@ flows.
102
125
  | `get_registry_document` | Read | Fetch a template, modifier, palette, composition, or capability manifest. |
103
126
  | `validate_document` | Read | Validate one document against a Mosvera schema kind. |
104
127
  | `validate_registry` | Read | Validate the active registry and return diagnostics. |
128
+ | `validate_aesthetic_pack` | Read | Validate an inline or local `.mosvera.json` aesthetic pack. |
129
+ | `preview_aesthetic_import` | Read | Preview importing an aesthetic pack without writing files. |
130
+ | `export_aesthetic_pack` | Read | Export a named aesthetic as a portable `.mosvera.json` pack. |
105
131
  | `resolve_aesthetic` | Read | Resolve a named or inline aesthetic into canonical Mosvera JSON. |
106
132
  | `compile_design_tokens` | Read | Compile canonical output into portable design tokens and CSS variables. |
107
133
  | `compile_provider_payload` | Read | Advanced deterministic provider payload compilation; no provider HTTP call. |
@@ -110,6 +136,7 @@ flows.
110
136
  | `save_registry_document` | Write | Advanced create/update for registry documents and manifests. |
111
137
  | `delete_registry_document` | Destructive write | Delete a registry document. |
112
138
  | `write_merge_strategies` | Write | Replace `merge-strategies.json` with deterministic JSON. |
139
+ | `import_aesthetic_pack` | Write | Import an aesthetic pack into the active local registry. |
113
140
 
114
141
  When the server starts with `--read-only`, write tools are not registered.
115
142
 
@@ -126,6 +153,11 @@ manifests/<provider>.manifest.json
126
153
  merge-strategies.json
127
154
  ```
128
155
 
156
+ Aesthetic packs are exchanged as separate `.mosvera.json` files. They can carry
157
+ templates, palettes, modifiers, composition documents, and merge strategies.
158
+ They do not carry assets, provider manifests, credentials, remote URLs, or zip
159
+ bundles in v1.
160
+
129
161
  IDs must be safe Mosvera references: lowercase letters, numbers, `_`, and `-`,
130
162
  starting with a letter. Absolute paths, dotfiles, path traversal, unknown
131
163
  kinds, and unsafe filenames are rejected.
@@ -144,7 +176,7 @@ npm run mcpb:inspect
144
176
  The MCPB pack step creates:
145
177
 
146
178
  ```text
147
- build/mosvera/mosvera-mcp-0.1.2.mcpb
179
+ build/mosvera/mosvera-mcp-0.1.4.mcpb
148
180
  ```
149
181
 
150
182
  ## Package Boundaries
package/dist/context.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type LoadedProject, type RegistryDiagnostic, type Validator } from "@mosvera/runtime";
2
2
  import type { ToolContext } from "./types.ts";
3
- export declare const SERVER_VERSION = "0.1.2";
3
+ export declare const SERVER_VERSION = "0.1.4";
4
4
  export interface CliOptions {
5
5
  registryDir?: string;
6
6
  readOnlyMode: boolean;
package/dist/context.js CHANGED
@@ -12,7 +12,7 @@ import { loadProject, RegistryProjectError } from "@mosvera/runtime/node";
12
12
  import { fluxAdapter } from "@mosvera/provider-flux";
13
13
  import { openaiAdapter } from "@mosvera/provider-openai";
14
14
  import { sdxlAdapter } from "@mosvera/provider-sdxl";
15
- export const SERVER_VERSION = "0.1.2";
15
+ export const SERVER_VERSION = "0.1.4";
16
16
  function flagValue(argv, name) {
17
17
  const direct = argv.find((arg) => arg.startsWith(`${name}=`));
18
18
  if (direct !== undefined)
package/dist/server.js CHANGED
@@ -10,8 +10,12 @@ import { realpathSync } from "node:fs";
10
10
  import { fileURLToPath } from "node:url";
11
11
  import { z } from "zod";
12
12
  import { buildContext, parseCliOptions, SERVER_VERSION } from "./context.js";
13
- import { documentKinds, runCompileDesignTokens, runCompileProviderPayload, runDeleteRegistryDocument, runDraftAesthetic, runGetRegistryDocument, runListAesthetics, runResolveAesthetic, runSaveAesthetic, runSaveRegistryDocument, runServerStatus, runValidateDocument, runValidateRegistry, runWriteMergeStrategies, } from "./tools/aesthetic.js";
13
+ import { documentKinds, runCompileDesignTokens, runCompileProviderPayload, runDeleteRegistryDocument, runDraftAesthetic, runExportAestheticPack, runGetRegistryDocument, runImportAestheticPack, runListAesthetics, runPreviewAestheticImport, runResolveAesthetic, runSaveAesthetic, runSaveRegistryDocument, runServerStatus, runValidateAestheticPack, runValidateDocument, runValidateRegistry, runWriteMergeStrategies, } from "./tools/aesthetic.js";
14
14
  const docArg = z.union([z.string(), z.record(z.any())]);
15
+ const packSourceArg = {
16
+ pack: docArg.optional(),
17
+ path: z.string().optional(),
18
+ };
15
19
  const strategiesArg = z.record(z.object({
16
20
  strategy: z.enum(["replace", "append", "merge_by"]),
17
21
  key: z.string().optional(),
@@ -19,6 +23,8 @@ const strategiesArg = z.record(z.object({
19
23
  const criticalityArg = z.record(z.enum(["required", "optional"]));
20
24
  const documentKindArg = z.enum(documentKinds);
21
25
  const registryDocumentKindArg = z.enum(documentKinds);
26
+ const packConflictArg = z.enum(["auto_rename", "fail", "replace"]);
27
+ const packStrategyConflictArg = z.enum(["fail", "replace"]);
22
28
  const outputSchema = z.object({ ok: z.boolean(), message: z.string() }).passthrough();
23
29
  const readAnnotations = {
24
30
  readOnlyHint: true,
@@ -79,6 +85,36 @@ export function createServer(ctx) {
79
85
  outputSchema,
80
86
  annotations: readAnnotations,
81
87
  }, async () => runValidateRegistry(ctx));
88
+ server.registerTool("validate_aesthetic_pack", {
89
+ title: "Validate Aesthetic Pack",
90
+ description: "Validate an inline or local .mosvera.json aesthetic pack.",
91
+ inputSchema: packSourceArg,
92
+ outputSchema,
93
+ annotations: readAnnotations,
94
+ }, async (args) => runValidateAestheticPack(ctx, args));
95
+ server.registerTool("preview_aesthetic_import", {
96
+ title: "Preview Aesthetic Import",
97
+ description: "Preview importing an aesthetic pack into the active local registry without writing files.",
98
+ inputSchema: {
99
+ ...packSourceArg,
100
+ conflict_strategy: packConflictArg.optional(),
101
+ strategy_conflict: packStrategyConflictArg.optional(),
102
+ },
103
+ outputSchema,
104
+ annotations: readAnnotations,
105
+ }, async (args) => runPreviewAestheticImport(ctx, args));
106
+ server.registerTool("export_aesthetic_pack", {
107
+ title: "Export Aesthetic Pack",
108
+ description: "Export a named aesthetic and its registry dependencies as a portable .mosvera.json pack.",
109
+ inputSchema: {
110
+ aesthetic: z.string(),
111
+ id: z.string().optional(),
112
+ name: z.string().optional(),
113
+ description: z.string().optional(),
114
+ },
115
+ outputSchema,
116
+ annotations: readAnnotations,
117
+ }, async (args) => runExportAestheticPack(ctx, args));
82
118
  server.registerTool("resolve_aesthetic", {
83
119
  title: "Resolve Aesthetic",
84
120
  description: "Resolve a named or inline aesthetic composition into the canonical Mosvera model.",
@@ -157,6 +193,17 @@ export function createServer(ctx) {
157
193
  outputSchema,
158
194
  annotations: writeAnnotations,
159
195
  }, async (args) => runWriteMergeStrategies(ctx, args));
196
+ server.registerTool("import_aesthetic_pack", {
197
+ title: "Import Aesthetic Pack",
198
+ description: "Import an inline or local .mosvera.json aesthetic pack into the active local registry.",
199
+ inputSchema: {
200
+ ...packSourceArg,
201
+ conflict_strategy: packConflictArg.optional(),
202
+ strategy_conflict: packStrategyConflictArg.optional(),
203
+ },
204
+ outputSchema,
205
+ annotations: writeAnnotations,
206
+ }, async (args) => runImportAestheticPack(ctx, args));
160
207
  }
161
208
  return server;
162
209
  }
@@ -1,4 +1,4 @@
1
- import { type Criticality, type DocumentKind, type MergeStrategies, type RegistryKind } from "@mosvera/runtime";
1
+ import { type AestheticPackConflictStrategy, type AestheticPackStrategyConflict, type Criticality, type DocumentKind, type MergeStrategies, type RegistryKind } from "@mosvera/runtime";
2
2
  import type { ToolContext, ToolErrorCode } from "../types.ts";
3
3
  import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
4
4
  export declare const registryKinds: readonly ["template", "modifier", "palette", "composition"];
@@ -14,6 +14,22 @@ export declare function runValidateDocument(ctx: ToolContext, args: {
14
14
  kind: DocumentKind;
15
15
  }): CallToolResult;
16
16
  export declare function runValidateRegistry(ctx: ToolContext): CallToolResult;
17
+ export declare function runValidateAestheticPack(ctx: ToolContext, args: {
18
+ pack?: object | string;
19
+ path?: string;
20
+ }): CallToolResult;
21
+ export declare function runPreviewAestheticImport(ctx: ToolContext, args: {
22
+ pack?: object | string;
23
+ path?: string;
24
+ conflict_strategy?: AestheticPackConflictStrategy;
25
+ strategy_conflict?: AestheticPackStrategyConflict;
26
+ }): CallToolResult;
27
+ export declare function runExportAestheticPack(ctx: ToolContext, args: {
28
+ aesthetic: string;
29
+ id?: string;
30
+ name?: string;
31
+ description?: string;
32
+ }): CallToolResult;
17
33
  export declare function runResolveAesthetic(ctx: ToolContext, args: {
18
34
  aesthetic: string | object;
19
35
  merge_strategies?: MergeStrategies;
@@ -54,4 +70,10 @@ export declare function runDeleteRegistryDocument(ctx: ToolContext, args: {
54
70
  export declare function runWriteMergeStrategies(ctx: ToolContext, args: {
55
71
  merge_strategies: MergeStrategies;
56
72
  }): CallToolResult;
73
+ export declare function runImportAestheticPack(ctx: ToolContext, args: {
74
+ pack?: object | string;
75
+ path?: string;
76
+ conflict_strategy?: AestheticPackConflictStrategy;
77
+ strategy_conflict?: AestheticPackStrategyConflict;
78
+ }): CallToolResult;
57
79
  export declare function errorCodeFromResult(result: CallToolResult): ToolErrorCode | undefined;
@@ -3,15 +3,18 @@
3
3
  // User-facing Mosvera MCP tools. These handlers keep the MCP layer thin:
4
4
  // parse/validate inputs, call @mosvera/runtime, persist through the Node
5
5
  // boundary where needed, and return MCP-native structured results.
6
- import { compile, compileDesignTokens, composeStrategies, createComposition, getRegistryDocument, listRegistryEntries, parse, resolveAesthetic, toCssVariables, } from "@mosvera/runtime";
6
+ import { compile, compileDesignTokens, composeStrategies, createComposition, exportAestheticPack, getRegistryDocument, importAestheticPack, listRegistryEntries, parse, previewAestheticPackImport, resolveAesthetic, toCssVariables, validateAestheticPack, } from "@mosvera/runtime";
7
7
  import { deleteProjectDocument, RegistryProjectError, saveProjectDocument, writeMergeStrategies } from "@mosvera/runtime/node";
8
8
  import { EmissionError } from "@mosvera/provider-base";
9
+ import { readFileSync } from "node:fs";
10
+ import { basename } from "node:path";
9
11
  import { registryDiagnostics, reloadContext, SERVER_VERSION } from "../context.js";
10
12
  import { fail, ok } from "../mcp-result.js";
11
13
  import { deleteCapabilityManifest, ProjectWriteError, saveCapabilityManifest } from "../project-writes.js";
12
14
  import { isResolutionError, mapResolutionError } from "../errors.js";
13
15
  export const registryKinds = ["template", "modifier", "palette", "composition"];
14
16
  export const documentKinds = ["template", "modifier", "palette", "composition", "capability-manifest"];
17
+ const PACK_EXT = /\.mosvera\.json$/i;
15
18
  function parseDocument(source) {
16
19
  try {
17
20
  return parse(source);
@@ -23,6 +26,63 @@ function parseDocument(source) {
23
26
  };
24
27
  }
25
28
  }
29
+ function stable(value) {
30
+ if (Array.isArray(value))
31
+ return value.map(stable);
32
+ if (value !== null && typeof value === "object") {
33
+ const out = {};
34
+ for (const [key, child] of Object.entries(value).sort(([a], [b]) => a.localeCompare(b))) {
35
+ out[key] = stable(child);
36
+ }
37
+ return out;
38
+ }
39
+ return value;
40
+ }
41
+ function stableStringify(value) {
42
+ return JSON.stringify(stable(value));
43
+ }
44
+ function validatePackPath(path) {
45
+ if (/^https?:\/\//i.test(path)) {
46
+ return { error: "unsafe_filename", message: "Aesthetic pack imports only accept local .mosvera.json files, not URLs." };
47
+ }
48
+ const file = basename(path);
49
+ if (file.startsWith(".") || !PACK_EXT.test(file)) {
50
+ return { error: "unsafe_filename", message: "Aesthetic pack paths must end with .mosvera.json and must not be dotfiles." };
51
+ }
52
+ return undefined;
53
+ }
54
+ function readPackSource(args) {
55
+ if ((args.pack === undefined && args.path === undefined) || (args.pack !== undefined && args.path !== undefined)) {
56
+ return { error: "invalid_document", message: "Provide exactly one aesthetic pack source: inline pack JSON or a local .mosvera.json path." };
57
+ }
58
+ if (args.path !== undefined) {
59
+ const pathFailure = validatePackPath(args.path);
60
+ if (pathFailure !== undefined)
61
+ return pathFailure;
62
+ const parsed = parseDocument(readFileSync(args.path, "utf8"));
63
+ if (maybeFail(parsed))
64
+ return parsed;
65
+ return { pack: parsed, source: "path", path: args.path };
66
+ }
67
+ const parsed = parseDocument(args.pack);
68
+ if (maybeFail(parsed))
69
+ return parsed;
70
+ return { pack: parsed, source: "inline" };
71
+ }
72
+ function readValidPackSource(args, ctx) {
73
+ const source = readPackSource(args);
74
+ if (maybeFail(source))
75
+ return source;
76
+ const diagnostics = validateAestheticPack(source.pack, { validator: ctx.validator });
77
+ if (diagnostics.length > 0) {
78
+ return {
79
+ error: "schema_failure",
80
+ message: "Aesthetic pack failed validation.",
81
+ detail: { valid: false, diagnostics },
82
+ };
83
+ }
84
+ return source;
85
+ }
26
86
  function runtimeError(e) {
27
87
  if (isResolutionError(e)) {
28
88
  const mapped = mapResolutionError(e);
@@ -116,7 +176,7 @@ export function runServerStatus(ctx) {
116
176
  fallback_reason: ctx.fallbackReason,
117
177
  versions: {
118
178
  mcp: SERVER_VERSION,
119
- runtime: "0.1.1",
179
+ runtime: "0.1.2",
120
180
  },
121
181
  counts,
122
182
  diagnostics,
@@ -124,7 +184,10 @@ export function runServerStatus(ctx) {
124
184
  }
125
185
  export function runListAesthetics(ctx) {
126
186
  const aesthetics = listRegistryEntries(ctx.project.registry, "composition");
127
- return ok(`Found ${aesthetics.length} aesthetic${aesthetics.length === 1 ? "" : "s"}.`, { aesthetics });
187
+ const label = aesthetics.length === 1 ? "aesthetic" : "aesthetics";
188
+ const summary = aesthetics.length === 0 ? "Found 0 aesthetics." :
189
+ `Found ${aesthetics.length} ${label}:\n${aesthetics.map((entry) => `- ${entry.id}${entry.base !== undefined ? ` (base: ${entry.base})` : ""}`).join("\n")}`;
190
+ return ok(summary, { aesthetics });
128
191
  }
129
192
  export function runGetRegistryDocument(ctx, args) {
130
193
  if (args.kind === "capability-manifest") {
@@ -154,6 +217,54 @@ export function runValidateRegistry(ctx) {
154
217
  diagnostics,
155
218
  });
156
219
  }
220
+ export function runValidateAestheticPack(ctx, args) {
221
+ const source = readPackSource(args);
222
+ if (maybeFail(source))
223
+ return toolFail(source);
224
+ const diagnostics = validateAestheticPack(source.pack, { validator: ctx.validator });
225
+ return ok(diagnostics.length === 0 ? "Aesthetic pack is valid." : "Aesthetic pack is invalid.", {
226
+ valid: diagnostics.length === 0,
227
+ source: source.source,
228
+ path: source.path,
229
+ diagnostics,
230
+ });
231
+ }
232
+ export function runPreviewAestheticImport(ctx, args) {
233
+ const source = readValidPackSource(args, ctx);
234
+ if (maybeFail(source))
235
+ return toolFail(source);
236
+ const options = {
237
+ validator: ctx.validator,
238
+ strategies: ctx.project.strategies,
239
+ };
240
+ if (args.conflict_strategy !== undefined)
241
+ options.conflictStrategy = args.conflict_strategy;
242
+ if (args.strategy_conflict !== undefined)
243
+ options.strategyConflict = args.strategy_conflict;
244
+ const plan = previewAestheticPackImport(source.pack, ctx.project.registry, options);
245
+ if (!plan.valid)
246
+ return fail("invalid_document", "Aesthetic pack import preview found blocking diagnostics.", { plan });
247
+ return ok("Previewed aesthetic pack import.", { source: source.source, path: source.path, plan });
248
+ }
249
+ export function runExportAestheticPack(ctx, args) {
250
+ try {
251
+ const options = {
252
+ strategies: ctx.project.strategies,
253
+ };
254
+ if (args.id !== undefined)
255
+ options.id = args.id;
256
+ if (args.name !== undefined)
257
+ options.name = args.name;
258
+ if (args.description !== undefined)
259
+ options.description = args.description;
260
+ const pack = exportAestheticPack(args.aesthetic, ctx.project.registry, options);
261
+ const suggested_filename = `${pack.id}.mosvera.json`;
262
+ return ok(`Exported aesthetic pack "${pack.id}".`, { pack, suggested_filename });
263
+ }
264
+ catch (e) {
265
+ return toolFail(runtimeError(e));
266
+ }
267
+ }
157
268
  export function runResolveAesthetic(ctx, args) {
158
269
  const input = { aesthetic: args.aesthetic };
159
270
  if (args.merge_strategies !== undefined)
@@ -325,6 +436,49 @@ export function runWriteMergeStrategies(ctx, args) {
325
436
  return toolFail(runtimeError(e));
326
437
  }
327
438
  }
439
+ export function runImportAestheticPack(ctx, args) {
440
+ const disabled = writeDisabled(ctx);
441
+ if (disabled !== undefined)
442
+ return toolFail(disabled);
443
+ const source = readValidPackSource(args, ctx);
444
+ if (maybeFail(source))
445
+ return toolFail(source);
446
+ try {
447
+ const options = {
448
+ validator: ctx.validator,
449
+ strategies: ctx.project.strategies,
450
+ };
451
+ if (args.conflict_strategy !== undefined)
452
+ options.conflictStrategy = args.conflict_strategy;
453
+ if (args.strategy_conflict !== undefined)
454
+ options.strategyConflict = args.strategy_conflict;
455
+ const result = importAestheticPack(ctx.project.registry, source.pack, options);
456
+ if (!result.plan.valid)
457
+ return fail("invalid_document", "Aesthetic pack import found blocking diagnostics.", { plan: result.plan });
458
+ for (const kind of registryKinds) {
459
+ const collection = kind === "template" ? result.pack.documents.templates :
460
+ kind === "modifier" ? result.pack.documents.modifiers :
461
+ kind === "palette" ? result.pack.documents.palettes :
462
+ result.pack.documents.compositions;
463
+ for (const document of Object.values(collection ?? {})) {
464
+ saveProjectDocument(ctx.registryDir, kind, document);
465
+ }
466
+ }
467
+ if (stableStringify(result.strategies) !== stableStringify(ctx.project.strategies)) {
468
+ writeMergeStrategies(ctx.registryDir, result.strategies);
469
+ }
470
+ reloadContext(ctx);
471
+ return ok(`Imported aesthetic pack "${result.pack.id}".`, {
472
+ source: source.source,
473
+ path: source.path,
474
+ plan: result.plan,
475
+ entrypoint: result.plan.installed_entrypoint,
476
+ });
477
+ }
478
+ catch (e) {
479
+ return toolFail(runtimeError(e));
480
+ }
481
+ }
328
482
  export function errorCodeFromResult(result) {
329
483
  const code = result.structuredContent?.error;
330
484
  return typeof code === "string" ? code : undefined;
package/dist/types.d.ts CHANGED
@@ -27,7 +27,7 @@ export interface ToolContext {
27
27
  adapters?: Record<string, ProviderAdapter>;
28
28
  }
29
29
  /** Closed MCP-layer error taxonomy (D2/D7 in the design spec). */
30
- export type ToolErrorCode = "invalid_document" | "unknown_reference" | "unknown_provider" | "unsafe_filename" | "schema_failure" | "write_disabled" | "registry_unwritable" | "inheritance_cycle" | "reference_cycle" | "multiple_inheritance_unsupported";
30
+ export type ToolErrorCode = "invalid_document" | "unknown_reference" | "unknown_provider" | "unsafe_filename" | "schema_failure" | "strategy_conflict" | "write_disabled" | "registry_unwritable" | "inheritance_cycle" | "reference_cycle" | "multiple_inheritance_unsupported";
31
31
  export interface ToolError {
32
32
  error: ToolErrorCode;
33
33
  detail?: JsonObject | string;
@@ -2,7 +2,7 @@
2
2
  "manifest_version": "0.3",
3
3
  "name": "mosvera-mcp",
4
4
  "display_name": "Mosvera",
5
- "version": "0.1.2",
5
+ "version": "0.1.4",
6
6
  "description": "Resolve, compile, and save local Mosvera aesthetics from Claude Desktop.",
7
7
  "long_description": "Mosvera runs locally against your own aesthetic registry. It lets Claude list named aesthetics, resolve them to canonical Mosvera models, compile portable design tokens and CSS variables, and save registry documents without sending provider requests or storing secrets.",
8
8
  "author": {
@@ -36,6 +36,9 @@
36
36
  { "name": "get_registry_document", "description": "Fetch a template, modifier, palette, composition, or capability manifest." },
37
37
  { "name": "validate_document", "description": "Validate one Mosvera document against a schema kind." },
38
38
  { "name": "validate_registry", "description": "Validate the active local registry." },
39
+ { "name": "validate_aesthetic_pack", "description": "Validate an inline or local .mosvera.json aesthetic pack." },
40
+ { "name": "preview_aesthetic_import", "description": "Preview importing an aesthetic pack without writing files." },
41
+ { "name": "export_aesthetic_pack", "description": "Export a named aesthetic as a portable .mosvera.json pack." },
39
42
  { "name": "resolve_aesthetic", "description": "Resolve a named or inline aesthetic to the canonical Mosvera model." },
40
43
  { "name": "compile_design_tokens", "description": "Compile an aesthetic into portable design tokens and CSS variables." },
41
44
  { "name": "compile_provider_payload", "description": "Compile a deterministic provider payload without making provider HTTP calls." },
@@ -43,7 +46,8 @@
43
46
  { "name": "save_aesthetic", "description": "Create or update a named aesthetic in the active local registry." },
44
47
  { "name": "save_registry_document", "description": "Create or update an advanced registry document." },
45
48
  { "name": "delete_registry_document", "description": "Delete a registry document from the active local registry." },
46
- { "name": "write_merge_strategies", "description": "Replace merge-strategies.json with deterministic JSON." }
49
+ { "name": "write_merge_strategies", "description": "Replace merge-strategies.json with deterministic JSON." },
50
+ { "name": "import_aesthetic_pack", "description": "Import an aesthetic pack into the active local registry." }
47
51
  ],
48
52
  "keywords": ["mosvera", "aesthetic-infrastructure", "mcp", "design-tokens"],
49
53
  "license": "Apache-2.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mosvera/mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Run Mosvera as local MCP tools for agents, editors, and Claude Desktop.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -41,8 +41,8 @@
41
41
  "ci": "npm run build && npm run typecheck && npm test",
42
42
  "clean": "rm -rf dist",
43
43
  "mcpb:stage": "npm run build && node scripts/stage-mcpb.mjs",
44
- "mcpb:pack": "npm run mcpb:stage && mcpb pack build/mcpb/mosvera build/mosvera/mosvera-mcp-0.1.2.mcpb",
45
- "mcpb:inspect": "node scripts/inspect-mcpb.mjs build/mosvera/mosvera-mcp-0.1.2.mcpb",
44
+ "mcpb:pack": "npm run mcpb:stage && mcpb pack build/mcpb/mosvera build/mosvera/mosvera-mcp-0.1.4.mcpb",
45
+ "mcpb:inspect": "node scripts/inspect-mcpb.mjs build/mosvera/mosvera-mcp-0.1.4.mcpb",
46
46
  "prepublishOnly": "npm run build && npm run typecheck && npm test",
47
47
  "start": "tsx src/server.ts",
48
48
  "test": "vitest run",
@@ -56,7 +56,7 @@
56
56
  "node": ">=20"
57
57
  },
58
58
  "dependencies": {
59
- "@mosvera/runtime": "^0.1.1",
59
+ "@mosvera/runtime": "^0.1.2",
60
60
  "@mosvera/provider-base": "^0.1.1",
61
61
  "@mosvera/provider-flux": "^0.1.1",
62
62
  "@mosvera/provider-openai": "^0.1.1",