@adobe/design-data-agent-mcp 1.5.0 → 1.6.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 +6 -5
- package/package.json +2 -2
- package/src/tools/read.js +93 -22
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.
|
|
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`) 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).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -29,7 +29,7 @@ https://github.com/adobe/spectrum-design-data/tree/main/tools/design-data-agent-
|
|
|
29
29
|
npx @adobe/design-data-agent-mcp
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The `@adobe/design-data` CLI binary is **only** needed for `authoring_session_step_intent`. All other tools run in-process. Set `DESIGN_DATA_BIN` if the binary is not on `PATH`.
|
|
33
33
|
|
|
34
34
|
## MCP server
|
|
35
35
|
|
|
@@ -49,7 +49,7 @@ node tools/design-data-agent-mcp/src/index.js
|
|
|
49
49
|
|
|
50
50
|
| Variable | Default | Description |
|
|
51
51
|
| ------------------------ | ------------- | ------------------------------------------------- |
|
|
52
|
-
| `DESIGN_DATA_BIN` | `design-data` | Path to the `design-data` binary
|
|
52
|
+
| `DESIGN_DATA_BIN` | `design-data` | Path to the `design-data` binary (authoring only) |
|
|
53
53
|
| `DESIGN_DATA_ROOT` | — | Absolute root that relative paths are anchored to |
|
|
54
54
|
| `DESIGN_DATA_PATH` | `.` | Dataset root path |
|
|
55
55
|
| `DESIGN_DATA_COMPONENTS` | — | Override components directory |
|
|
@@ -74,8 +74,9 @@ node tools/design-data-agent-mcp/src/index.js
|
|
|
74
74
|
> `packages/design-data`; when published it uses the installed dependency. This
|
|
75
75
|
> is independent of the working directory.
|
|
76
76
|
> 3. **Fallback.** `dataPath` falls back to the (anchored) current directory; the
|
|
77
|
-
> component/field overrides fall back to
|
|
78
|
-
>
|
|
77
|
+
> component/field overrides fall back to `null` (not supplied), which means
|
|
78
|
+
> `describe_component` will throw an error if `@adobe/spectrum-design-data` is
|
|
79
|
+
> not resolvable.
|
|
79
80
|
>
|
|
80
81
|
> In a monorepo checkout you typically need no `DESIGN_DATA_*` env vars at all —
|
|
81
82
|
> resolution via the workspace package handles it.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/design-data-agent-mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP server and Claude Code skill for the design-data agent surface —
|
|
3
|
+
"version": "1.6.0",
|
|
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",
|
|
7
7
|
"bin": {
|
package/src/tools/read.js
CHANGED
|
@@ -11,19 +11,54 @@
|
|
|
11
11
|
/**
|
|
12
12
|
* Read tools for design-data-agent-mcp.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* All read tools run fully in-process via @adobe/design-data-wasm — no CLI binary
|
|
15
|
+
* required. primer and describe_component were migrated in issue m1r.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* describe_component requires the components catalog path resolution that the CLI
|
|
20
|
-
* handles. These will be ported when those APIs are added to the wasm surface.
|
|
17
|
+
* Note: authoring_session_step_intent in authoring.js still uses the CLI because
|
|
18
|
+
* the NLP suggest ranking is not yet on the wasm surface.
|
|
21
19
|
*/
|
|
22
20
|
|
|
21
|
+
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
23
|
import { loadDataset } from "@adobe/design-data/load";
|
|
24
|
-
import { runCli } from "../cli.js";
|
|
25
24
|
import { config } from "../config.js";
|
|
26
25
|
|
|
26
|
+
let _wasm;
|
|
27
|
+
/** Lazy-load and cache the wasm module (nodejs target, no init() required). */
|
|
28
|
+
async function getWasm() {
|
|
29
|
+
if (!_wasm) _wasm = await import("@adobe/design-data-wasm");
|
|
30
|
+
return _wasm;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let _dataset;
|
|
34
|
+
/**
|
|
35
|
+
* Return the embedded Spectrum dataset, caching it after first access.
|
|
36
|
+
*
|
|
37
|
+
* Dataset.embedded() clones the in-memory graph on every call; caching here
|
|
38
|
+
* avoids that per-request cost.
|
|
39
|
+
*/
|
|
40
|
+
async function getDataset() {
|
|
41
|
+
if (!_dataset) {
|
|
42
|
+
const wasm = await getWasm();
|
|
43
|
+
_dataset = wasm.Dataset.embedded();
|
|
44
|
+
}
|
|
45
|
+
return _dataset;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validate a component ID against the same rule as the Rust SDK.
|
|
50
|
+
* See sdk/core/src/component.rs:validate_id — prevents path traversal.
|
|
51
|
+
*/
|
|
52
|
+
const COMPONENT_ID_RE = /^[a-z][a-z0-9-]*$/;
|
|
53
|
+
function validateComponentId(id) {
|
|
54
|
+
if (!COMPONENT_ID_RE.test(id)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`Invalid component ID "${id}". IDs must be kebab-case: start with a lowercase ` +
|
|
57
|
+
`letter and contain only lowercase letters, digits, and hyphens.`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
27
62
|
export function createReadTools() {
|
|
28
63
|
return [
|
|
29
64
|
{
|
|
@@ -36,14 +71,31 @@ export function createReadTools() {
|
|
|
36
71
|
additionalProperties: false,
|
|
37
72
|
},
|
|
38
73
|
async handler() {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
74
|
+
// Shape note: this response intentionally diverges from the CLI PrimerData
|
|
75
|
+
// struct (sdk/core/src/primer.rs). The CLI emits modeSets as an array of
|
|
76
|
+
// {name, values} objects and taxonomyFields as a flat array. This in-process
|
|
77
|
+
// shape uses keyed objects (matching the sibling design-data-mcp), which agents
|
|
78
|
+
// and the SKILL.md skill prompt consume by key name. Skill contract:
|
|
79
|
+
// tokenCount, modeSets.{colorScheme,scale,contrast}, components[],
|
|
80
|
+
// taxonomyFields.{indexed,advisory}. CLI-only fields (specVersion, manifest,
|
|
81
|
+
// provenance) are not present — no SKILL.md reference or consumer relies on them.
|
|
82
|
+
const wasm = await getWasm();
|
|
83
|
+
const ds = await getDataset();
|
|
84
|
+
return {
|
|
85
|
+
source: "embedded",
|
|
86
|
+
tokenCount: ds.tokenCount(),
|
|
87
|
+
modeSets: {
|
|
88
|
+
colorScheme: wasm.getFieldValues("colorScheme") ?? [],
|
|
89
|
+
scale: wasm.getFieldValues("scale") ?? [],
|
|
90
|
+
contrast: wasm.getFieldValues("contrast") ?? [],
|
|
91
|
+
},
|
|
92
|
+
taxonomyFields: {
|
|
93
|
+
indexed: wasm.getIndexedFields(),
|
|
94
|
+
advisory: wasm.getAdvisoryFields() ?? [],
|
|
95
|
+
},
|
|
96
|
+
components: wasm.getFieldValues("component") ?? [],
|
|
97
|
+
properties: wasm.getFieldValues("property") ?? [],
|
|
98
|
+
};
|
|
47
99
|
},
|
|
48
100
|
},
|
|
49
101
|
|
|
@@ -127,13 +179,32 @@ export function createReadTools() {
|
|
|
127
179
|
additionalProperties: false,
|
|
128
180
|
},
|
|
129
181
|
async handler({ id }) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
182
|
+
validateComponentId(id);
|
|
183
|
+
const componentsDir = config.componentsDir;
|
|
184
|
+
if (!componentsDir) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`@adobe/spectrum-design-data is not installed — cannot load component "${id}". ` +
|
|
187
|
+
`Install it with: pnpm add @adobe/spectrum-design-data`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const componentFile = join(componentsDir, `${id}.json`);
|
|
191
|
+
if (!existsSync(componentFile)) {
|
|
192
|
+
let available;
|
|
193
|
+
try {
|
|
194
|
+
available = readdirSync(componentsDir)
|
|
195
|
+
.filter((f) => f.endsWith(".json"))
|
|
196
|
+
.map((f) => f.replace(/\.json$/, ""))
|
|
197
|
+
.sort()
|
|
198
|
+
.join(", ");
|
|
199
|
+
} catch {
|
|
200
|
+
available = null;
|
|
201
|
+
}
|
|
202
|
+
const hint = available
|
|
203
|
+
? `Available components: ${available}`
|
|
204
|
+
: `Call primer to see available component IDs.`;
|
|
205
|
+
throw new Error(`Component not found: "${id}". ${hint}`);
|
|
206
|
+
}
|
|
207
|
+
return JSON.parse(readFileSync(componentFile, "utf-8"));
|
|
137
208
|
},
|
|
138
209
|
},
|
|
139
210
|
];
|