@adobe/design-data-agent-mcp 1.12.0 → 1.14.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@adobe/design-data-agent-mcp`
2
2
 
3
- MCP server and Claude Code skill for the [Spectrum Design Data](../../packages/design-data/) agent surface. Read tools (`primer`, `resolve_token`, `query_tokens`, `describe_component`, `describe_guideline`, `list_guidelines`) run fully in-process via `@adobe/design-data-wasm` — no CLI binary required for those. Only `authoring_session_step_intent` still invokes the native binary (for NLP suggest ranking, not yet on the wasm surface).
3
+ MCP server and Claude Code skill for the [Spectrum Design Data](../../packages/design-data/) agent surface. Read tools (`primer`, `resolve_token`, `query_tokens`, `suggest_token`, `describe_component`, `describe_guideline`, `list_guidelines`) run fully in-process via `@adobe/design-data-wasm` — no CLI binary required for those. `suggest_token` uses the wasm `suggest` API directly; `authoring_session_step_intent` still invokes the native binary for session-state-aware ranking within an authoring flow.
4
4
 
5
5
  ## Install
6
6
 
@@ -71,11 +71,14 @@ node tools/design-data-agent-mcp/src/index.js
71
71
  | `DESIGN_DATA_SCHEMAS` | — | Override schema path (for `validate`) |
72
72
  | `DESIGN_DATA_EXCEPTIONS` | — | Override exceptions path (for `validate`) |
73
73
  | `DESIGN_DATA_CONFIG` | — | Path to a `.design-data.toml` (or its directory) to resolve a platform cascade |
74
+ | `DESIGN_DATA_PLATFORM` | — | Select a named `[platforms.<id>]` entry (needs `DESIGN_DATA_CONFIG`) |
74
75
 
75
76
  > **Platform cascade.** If `DESIGN_DATA_CONFIG` is set, the server shells out to
76
77
  > the `design-data` CLI once at startup (`design-data query --filter "" --format
77
78
  > json`, run from the config's directory) to resolve its `.design-data.toml`
78
- > source (path/npm/github/git) and any top-level `manifest` cascade, then
79
+ > source (path/npm/github/git) and either its top-level `manifest` cascade or,
80
+ > if `DESIGN_DATA_PLATFORM` is also set, that named `[platforms.<id>]` entry's
81
+ > manifest — mirroring the CLI's own `--platform`/`DESIGN_DATA_PLATFORM`, then
79
82
  > materializes the result to a temp dir and points `primer` / `resolve_token` /
80
83
  > `query_tokens` / `validate_usage` / `describe_component` /
81
84
  > `describe_guideline` / `list_guidelines` at it instead of the embedded
@@ -152,6 +155,7 @@ node tools/design-data-agent-mcp/src/index.js
152
155
  | `primer` | Load full token taxonomy, component list, and field definitions |
153
156
  | `resolve_token` | Resolve a token property to its literal value |
154
157
  | `query_tokens` | Filter tokens by expression |
158
+ | `suggest_token` | Suggest tokens matching a natural-language intent |
155
159
  | `describe_component` | Fetch component schema and token bindings |
156
160
  | `describe_guideline` | Fetch guideline documentBlocks content and metadata |
157
161
  | `list_guidelines` | List guideline slugs and metadata, optionally by category |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/design-data-agent-mcp",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "MCP server and Claude Code skill for the design-data agent surface — read tools run in-process via wasm",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@modelcontextprotocol/sdk": "^1.27.1",
33
- "@adobe/design-data": "3.2.1",
34
- "@adobe/design-data-wasm": "0.10.0",
35
- "@adobe/spectrum-design-data": "3.2.5"
33
+ "@adobe/design-data": "3.2.2",
34
+ "@adobe/design-data-wasm": "0.10.1",
35
+ "@adobe/spectrum-design-data": "3.3.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "ava": "^6.0.1"
@@ -6,12 +6,12 @@ description: >
6
6
  system, token lookup, spec-conformance, drift detection, or token authoring on custom data.
7
7
  metadata:
8
8
  author: adobe
9
- version: "1.12.0"
9
+ version: "1.14.0"
10
10
  when_to_use: >
11
11
  Trigger on: design system, design tokens, spec-conformant, drift, validate tokens, token
12
12
  authoring, custom dataset, DESIGN_DATA_PATH, design-data validate, design-data diff,
13
13
  design-data write, product-context.json.
14
- allowed-tools: mcp__design-data-agent__primer, mcp__design-data-agent__query_tokens, mcp__design-data-agent__resolve_token, mcp__design-data-agent__describe_component, mcp__design-data-agent__validate_usage, mcp__design-data-agent__diff_datasets, mcp__design-data-agent__write, mcp__design-data-agent__start_authoring_session, mcp__design-data-agent__authoring_session_step_intent, mcp__design-data-agent__authoring_session_step_classification, mcp__design-data-agent__authoring_session_step_values, mcp__design-data-agent__authoring_session_commit, mcp__design-data-agent__authoring_session_cancel, mcp__design-data-agent__authoring_session_get, mcp__design-data-agent__authoring_session_list
14
+ allowed-tools: mcp__design-data-agent__primer, mcp__design-data-agent__query_tokens, mcp__design-data-agent__suggest_token, mcp__design-data-agent__resolve_token, mcp__design-data-agent__describe_component, mcp__design-data-agent__validate_usage, mcp__design-data-agent__diff_datasets, mcp__design-data-agent__write, mcp__design-data-agent__start_authoring_session, mcp__design-data-agent__authoring_session_step_intent, mcp__design-data-agent__authoring_session_step_classification, mcp__design-data-agent__authoring_session_step_values, mcp__design-data-agent__authoring_session_commit, mcp__design-data-agent__authoring_session_cancel, mcp__design-data-agent__authoring_session_get, mcp__design-data-agent__authoring_session_list
15
15
  ---
16
16
 
17
17
  # design-data agent skill
@@ -102,6 +102,15 @@ $schema=https://spectrum.adobe.com/page/design-token/
102
102
 
103
103
  > **Exit codes:** `0` = matches found; empty array = no matches (not an error).
104
104
 
105
+ ### Suggest a token from a description — `suggest_token`
106
+
107
+ Required: `intent` (string) — a natural-language description of the design need,
108
+ such as `"primary CTA button background color"`.
109
+
110
+ Optional: `limit` (number, default `5`) — the maximum number of suggestions to return.
111
+ Results are ranked by confidence using token names, name-object fields, and description
112
+ text. Use this when the user describes what they need rather than knowing a token name.
113
+
105
114
  ***
106
115
 
107
116
  ## Component info — `describe_component`
@@ -163,8 +172,9 @@ Helper tools: `authoring_session_get` (inspect state), `authoring_session_list`
163
172
  `authoring_session_commit` accepts an optional `schema_path` to override the schemas directory
164
173
  for Layer-1 JSON-Schema validation before writing.
165
174
 
166
- > **Note:** `authoring_session_step_intent` (NLP suggestion ranking) still delegates to the
167
- > `design-data` CLI because the NLP `suggest` API is not yet on the wasm surface.
175
+ > **Note:** The standalone `suggest_token` tool calls the wasm `suggest` API directly.
176
+ > `authoring_session_step_intent` still delegates to the `design-data` CLI for
177
+ > session-state-aware ranking within an authoring flow.
168
178
 
169
179
  ***
170
180
 
@@ -43,18 +43,64 @@ function resolveConfigDir(configPath) {
43
43
  return statSync(configPath).isDirectory() ? configPath : dirname(configPath);
44
44
  }
45
45
 
46
- function resolveManifestPath(configDir) {
46
+ function resolveManifestPath(configDir, platformId) {
47
47
  const configPath = join(configDir, ".design-data.toml");
48
48
  if (!existsSync(configPath)) return null;
49
49
 
50
50
  const configText = readFileSync(configPath, "utf-8");
51
+
52
+ if (platformId) {
53
+ // Named `[platforms.<id>]` entries (spectrum-design-data-h890.27.3) are
54
+ // either a bare local path (`id = "platforms/id/manifest.json"`, matched
55
+ // here) or a remote `github`-sourced table. This regex only resolves the
56
+ // local-path shape — a remote platform entry's extensions/ catalogs still
57
+ // need fetching, which the CLI's `query` shell-out below does not surface
58
+ // to this file; local-path is the shape every platform incubating in this
59
+ // monorepo uses today (see platforms/README.md).
60
+ const idPattern = platformId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
61
+ const match = configText.match(
62
+ new RegExp(`^\\s*${idPattern}\\s*=\\s*["']([^"']+)["']\\s*$`, "m"),
63
+ );
64
+ if (!match) return null;
65
+ const manifestPath = join(configDir, match[1]);
66
+ return existsSync(manifestPath) ? manifestPath : null;
67
+ }
68
+
51
69
  const match = configText.match(/^\s*manifest\s*=\s*["']([^"']+)["']\s*$/m);
52
70
  const manifestPath = join(configDir, match?.[1] ?? "manifest.json");
53
71
  return existsSync(manifestPath) ? manifestPath : null;
54
72
  }
55
73
 
56
- function materializeCatalogs(config, cascadeDir, configDir) {
57
- const manifestPath = resolveManifestPath(configDir);
74
+ /**
75
+ * Determine which named `[platforms.<id>]` entry, if any, the CLI would pick
76
+ * for the *tokens* cascade so catalog materialization can match it exactly.
77
+ * `config.platformId` (from `DESIGN_DATA_PLATFORM`) always wins; otherwise
78
+ * this asks the CLI which id `default_platform` resolves to, via
79
+ * `platform list --format json`, rather than re-implementing the CLI's own
80
+ * precedence rules (`--manifest` > `--platform` > `DESIGN_DATA_PLATFORM` >
81
+ * `default_platform` > legacy `manifest` key) in a second, drifting regex.
82
+ * Returns `null` on any failure (no platforms configured, CLI error,
83
+ * unparsable output) so callers fall back to the legacy `manifest` key.
84
+ */
85
+ async function resolveActivePlatformId(configDir, config, run) {
86
+ if (config.platformId) return config.platformId;
87
+ try {
88
+ const { exitCode, stdout } = await run(
89
+ ["platform", "list", "--format", "json"],
90
+ { timeout: 10_000, cwd: configDir },
91
+ );
92
+ if (exitCode !== 0) return null;
93
+ const rows = JSON.parse(stdout);
94
+ const defaultRow = rows.find((row) => row.default);
95
+ if (!defaultRow || defaultRow.id === "(default)") return null;
96
+ return defaultRow.id;
97
+ } catch {
98
+ return null;
99
+ }
100
+ }
101
+
102
+ function materializeCatalogs(config, cascadeDir, configDir, activePlatformId) {
103
+ const manifestPath = resolveManifestPath(configDir, activePlatformId);
58
104
  let extensionsDir = null;
59
105
  if (manifestPath) {
60
106
  const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
@@ -119,7 +165,13 @@ function mergeGuidelineManifest(targetDir, extensionDir) {
119
165
 
120
166
  /**
121
167
  * Resolve `config.designDataConfig`'s cascade and populate
122
- * `config.cascadeDataPath` / `config.cascadeActive` with the result.
168
+ * `config.cascadeDataPath` / `config.cascadeActive` with the result. If
169
+ * `config.platformId` is set, selects that named `[platforms.<id>]` entry
170
+ * (spectrum-design-data-h890.27.14) — both for the CLI query shell-out and
171
+ * for materializing that platform's `extensions/` catalogs, instead of the
172
+ * legacy top-level `manifest` key. If `platformId` is unset but the config
173
+ * has a `default_platform`, `resolveActivePlatformId` discovers that id from
174
+ * the CLI itself so both halves still agree on the same platform.
123
175
  * Deliberately does not touch `config.dataPath`/`config.dataRoot` — those
124
176
  * remain the fallback anchors for unrelated write/authoring/data tools,
125
177
  * which must keep targeting the real dataset root, not the cascade's
@@ -144,10 +196,25 @@ export async function bootstrapCascade(config, { run = runCli } = {}) {
144
196
  }
145
197
 
146
198
  try {
147
- const { exitCode, stdout, stderr } = await run(
148
- ["query", "--filter", "", "--format", "json"],
149
- { timeout: 60_000, cwd: configDir },
199
+ const activePlatformId = await resolveActivePlatformId(
200
+ configDir,
201
+ config,
202
+ run,
150
203
  );
204
+ const queryArgs = ["query", "--filter", "", "--format", "json"];
205
+ if (activePlatformId) {
206
+ // Must follow the subcommand — see the CLI's own --platform help text
207
+ // on this ordering limitation. Passing this explicitly (even when it
208
+ // only came from `default_platform`, not an explicit selection) keeps
209
+ // the token query and the catalog materialization below looking at
210
+ // the exact same platform, instead of letting the CLI's own default
211
+ // resolution and this file's manifest-path regex potentially disagree.
212
+ queryArgs.push("--platform", activePlatformId);
213
+ }
214
+ const { exitCode, stdout, stderr } = await run(queryArgs, {
215
+ timeout: 60_000,
216
+ cwd: configDir,
217
+ });
151
218
  if (exitCode !== 0) {
152
219
  throw new Error(stderr || `design-data exited with code ${exitCode}`);
153
220
  }
@@ -159,7 +226,7 @@ export async function bootstrapCascade(config, { run = runCli } = {}) {
159
226
  JSON.stringify(tokens),
160
227
  "utf-8",
161
228
  );
162
- materializeCatalogs(config, dir, configDir);
229
+ materializeCatalogs(config, dir, configDir, activePlatformId);
163
230
 
164
231
  config.cascadeDataPath = dir;
165
232
  config.cascadeActive = true;
package/src/config.js CHANGED
@@ -89,6 +89,12 @@ export const config = {
89
89
  // cascadeDataPath/cascadeActive below. Unset by default so an in-repo run's
90
90
  // ambient .design-data.toml (if any) doesn't surprise it.
91
91
  designDataConfig: anchorPath(process.env.DESIGN_DATA_CONFIG ?? null),
92
+ // Selects a named `[platforms.<id>]` entry from designDataConfig's
93
+ // `.design-data.toml` (spectrum-design-data-h890.27.14), mirroring the CLI's
94
+ // own `--platform`/`DESIGN_DATA_PLATFORM`. Has no effect unless
95
+ // designDataConfig is also set. Unset by default: falls back to the config's
96
+ // legacy top-level `manifest` key or `default_platform`, same as the CLI.
97
+ platformId: process.env.DESIGN_DATA_PLATFORM ?? null,
92
98
  // Set by cascade-bootstrap.js on a successful resolve: the temp dir holding
93
99
  // the materialized cascade dataset. Deliberately separate from dataPath —
94
100
  // dataPath/dataRoot are also the fallback anchors for unrelated
package/src/tools/read.js CHANGED
@@ -20,8 +20,9 @@
20
20
  * @adobe/design-data-mcp package's `design-data-guideline` tool via the
21
21
  * `@adobe/design-data/guideline` module, rather than duplicated here.
22
22
  *
23
- * Note: authoring_session_step_intent in authoring.js still uses the CLI because
24
- * the NLP suggest ranking is not yet on the wasm surface.
23
+ * suggest_token uses the wasm suggest surface directly. The separate
24
+ * authoring_session_step_intent flow still uses the CLI for session-state-aware
25
+ * ranking within an authoring session.
25
26
  *
26
27
  * Cascade scope (see cascade-bootstrap.js / spectrum-design-data-h890.14): once a
27
28
  * `.design-data.toml` cascade is resolved, primer/resolve_token/query_tokens/
@@ -286,6 +287,36 @@ export function createReadTools() {
286
287
  },
287
288
  },
288
289
 
290
+ {
291
+ name: "suggest_token",
292
+ description:
293
+ "Suggest Spectrum tokens matching a natural-language intent using Jaccard similarity " +
294
+ "scoring over token name segments, name-object fields, and description text. " +
295
+ "Returns matches ranked by confidence with token name, layer, value, and name object. " +
296
+ "Use when the user describes what they need rather than knowing the token name.",
297
+ inputSchema: {
298
+ type: "object",
299
+ required: ["intent"],
300
+ properties: {
301
+ intent: {
302
+ type: "string",
303
+ description:
304
+ 'Natural-language description of the design need, e.g. "primary CTA button background color"',
305
+ },
306
+ limit: {
307
+ type: "number",
308
+ description: "Maximum number of suggestions to return (default: 5)",
309
+ default: 5,
310
+ },
311
+ },
312
+ additionalProperties: false,
313
+ },
314
+ async handler({ intent, limit = 5 }) {
315
+ const ds = await getDataset();
316
+ return ds.suggest(intent, undefined, limit);
317
+ },
318
+ },
319
+
289
320
  {
290
321
  name: "describe_component",
291
322
  description: