@adobe/design-data-agent-mcp 1.3.1 → 1.5.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/LICENSE +1 -1
- package/README.md +37 -14
- package/package.json +5 -2
- package/skills/design-data/SKILL.md +78 -97
- package/src/cli.js +4 -0
- package/src/config.js +64 -6
- package/src/tools/authoring.js +56 -77
- package/src/tools/diff.js +33 -7
- package/src/tools/read.js +30 -25
- package/src/tools/validate.js +17 -15
- package/src/tools/write.js +2 -7
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@ file or class name and description of purpose be included on the
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2026 Adobe
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
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
|
|
3
|
+
MCP server and Claude Code skill for the [Spectrum Design Data](../../packages/design-data/) agent surface. Shells out to the `design-data` CLI — all logic stays in the Rust SDK.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -47,15 +47,38 @@ node tools/design-data-agent-mcp/src/index.js
|
|
|
47
47
|
|
|
48
48
|
### Environment variables
|
|
49
49
|
|
|
50
|
-
| Variable | Default | Description
|
|
51
|
-
| ------------------------ | ------------- |
|
|
52
|
-
| `DESIGN_DATA_BIN` | `design-data` | Path to the `design-data` binary
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `DESIGN_DATA_SCHEMAS` | — | Override schema path (for `validate`)
|
|
58
|
-
| `DESIGN_DATA_EXCEPTIONS` | — | Override exceptions path (for `validate`)
|
|
50
|
+
| Variable | Default | Description |
|
|
51
|
+
| ------------------------ | ------------- | ------------------------------------------------- |
|
|
52
|
+
| `DESIGN_DATA_BIN` | `design-data` | Path to the `design-data` binary |
|
|
53
|
+
| `DESIGN_DATA_ROOT` | — | Absolute root that relative paths are anchored to |
|
|
54
|
+
| `DESIGN_DATA_PATH` | `.` | Dataset root path |
|
|
55
|
+
| `DESIGN_DATA_COMPONENTS` | — | Override components directory |
|
|
56
|
+
| `DESIGN_DATA_FIELDS` | — | Override fields directory |
|
|
57
|
+
| `DESIGN_DATA_SCHEMAS` | — | Override schema path (for `validate`) |
|
|
58
|
+
| `DESIGN_DATA_EXCEPTIONS` | — | Override exceptions path (for `validate`) |
|
|
59
|
+
|
|
60
|
+
> **Path resolution.** The MCP client launches this server with the working
|
|
61
|
+
> directory inherited from wherever the editor was opened — which may be a
|
|
62
|
+
> subdirectory of your repo (e.g. `sdk/`), not the repo root. To stay independent
|
|
63
|
+
> of that working directory, each data path is resolved in this order:
|
|
64
|
+
>
|
|
65
|
+
> 1. **Explicit env override.** If `DESIGN_DATA_PATH` / `DESIGN_DATA_COMPONENTS` /
|
|
66
|
+
> `DESIGN_DATA_FIELDS` is set, it is used. Relative values are anchored to
|
|
67
|
+
> `DESIGN_DATA_ROOT` (absolute, recommended when launching via `npx`) or, if
|
|
68
|
+
> that is unset, to the server package's own location in the monorepo. Absolute
|
|
69
|
+
> values are used as-is.
|
|
70
|
+
> 2. **Resolved `@adobe/spectrum-design-data` package** (zero config). When no env
|
|
71
|
+
> override is set, the server resolves the installed `@adobe/spectrum-design-data`
|
|
72
|
+
> package via Node module resolution and reads its `tokens/`, `components/`, and
|
|
73
|
+
> `fields/` directories. In a pnpm workspace this follows the symlink to
|
|
74
|
+
> `packages/design-data`; when published it uses the installed dependency. This
|
|
75
|
+
> is independent of the working directory.
|
|
76
|
+
> 3. **Fallback.** `dataPath` falls back to the (anchored) current directory; the
|
|
77
|
+
> component/field overrides fall back to the `design-data` binary's own
|
|
78
|
+
> discovery (including its embedded snapshot).
|
|
79
|
+
>
|
|
80
|
+
> In a monorepo checkout you typically need no `DESIGN_DATA_*` env vars at all —
|
|
81
|
+
> resolution via the workspace package handles it.
|
|
59
82
|
|
|
60
83
|
### Example (Cursor `.cursor/mcp.json`)
|
|
61
84
|
|
|
@@ -66,10 +89,10 @@ node tools/design-data-agent-mcp/src/index.js
|
|
|
66
89
|
"command": "npx",
|
|
67
90
|
"args": ["-y", "@adobe/design-data-agent-mcp"],
|
|
68
91
|
"env": {
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
92
|
+
"DESIGN_DATA_ROOT": "/abs/path/to/your/repo",
|
|
93
|
+
"DESIGN_DATA_PATH": "packages/design-data/tokens",
|
|
94
|
+
"DESIGN_DATA_COMPONENTS": "packages/design-data/components",
|
|
95
|
+
"DESIGN_DATA_FIELDS": "packages/design-data/fields"
|
|
73
96
|
}
|
|
74
97
|
}
|
|
75
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/design-data-agent-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "MCP server and Claude Code skill for the design-data agent surface — shells out to the design-data CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
"provenance": true
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@modelcontextprotocol/sdk": "^1.27.1"
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
33
|
+
"@adobe/design-data": "2.0.0",
|
|
34
|
+
"@adobe/design-data-wasm": "0.1.0",
|
|
35
|
+
"@adobe/spectrum-design-data": "0.3.0"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
38
|
"ava": "^6.0.1"
|
|
@@ -2,80 +2,76 @@
|
|
|
2
2
|
name: design-data-agent
|
|
3
3
|
description: >
|
|
4
4
|
Validate, query, resolve, diff, and author spec-conformant design tokens and components using the
|
|
5
|
-
design-data
|
|
5
|
+
design-data MCP tools against a local dataset. Use when the user asks about design tokens, a design
|
|
6
6
|
system, token lookup, spec-conformance, drift detection, or token authoring on custom data.
|
|
7
7
|
when_to_use: >
|
|
8
8
|
Trigger on: design system, design tokens, spec-conformant, drift, validate tokens, token
|
|
9
9
|
authoring, custom dataset, DESIGN_DATA_PATH, design-data validate, design-data diff,
|
|
10
10
|
design-data write, product-context.json.
|
|
11
|
-
allowed-tools:
|
|
11
|
+
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
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# design-data agent skill
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
`@adobe/design-data-agent-mcp` provides in-process wasm tools for validating, querying,
|
|
17
|
+
resolving, diffing, and authoring spec-conformant tokens and components from any dataset
|
|
18
|
+
on the local filesystem.
|
|
17
19
|
|
|
18
|
-
Set two path variables once and reference them throughout
|
|
20
|
+
Set two path variables once and reference them throughout:
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
|
-
export DESIGN_DATA_PATH=./packages/tokens
|
|
22
|
-
export DESIGN_DATA_SPEC_PATH=./packages/design-data
|
|
23
|
+
export DESIGN_DATA_PATH=./packages/design-data/tokens
|
|
24
|
+
export DESIGN_DATA_SPEC_PATH=./packages/design-data
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
For Spectrum tokens with zero setup (embedded snapshot), use the `design-data` skill instead — this skill targets custom or repo-local datasets.
|
|
26
28
|
|
|
27
29
|
## Bootstrap
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
Add `@adobe/design-data-agent-mcp` to your `.cursor/mcp.json`:
|
|
30
32
|
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"design-data-agent": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["-y", "@adobe/design-data-agent-mcp"],
|
|
39
|
+
"env": {
|
|
40
|
+
"DESIGN_DATA_PATH": "./packages/tokens/src",
|
|
41
|
+
"DESIGN_DATA_COMPONENTS": "./packages/design-data/components",
|
|
42
|
+
"DESIGN_DATA_FIELDS": "./packages/design-data/fields"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
31
47
|
```
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
|
|
49
|
+
Adjust paths to match your dataset layout.
|
|
34
50
|
|
|
35
51
|
***
|
|
36
52
|
|
|
37
53
|
## Session start — call `primer` first
|
|
38
54
|
|
|
39
|
-
Call `primer` at the start of every session that touches design data. It returns the active
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
npx @adobe/design-data primer "$DESIGN_DATA_PATH" --format json \
|
|
43
|
-
--components-dir "$DESIGN_DATA_SPEC_PATH/components" \
|
|
44
|
-
--fields-dir "$DESIGN_DATA_SPEC_PATH/fields" \
|
|
45
|
-
--dimensions-dir "$DESIGN_DATA_SPEC_PATH/dimensions"
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Always pass `--components-dir`, `--fields-dir`, and `--dimensions-dir` explicitly. These directories live under `packages/design-data-spec/`, not under the token dataset. The CLI defaults probe those paths relative to CWD, so omitting the flags when running from an arbitrary directory (or with an absolute `DESIGN_DATA_PATH`) produces empty `components`, `taxonomyFields`, and `dimensions`.
|
|
49
|
-
|
|
50
|
-
The payload includes `specVersion`, `manifest`, `dimensions`, `components`, `taxonomyFields`, and `tokenCount`.
|
|
55
|
+
Call `primer` at the start of every session that touches design data. It returns the active
|
|
56
|
+
dimensions, component list, taxonomy fields, and token count — structural context that scopes
|
|
57
|
+
all subsequent lookups. No inputs required.
|
|
51
58
|
|
|
52
59
|
***
|
|
53
60
|
|
|
54
61
|
## Token lookup
|
|
55
62
|
|
|
56
|
-
### Resolve a token to its literal value
|
|
63
|
+
### Resolve a token to its literal value — `resolve_token`
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
[--scale desktop|mobile] \
|
|
62
|
-
[--contrast regular|high]
|
|
63
|
-
```
|
|
65
|
+
Required: `property` (string) — e.g. `"accent-background-color-default"`
|
|
66
|
+
Optional: `colorScheme` (`"light"` or `"dark"`), `scale` (`"desktop"` or `"mobile"`),
|
|
67
|
+
`contrast` (`"regular"` or `"high"`)
|
|
64
68
|
|
|
65
|
-
|
|
69
|
+
### Query tokens by filter expression — `query_tokens`
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
npx @adobe/design-data resolve accent-background-color-default "$DESIGN_DATA_PATH" \
|
|
69
|
-
--format json --color-scheme dark --scale desktop
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Query tokens by filter expression
|
|
71
|
+
Required: `filter` (string)
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Valid filter keys: `property`, `component`, `variant`, `state`, `colorScheme`, `scale`, `contrast`, `uuid`, `$schema`. Any other key is a parse error. The dimension keys (`colorScheme`, `scale`, `contrast`) accept the same enum values as the `resolve` flags (`light`/`dark`, `desktop`/`mobile`, `regular`/`high`).
|
|
73
|
+
Valid filter keys: `property`, `component`, `variant`, `state`, `colorScheme`, `scale`,
|
|
74
|
+
`contrast`, `uuid`, `$schema`.
|
|
79
75
|
|
|
80
76
|
Filter syntax examples:
|
|
81
77
|
|
|
@@ -88,64 +84,71 @@ property=background-color|property=border-color
|
|
|
88
84
|
$schema=https://spectrum.adobe.com/page/design-token/
|
|
89
85
|
```
|
|
90
86
|
|
|
91
|
-
> **Exit codes:** `0` = matches found;
|
|
87
|
+
> **Exit codes:** `0` = matches found; empty array = no matches (not an error).
|
|
92
88
|
|
|
93
89
|
***
|
|
94
90
|
|
|
95
|
-
## Component info
|
|
91
|
+
## Component info — `describe_component`
|
|
96
92
|
|
|
97
|
-
|
|
98
|
-
npx @adobe/design-data component <id> --components-dir "$DESIGN_DATA_SPEC_PATH/components"
|
|
99
|
-
```
|
|
93
|
+
Required: `id` (string) — kebab-case component ID, e.g. `button`, `action-button`
|
|
100
94
|
|
|
101
|
-
Returns the component contract: `name`, `displayName`, `options`, `anatomy`, `states`,
|
|
95
|
+
Returns the component contract: `name`, `displayName`, `options`, `anatomy`, `states`,
|
|
96
|
+
and `tokenBindings`.
|
|
102
97
|
|
|
103
|
-
|
|
98
|
+
***
|
|
104
99
|
|
|
105
|
-
|
|
100
|
+
## Validation — `validate_usage`
|
|
106
101
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
Optional inputs:
|
|
103
|
+
|
|
104
|
+
* `path` — dataset path (defaults to `DESIGN_DATA_PATH`)
|
|
105
|
+
* `strict` (boolean) — treat warnings as errors
|
|
106
|
+
* `schema_path` — override schemas directory (defaults to `@adobe/spectrum-tokens` schemas)
|
|
107
|
+
|
|
108
|
+
Runs Layer-1 JSON-Schema structural validation and Layer-2 relational rules.
|
|
109
|
+
Returns `{ valid, errors, warnings }`.
|
|
110
|
+
|
|
111
|
+
> **Note:** `--exceptions-path` (SPEC-007 naming allowlist) is not supported in the
|
|
112
|
+
> in-process path. Use the `design-data` CLI directly if you need exceptions support.
|
|
110
113
|
|
|
111
114
|
***
|
|
112
115
|
|
|
113
|
-
##
|
|
116
|
+
## Dataset diff — `diff_datasets`
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
[--schema-path <path>] \
|
|
118
|
-
[--exceptions-path <path>] \
|
|
119
|
-
[--strict]
|
|
120
|
-
```
|
|
118
|
+
Required: `oldPath`, `newPath`
|
|
119
|
+
Optional: `filter` (substring to narrow results by token name)
|
|
121
120
|
|
|
122
|
-
Returns
|
|
121
|
+
Returns `{ renamed, deprecated, reverted, added, deleted, updated }`.
|
|
123
122
|
|
|
124
123
|
***
|
|
125
124
|
|
|
126
|
-
##
|
|
125
|
+
## Product-layer authoring — `write`
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
npx @adobe/design-data diff <old-path> <new-path> --format json [--filter <expr>]
|
|
130
|
-
```
|
|
127
|
+
Write or update the product context document in the dataset.
|
|
131
128
|
|
|
132
|
-
|
|
129
|
+
Optional inputs: `output` (defaults to `$DESIGN_DATA_PATH/product-context.json`),
|
|
130
|
+
`rationale` (string)
|
|
133
131
|
|
|
134
132
|
***
|
|
135
133
|
|
|
136
|
-
##
|
|
134
|
+
## Token authoring session
|
|
137
135
|
|
|
138
|
-
|
|
136
|
+
Use the following tools in sequence to create a new token through the wizard:
|
|
139
137
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
1. **`start_authoring_session`** — start a session (returns `session_id`)
|
|
139
|
+
2. **`authoring_session_step_intent`** — provide natural-language intent; get token suggestions
|
|
140
|
+
3. **`authoring_session_step_classification`** — set layer, property, name fields
|
|
141
|
+
4. **`authoring_session_step_values`** — set mode-specific value rows
|
|
142
|
+
5. **`authoring_session_commit`** — validate and write the token to disk
|
|
143
|
+
6. **`authoring_session_cancel`** — cancel without writing
|
|
145
144
|
|
|
146
|
-
|
|
145
|
+
Helper tools: `authoring_session_get` (inspect state), `authoring_session_list` (all active sessions).
|
|
147
146
|
|
|
148
|
-
|
|
147
|
+
`authoring_session_commit` accepts an optional `schema_path` to override the schemas directory
|
|
148
|
+
for Layer-1 JSON-Schema validation before writing.
|
|
149
|
+
|
|
150
|
+
> **Note:** `authoring_session_step_intent` (NLP suggestion ranking) still delegates to the
|
|
151
|
+
> `design-data` CLI because the NLP `suggest` API is not yet on the wasm surface.
|
|
149
152
|
|
|
150
153
|
***
|
|
151
154
|
|
|
@@ -153,9 +156,8 @@ Generates a product-context scaffold at the output path (`specVersion`, `layer:
|
|
|
153
156
|
|
|
154
157
|
* **Scale values:** `desktop` and `mobile` — not `medium`/`large`.
|
|
155
158
|
* **Contrast values:** `regular` and `high` — not `standard`/`high`.
|
|
156
|
-
* **`
|
|
157
|
-
* **`
|
|
158
|
-
* **`--format json`** — always pass this in agent and script contexts; the CLI pretty-prints when stdout is a TTY.
|
|
159
|
+
* **`query_tokens` returns `[]`** when no tokens match — not an error.
|
|
160
|
+
* **`diff_datasets` filter** matches by token name substring (case-insensitive).
|
|
159
161
|
|
|
160
162
|
## When working in Cursor
|
|
161
163
|
|
|
@@ -164,24 +166,3 @@ Cursor Settings → Rules → **Add Rule** → **Remote Rule (GitHub)** → past
|
|
|
164
166
|
```
|
|
165
167
|
https://github.com/adobe/spectrum-design-data/tree/main/tools/design-data-agent-mcp/skills/design-data
|
|
166
168
|
```
|
|
167
|
-
|
|
168
|
-
For always-available tool access (higher context cost), add `@adobe/design-data-agent-mcp` to `.cursor/mcp.json`:
|
|
169
|
-
|
|
170
|
-
```json
|
|
171
|
-
{
|
|
172
|
-
"mcpServers": {
|
|
173
|
-
"design-data-agent": {
|
|
174
|
-
"command": "npx",
|
|
175
|
-
"args": ["-y", "@adobe/design-data-agent-mcp"],
|
|
176
|
-
"env": {
|
|
177
|
-
"DESIGN_DATA_PATH": "./packages/tokens/src",
|
|
178
|
-
"DESIGN_DATA_COMPONENTS": "./packages/design-data-spec/components",
|
|
179
|
-
"DESIGN_DATA_FIELDS": "./packages/design-data-spec/fields",
|
|
180
|
-
"DESIGN_DATA_DIMENSIONS": "./packages/design-data-spec/dimensions"
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
Adjust paths to match your dataset layout.
|
package/src/cli.js
CHANGED
|
@@ -14,6 +14,10 @@ import { config } from "./config.js";
|
|
|
14
14
|
export function runCli(args, { timeout = 10_000 } = {}) {
|
|
15
15
|
return new Promise((resolve, reject) => {
|
|
16
16
|
const proc = spawn(config.bin, args, {
|
|
17
|
+
// Anchor the CLI's working directory to the resolved data root so its own
|
|
18
|
+
// tier/probe logic (data_source::resolve, is_in_repo) resolves correctly
|
|
19
|
+
// even when Claude Code launched the server from a monorepo subdirectory.
|
|
20
|
+
cwd: config.dataRoot,
|
|
17
21
|
// isolates CLI stdout from the MCP JSON-RPC stream on the parent's stdout
|
|
18
22
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19
23
|
});
|
package/src/config.js
CHANGED
|
@@ -8,12 +8,70 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import { dirname, isAbsolute, resolve } from "path";
|
|
14
|
+
|
|
15
|
+
// The repo root relative to this file: src → package → tools → repo root.
|
|
16
|
+
// Used as the self-anchoring fallback when DESIGN_DATA_ROOT is not provided
|
|
17
|
+
// and the server is run from inside the monorepo checkout.
|
|
18
|
+
const SERVER_ROOT = fileURLToPath(new URL("../../..", import.meta.url));
|
|
19
|
+
|
|
20
|
+
// Claude Code launches the MCP server with the working directory inherited from
|
|
21
|
+
// wherever the editor was opened (e.g. `sdk/`), not the repo root. Relative
|
|
22
|
+
// DESIGN_DATA_* paths must therefore be anchored to a known root rather than the
|
|
23
|
+
// process CWD. Prefer an explicit absolute DESIGN_DATA_ROOT (works even when the
|
|
24
|
+
// server is launched via `npx` from the npm cache); fall back to SERVER_ROOT for
|
|
25
|
+
// in-repo runs.
|
|
26
|
+
const dataRoot = process.env.DESIGN_DATA_ROOT
|
|
27
|
+
? resolve(process.env.DESIGN_DATA_ROOT)
|
|
28
|
+
: SERVER_ROOT;
|
|
29
|
+
|
|
30
|
+
function anchorPath(p) {
|
|
31
|
+
return p && !isAbsolute(p) ? resolve(dataRoot, p) : p;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Locate a directory inside the @adobe/spectrum-design-data package via Node's
|
|
35
|
+
// module resolution. In a pnpm workspace this resolves through the symlink to
|
|
36
|
+
// `packages/design-data`; when published it resolves the installed dependency.
|
|
37
|
+
// Either way it is independent of the process working directory, so it provides
|
|
38
|
+
// a zero-config default that does not depend on where the server was launched.
|
|
39
|
+
// Returns null when the package is not installed (e.g. a standalone CLI install
|
|
40
|
+
// that relies on the design-data binary's embedded snapshot instead).
|
|
41
|
+
function resolveDataPackageDir(subdir) {
|
|
42
|
+
try {
|
|
43
|
+
const pkgJson = createRequire(import.meta.url).resolve(
|
|
44
|
+
"@adobe/spectrum-design-data/package.json",
|
|
45
|
+
);
|
|
46
|
+
return resolve(dirname(pkgJson), subdir);
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Path precedence: explicit env override (anchored to dataRoot) wins, then the
|
|
53
|
+
// resolved design-data package directory, then a final fallback.
|
|
54
|
+
//
|
|
55
|
+
// The fallback differs by field on purpose: `dataPath` is a required positional
|
|
56
|
+
// CLI argument, so it falls back to the anchored current directory. `componentsDir`
|
|
57
|
+
// and `fieldsDir` are optional `--components-dir`/`--fields-dir` flags, so they fall
|
|
58
|
+
// back to `null` (flag omitted) and let the design-data binary's own discovery —
|
|
59
|
+
// including its embedded snapshot — locate them.
|
|
11
60
|
export const config = {
|
|
12
61
|
bin: process.env.DESIGN_DATA_BIN ?? "design-data",
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
62
|
+
dataRoot,
|
|
63
|
+
dataPath:
|
|
64
|
+
anchorPath(process.env.DESIGN_DATA_PATH) ??
|
|
65
|
+
resolveDataPackageDir("tokens") ??
|
|
66
|
+
anchorPath("."),
|
|
67
|
+
schemaPath: anchorPath(process.env.DESIGN_DATA_SCHEMAS ?? null),
|
|
68
|
+
exceptionsPath: anchorPath(process.env.DESIGN_DATA_EXCEPTIONS ?? null),
|
|
69
|
+
componentsDir:
|
|
70
|
+
anchorPath(process.env.DESIGN_DATA_COMPONENTS) ??
|
|
71
|
+
resolveDataPackageDir("components") ??
|
|
72
|
+
null,
|
|
73
|
+
fieldsDir:
|
|
74
|
+
anchorPath(process.env.DESIGN_DATA_FIELDS) ??
|
|
75
|
+
resolveDataPackageDir("fields") ??
|
|
76
|
+
null,
|
|
19
77
|
};
|
package/src/tools/authoring.js
CHANGED
|
@@ -8,21 +8,27 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Authoring-session tools for design-data-agent-mcp.
|
|
13
|
+
*
|
|
14
|
+
* Most operations use @adobe/design-data (on-disk session store) and run
|
|
15
|
+
* fully in-process. The exception is authoring_session_step_intent, which still
|
|
16
|
+
* delegates to the CLI because the NLP `suggest` ranking is not yet on the wasm
|
|
17
|
+
* surface. When that API is added, step_intent can be migrated here too.
|
|
18
|
+
*/
|
|
15
19
|
|
|
20
|
+
import {
|
|
21
|
+
startSession,
|
|
22
|
+
getSession,
|
|
23
|
+
listSessions,
|
|
24
|
+
stepClassification,
|
|
25
|
+
stepValues,
|
|
26
|
+
commitSession,
|
|
27
|
+
cancelSession,
|
|
28
|
+
} from "@adobe/design-data/session";
|
|
16
29
|
import { runCli } from "../cli.js";
|
|
17
30
|
import { config } from "../config.js";
|
|
18
31
|
|
|
19
|
-
async function callCli(args) {
|
|
20
|
-
const { exitCode, stdout, stderr } = await runCli(args, { timeout: 30_000 });
|
|
21
|
-
if (exitCode !== 0)
|
|
22
|
-
throw new Error(stderr || `authoring-session exited ${exitCode}`);
|
|
23
|
-
return JSON.parse(stdout);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
32
|
export function createAuthoringTools() {
|
|
27
33
|
return [
|
|
28
34
|
{
|
|
@@ -48,7 +54,7 @@ export function createAuthoringTools() {
|
|
|
48
54
|
"dataset_path is required (or set DESIGN_DATA_PATH in the environment)",
|
|
49
55
|
);
|
|
50
56
|
}
|
|
51
|
-
return
|
|
57
|
+
return startSession(path);
|
|
52
58
|
},
|
|
53
59
|
},
|
|
54
60
|
|
|
@@ -71,15 +77,25 @@ export function createAuthoringTools() {
|
|
|
71
77
|
additionalProperties: false,
|
|
72
78
|
},
|
|
73
79
|
async handler({ session_id, intent }) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
// step_intent requires NLP suggest ranking — still uses the CLI.
|
|
81
|
+
// Will be migrated when suggest is added to the wasm surface.
|
|
82
|
+
const { exitCode, stdout, stderr } = await runCli(
|
|
83
|
+
[
|
|
84
|
+
"authoring-session",
|
|
85
|
+
"step",
|
|
86
|
+
"intent",
|
|
87
|
+
"--session-id",
|
|
88
|
+
session_id,
|
|
89
|
+
"--intent",
|
|
90
|
+
intent,
|
|
91
|
+
],
|
|
92
|
+
{ timeout: 30_000 },
|
|
93
|
+
);
|
|
94
|
+
if (exitCode !== 0)
|
|
95
|
+
throw new Error(
|
|
96
|
+
stderr || `authoring-session step intent exited ${exitCode}`,
|
|
97
|
+
);
|
|
98
|
+
return JSON.parse(stdout);
|
|
83
99
|
},
|
|
84
100
|
},
|
|
85
101
|
|
|
@@ -118,21 +134,11 @@ export function createAuthoringTools() {
|
|
|
118
134
|
additionalProperties: false,
|
|
119
135
|
},
|
|
120
136
|
async handler({ session_id, layer, property, name_fields = [] }) {
|
|
121
|
-
|
|
122
|
-
"authoring-session",
|
|
123
|
-
"step",
|
|
124
|
-
"classification",
|
|
125
|
-
"--session-id",
|
|
126
|
-
session_id,
|
|
127
|
-
"--layer",
|
|
137
|
+
return stepClassification(session_id, {
|
|
128
138
|
layer,
|
|
129
|
-
"--property",
|
|
130
139
|
property,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
args.push("--name-field", `${key}=${value}`);
|
|
134
|
-
}
|
|
135
|
-
return callCli(args);
|
|
140
|
+
nameFields: name_fields,
|
|
141
|
+
});
|
|
136
142
|
},
|
|
137
143
|
},
|
|
138
144
|
|
|
@@ -174,15 +180,7 @@ export function createAuthoringTools() {
|
|
|
174
180
|
additionalProperties: false,
|
|
175
181
|
},
|
|
176
182
|
async handler({ session_id, rows }) {
|
|
177
|
-
return
|
|
178
|
-
"authoring-session",
|
|
179
|
-
"step",
|
|
180
|
-
"values",
|
|
181
|
-
"--session-id",
|
|
182
|
-
session_id,
|
|
183
|
-
"--rows",
|
|
184
|
-
JSON.stringify(rows),
|
|
185
|
-
]);
|
|
183
|
+
return stepValues(session_id, rows);
|
|
186
184
|
},
|
|
187
185
|
},
|
|
188
186
|
|
|
@@ -217,7 +215,9 @@ export function createAuthoringTools() {
|
|
|
217
215
|
schema_path: {
|
|
218
216
|
type: "string",
|
|
219
217
|
description:
|
|
220
|
-
"Path to schemas directory
|
|
218
|
+
"Path to schemas directory containing token-types/ and token-file.json. " +
|
|
219
|
+
"Used for Layer-1 JSON-Schema validation before writing. " +
|
|
220
|
+
"Defaults to @adobe/spectrum-tokens schemas when omitted.",
|
|
221
221
|
},
|
|
222
222
|
is_override: {
|
|
223
223
|
type: "boolean",
|
|
@@ -236,22 +236,15 @@ export function createAuthoringTools() {
|
|
|
236
236
|
schema_path,
|
|
237
237
|
is_override = false,
|
|
238
238
|
}) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"--session-id",
|
|
243
|
-
session_id,
|
|
244
|
-
"--schema-url",
|
|
245
|
-
schema_url,
|
|
246
|
-
"--target",
|
|
239
|
+
return commitSession({
|
|
240
|
+
sessionId: session_id,
|
|
241
|
+
schemaUrl: schema_url,
|
|
247
242
|
target,
|
|
248
|
-
"--rationale",
|
|
249
243
|
rationale,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return callCli(args);
|
|
244
|
+
productContext: product_context,
|
|
245
|
+
schemaPath: schema_path ?? null,
|
|
246
|
+
isOverride: is_override,
|
|
247
|
+
});
|
|
255
248
|
},
|
|
256
249
|
},
|
|
257
250
|
|
|
@@ -261,18 +254,11 @@ export function createAuthoringTools() {
|
|
|
261
254
|
inputSchema: {
|
|
262
255
|
type: "object",
|
|
263
256
|
required: ["session_id"],
|
|
264
|
-
properties: {
|
|
265
|
-
session_id: { type: "string" },
|
|
266
|
-
},
|
|
257
|
+
properties: { session_id: { type: "string" } },
|
|
267
258
|
additionalProperties: false,
|
|
268
259
|
},
|
|
269
260
|
async handler({ session_id }) {
|
|
270
|
-
return
|
|
271
|
-
"authoring-session",
|
|
272
|
-
"cancel",
|
|
273
|
-
"--session-id",
|
|
274
|
-
session_id,
|
|
275
|
-
]);
|
|
261
|
+
return cancelSession(session_id);
|
|
276
262
|
},
|
|
277
263
|
},
|
|
278
264
|
|
|
@@ -282,18 +268,11 @@ export function createAuthoringTools() {
|
|
|
282
268
|
inputSchema: {
|
|
283
269
|
type: "object",
|
|
284
270
|
required: ["session_id"],
|
|
285
|
-
properties: {
|
|
286
|
-
session_id: { type: "string" },
|
|
287
|
-
},
|
|
271
|
+
properties: { session_id: { type: "string" } },
|
|
288
272
|
additionalProperties: false,
|
|
289
273
|
},
|
|
290
274
|
async handler({ session_id }) {
|
|
291
|
-
return
|
|
292
|
-
"authoring-session",
|
|
293
|
-
"get",
|
|
294
|
-
"--session-id",
|
|
295
|
-
session_id,
|
|
296
|
-
]);
|
|
275
|
+
return getSession(session_id);
|
|
297
276
|
},
|
|
298
277
|
},
|
|
299
278
|
|
|
@@ -306,7 +285,7 @@ export function createAuthoringTools() {
|
|
|
306
285
|
additionalProperties: false,
|
|
307
286
|
},
|
|
308
287
|
async handler() {
|
|
309
|
-
return
|
|
288
|
+
return listSessions();
|
|
310
289
|
},
|
|
311
290
|
},
|
|
312
291
|
];
|
package/src/tools/diff.js
CHANGED
|
@@ -8,7 +8,32 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { loadDataset } from "@adobe/design-data/load";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Filter a diff result by a substring match against token names.
|
|
15
|
+
*
|
|
16
|
+
* The diff() return shape uses camelCase (per wasm serde rename_all = "camelCase"):
|
|
17
|
+
* - renamed entries: { oldName, newName, ... }
|
|
18
|
+
* - all other entries: { name, ... }
|
|
19
|
+
*
|
|
20
|
+
* @param {object} diff - DiffResult from Dataset.diff().
|
|
21
|
+
* @param {string} filter - Substring to match (case-insensitive).
|
|
22
|
+
* @returns {object} Filtered diff with the same top-level keys.
|
|
23
|
+
*/
|
|
24
|
+
export function filterDiffByName(diff, filter) {
|
|
25
|
+
const f = filter.toLowerCase();
|
|
26
|
+
const matchName = (t) =>
|
|
27
|
+
[t.name, t.oldName, t.newName].some((n) => n?.toLowerCase().includes(f));
|
|
28
|
+
return {
|
|
29
|
+
renamed: diff.renamed.filter(matchName),
|
|
30
|
+
deprecated: diff.deprecated.filter(matchName),
|
|
31
|
+
reverted: diff.reverted.filter(matchName),
|
|
32
|
+
added: diff.added.filter(matchName),
|
|
33
|
+
deleted: diff.deleted.filter(matchName),
|
|
34
|
+
updated: diff.updated.filter(matchName),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
12
37
|
|
|
13
38
|
export function createDiffTools() {
|
|
14
39
|
return [
|
|
@@ -36,12 +61,13 @@ export function createDiffTools() {
|
|
|
36
61
|
additionalProperties: false,
|
|
37
62
|
},
|
|
38
63
|
async handler({ oldPath, newPath, filter }) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
const [oldDs, newDs] = await Promise.all([
|
|
65
|
+
loadDataset(oldPath),
|
|
66
|
+
loadDataset(newPath),
|
|
67
|
+
]);
|
|
68
|
+
const diff = oldDs.diff(newDs);
|
|
69
|
+
if (!filter) return diff;
|
|
70
|
+
return filterDiffByName(diff, filter);
|
|
45
71
|
},
|
|
46
72
|
},
|
|
47
73
|
];
|
package/src/tools/read.js
CHANGED
|
@@ -8,6 +8,19 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Read tools for design-data-agent-mcp.
|
|
13
|
+
*
|
|
14
|
+
* query_tokens and resolve_token use @adobe/design-data (loadDataset) + the
|
|
15
|
+
* wasm Dataset to run in-process without spawning the CLI binary.
|
|
16
|
+
*
|
|
17
|
+
* primer and describe_component still invoke the CLI: primer aggregates complex
|
|
18
|
+
* catalog metadata (components, fields) not yet on the wasm surface, and
|
|
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.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { loadDataset } from "@adobe/design-data/load";
|
|
11
24
|
import { runCli } from "../cli.js";
|
|
12
25
|
import { config } from "../config.js";
|
|
13
26
|
|
|
@@ -27,14 +40,13 @@ export function createReadTools() {
|
|
|
27
40
|
if (config.componentsDir)
|
|
28
41
|
args.push("--components-dir", config.componentsDir);
|
|
29
42
|
if (config.fieldsDir) args.push("--fields-dir", config.fieldsDir);
|
|
30
|
-
if (config.dimensionsDir)
|
|
31
|
-
args.push("--dimensions-dir", config.dimensionsDir);
|
|
32
43
|
const { exitCode, stdout, stderr } = await runCli(args);
|
|
33
44
|
if (exitCode !== 0)
|
|
34
45
|
throw new Error(stderr || `primer exited ${exitCode}`);
|
|
35
46
|
return JSON.parse(stdout);
|
|
36
47
|
},
|
|
37
48
|
},
|
|
49
|
+
|
|
38
50
|
{
|
|
39
51
|
name: "resolve_token",
|
|
40
52
|
description:
|
|
@@ -66,19 +78,21 @@ export function createReadTools() {
|
|
|
66
78
|
additionalProperties: false,
|
|
67
79
|
},
|
|
68
80
|
async handler({ property, colorScheme, scale, contrast }) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
const ds = await loadDataset(config.dataPath);
|
|
82
|
+
const context = {};
|
|
83
|
+
if (colorScheme) context.colorScheme = colorScheme;
|
|
84
|
+
if (scale) context.scale = scale;
|
|
85
|
+
if (contrast) context.contrast = contrast;
|
|
86
|
+
const result = ds.resolve(property, context);
|
|
87
|
+
if (!result) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`No token found for property "${property}" in context ${JSON.stringify(context)}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
80
93
|
},
|
|
81
94
|
},
|
|
95
|
+
|
|
82
96
|
{
|
|
83
97
|
name: "query_tokens",
|
|
84
98
|
description:
|
|
@@ -95,20 +109,11 @@ export function createReadTools() {
|
|
|
95
109
|
additionalProperties: false,
|
|
96
110
|
},
|
|
97
111
|
async handler({ filter }) {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
config.dataPath,
|
|
101
|
-
"--filter",
|
|
102
|
-
filter,
|
|
103
|
-
"--format",
|
|
104
|
-
"json",
|
|
105
|
-
];
|
|
106
|
-
const { exitCode, stdout, stderr } = await runCli(args);
|
|
107
|
-
// exit code 1 means no matches — still valid JSON []
|
|
108
|
-
if (exitCode > 1) throw new Error(stderr || `query exited ${exitCode}`);
|
|
109
|
-
return JSON.parse(stdout);
|
|
112
|
+
const ds = await loadDataset(config.dataPath);
|
|
113
|
+
return ds.query(filter);
|
|
110
114
|
},
|
|
111
115
|
},
|
|
116
|
+
|
|
112
117
|
{
|
|
113
118
|
name: "describe_component",
|
|
114
119
|
description:
|
package/src/tools/validate.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { validateDataset } from "@adobe/design-data/validate";
|
|
12
12
|
import { config } from "../config.js";
|
|
13
13
|
|
|
14
14
|
export function createValidateTools() {
|
|
@@ -16,7 +16,8 @@ export function createValidateTools() {
|
|
|
16
16
|
{
|
|
17
17
|
name: "validate_usage",
|
|
18
18
|
description:
|
|
19
|
-
"Validate design token usage in a dataset.
|
|
19
|
+
"Validate design token usage in a dataset. Runs Layer-1 JSON-Schema structural " +
|
|
20
|
+
"validation and Layer-2 relational rules. Returns a JSON report of violations and warnings.",
|
|
20
21
|
inputSchema: {
|
|
21
22
|
type: "object",
|
|
22
23
|
properties: {
|
|
@@ -26,23 +27,24 @@ export function createValidateTools() {
|
|
|
26
27
|
"Path to dataset to validate (defaults to DESIGN_DATA_PATH)",
|
|
27
28
|
},
|
|
28
29
|
strict: { type: "boolean", description: "Treat warnings as errors" },
|
|
30
|
+
schema_path: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description:
|
|
33
|
+
"Path to schemas directory containing token-types/ and token-file.json. " +
|
|
34
|
+
"Defaults to @adobe/spectrum-tokens schemas. Set DESIGN_DATA_SCHEMAS env var or " +
|
|
35
|
+
"pass explicitly for custom schema sets.",
|
|
36
|
+
},
|
|
29
37
|
},
|
|
30
38
|
additionalProperties: false,
|
|
31
39
|
},
|
|
32
|
-
async handler({ path, strict } = {}) {
|
|
40
|
+
async handler({ path, strict, schema_path } = {}) {
|
|
33
41
|
const target = path ?? config.dataPath;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
args.push("--dimensions-path", config.dimensionsDir);
|
|
41
|
-
if (strict === true) args.push("--strict");
|
|
42
|
-
const { exitCode, stdout, stderr } = await runCli(args);
|
|
43
|
-
if (exitCode !== 0 && !stdout)
|
|
44
|
-
throw new Error(stderr || `validate exited ${exitCode}`);
|
|
45
|
-
return JSON.parse(stdout);
|
|
42
|
+
const schemaPath = schema_path ?? config.schemaPath ?? null;
|
|
43
|
+
// NOTE: exceptionsPath (DESIGN_DATA_EXCEPTIONS / --exceptions-path) applies to the
|
|
44
|
+
// SPEC-007 naming rule in the relational layer. The in-process wasm validate() does
|
|
45
|
+
// not consume it. Passing exceptionsPath here would throw an explicit error from
|
|
46
|
+
// validateDataset — omit it and document the limitation.
|
|
47
|
+
return validateDataset(target, { schemaPath, strict: strict ?? false });
|
|
46
48
|
},
|
|
47
49
|
},
|
|
48
50
|
];
|
package/src/tools/write.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
11
|
import { join } from "path";
|
|
12
|
-
import {
|
|
12
|
+
import { writeProductContext } from "@adobe/design-data/write";
|
|
13
13
|
import { config } from "../config.js";
|
|
14
14
|
|
|
15
15
|
export function createWriteTools() {
|
|
@@ -36,12 +36,7 @@ export function createWriteTools() {
|
|
|
36
36
|
async handler({ output, rationale } = {}) {
|
|
37
37
|
const resolvedOutput =
|
|
38
38
|
output ?? join(config.dataPath, "product-context.json");
|
|
39
|
-
|
|
40
|
-
if (rationale) args.push("--rationale", rationale);
|
|
41
|
-
const { exitCode, stdout, stderr } = await runCli(args);
|
|
42
|
-
if (exitCode !== 0)
|
|
43
|
-
throw new Error(stderr || `write exited ${exitCode}`);
|
|
44
|
-
return stdout;
|
|
39
|
+
return writeProductContext({ output: resolvedOutput, rationale });
|
|
45
40
|
},
|
|
46
41
|
},
|
|
47
42
|
];
|