@adobe/design-data-agent-mcp 1.3.0 → 1.4.1
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 +37 -14
- package/package.json +9 -8
- package/skills/design-data/SKILL.md +7 -9
- package/src/cli.js +4 -0
- package/src/config.js +64 -6
- package/src/index.js +16 -2
- package/src/tools/read.js +0 -5
- package/src/tools/validate.js +0 -3
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.4.1",
|
|
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",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"README.md",
|
|
15
15
|
"LICENSE"
|
|
16
16
|
],
|
|
17
|
-
"scripts": {
|
|
18
|
-
"start": "node src/index.js",
|
|
19
|
-
"test": "ava"
|
|
20
|
-
},
|
|
21
17
|
"repository": {
|
|
22
18
|
"type": "git",
|
|
23
19
|
"url": "git+https://github.com/adobe/spectrum-design-data.git",
|
|
@@ -33,7 +29,8 @@
|
|
|
33
29
|
"provenance": true
|
|
34
30
|
},
|
|
35
31
|
"dependencies": {
|
|
36
|
-
"@modelcontextprotocol/sdk": "^1.27.1"
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
33
|
+
"@adobe/spectrum-design-data": "0.3.0"
|
|
37
34
|
},
|
|
38
35
|
"devDependencies": {
|
|
39
36
|
"ava": "^6.0.1"
|
|
@@ -50,5 +47,9 @@
|
|
|
50
47
|
"cli"
|
|
51
48
|
],
|
|
52
49
|
"author": "Adobe",
|
|
53
|
-
"license": "Apache-2.0"
|
|
54
|
-
|
|
50
|
+
"license": "Apache-2.0",
|
|
51
|
+
"scripts": {
|
|
52
|
+
"start": "node src/index.js",
|
|
53
|
+
"test": "ava"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -18,8 +18,8 @@ allowed-tools: Bash(npx @adobe/design-data *)
|
|
|
18
18
|
Set two path variables once and reference them throughout. The token dataset and the spec catalog (components, fields, dimensions) live in separate directories:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
export DESIGN_DATA_PATH=./packages/tokens
|
|
22
|
-
export DESIGN_DATA_SPEC_PATH=./packages/design-data
|
|
21
|
+
export DESIGN_DATA_PATH=./packages/design-data/tokens
|
|
22
|
+
export DESIGN_DATA_SPEC_PATH=./packages/design-data
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
For Spectrum tokens with zero setup (embedded snapshot), use the `design-data` skill instead — this skill targets custom or repo-local datasets.
|
|
@@ -41,13 +41,12 @@ Call `primer` at the start of every session that touches design data. It returns
|
|
|
41
41
|
```bash
|
|
42
42
|
npx @adobe/design-data primer "$DESIGN_DATA_PATH" --format json \
|
|
43
43
|
--components-dir "$DESIGN_DATA_SPEC_PATH/components" \
|
|
44
|
-
--fields-dir "$DESIGN_DATA_SPEC_PATH/fields"
|
|
45
|
-
--dimensions-dir "$DESIGN_DATA_SPEC_PATH/dimensions"
|
|
44
|
+
--fields-dir "$DESIGN_DATA_SPEC_PATH/fields"
|
|
46
45
|
```
|
|
47
46
|
|
|
48
|
-
Always pass `--components-dir
|
|
47
|
+
Always pass `--components-dir` and `--fields-dir` explicitly. These directories live under `packages/design-data/`, alongside 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` and `taxonomyFields`.
|
|
49
48
|
|
|
50
|
-
The payload includes `specVersion`, `manifest`, `
|
|
49
|
+
The payload includes `specVersion`, `manifest`, `components`, `taxonomyFields`, and `tokenCount`.
|
|
51
50
|
|
|
52
51
|
***
|
|
53
52
|
|
|
@@ -175,9 +174,8 @@ For always-available tool access (higher context cost), add `@adobe/design-data-
|
|
|
175
174
|
"args": ["-y", "@adobe/design-data-agent-mcp"],
|
|
176
175
|
"env": {
|
|
177
176
|
"DESIGN_DATA_PATH": "./packages/tokens/src",
|
|
178
|
-
"DESIGN_DATA_COMPONENTS": "./packages/design-data
|
|
179
|
-
"DESIGN_DATA_FIELDS": "./packages/design-data
|
|
180
|
-
"DESIGN_DATA_DIMENSIONS": "./packages/design-data-spec/dimensions"
|
|
177
|
+
"DESIGN_DATA_COMPONENTS": "./packages/design-data/components",
|
|
178
|
+
"DESIGN_DATA_FIELDS": "./packages/design-data/fields"
|
|
181
179
|
}
|
|
182
180
|
}
|
|
183
181
|
}
|
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/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
// governing permissions and limitations under the License.
|
|
11
11
|
|
|
12
|
-
import { readFileSync } from "fs";
|
|
12
|
+
import { readFileSync, realpathSync } from "fs";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
14
14
|
import { resolve, dirname } from "path";
|
|
15
15
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -89,7 +89,21 @@ async function startServer() {
|
|
|
89
89
|
console.error("design-data-agent-mcp started");
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
// Resolve real paths so the entry-point check still matches when this module is
|
|
93
|
+
// launched through a symlink (e.g. node_modules/.bin shim created by npx/pnpm).
|
|
94
|
+
function isMainModule() {
|
|
95
|
+
const entry = process.argv[1];
|
|
96
|
+
if (!entry) return false;
|
|
97
|
+
const here = fileURLToPath(import.meta.url);
|
|
98
|
+
if (entry === here) return true;
|
|
99
|
+
try {
|
|
100
|
+
return realpathSync(entry) === realpathSync(here);
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (isMainModule()) {
|
|
93
107
|
startServer().catch((err) => {
|
|
94
108
|
console.error(err);
|
|
95
109
|
process.exit(1);
|
package/src/tools/read.js
CHANGED
|
@@ -27,8 +27,6 @@ export function createReadTools() {
|
|
|
27
27
|
if (config.componentsDir)
|
|
28
28
|
args.push("--components-dir", config.componentsDir);
|
|
29
29
|
if (config.fieldsDir) args.push("--fields-dir", config.fieldsDir);
|
|
30
|
-
if (config.dimensionsDir)
|
|
31
|
-
args.push("--dimensions-dir", config.dimensionsDir);
|
|
32
30
|
const { exitCode, stdout, stderr } = await runCli(args);
|
|
33
31
|
if (exitCode !== 0)
|
|
34
32
|
throw new Error(stderr || `primer exited ${exitCode}`);
|
|
@@ -67,9 +65,6 @@ export function createReadTools() {
|
|
|
67
65
|
},
|
|
68
66
|
async handler({ property, colorScheme, scale, contrast }) {
|
|
69
67
|
const args = ["resolve", property, config.dataPath, "--format", "json"];
|
|
70
|
-
// resolve uses --dimensions-path (old flag name, not --dimensions-dir)
|
|
71
|
-
if (config.dimensionsDir)
|
|
72
|
-
args.push("--dimensions-path", config.dimensionsDir);
|
|
73
68
|
if (colorScheme) args.push("--color-scheme", colorScheme);
|
|
74
69
|
if (scale) args.push("--scale", scale);
|
|
75
70
|
if (contrast) args.push("--contrast", contrast);
|
package/src/tools/validate.js
CHANGED
|
@@ -35,9 +35,6 @@ export function createValidateTools() {
|
|
|
35
35
|
if (config.schemaPath) args.push("--schema-path", config.schemaPath);
|
|
36
36
|
if (config.exceptionsPath)
|
|
37
37
|
args.push("--exceptions-path", config.exceptionsPath);
|
|
38
|
-
// validate uses --dimensions-path (old flag name, not --dimensions-dir)
|
|
39
|
-
if (config.dimensionsDir)
|
|
40
|
-
args.push("--dimensions-path", config.dimensionsDir);
|
|
41
38
|
if (strict === true) args.push("--strict");
|
|
42
39
|
const { exitCode, stdout, stderr } = await runCli(args);
|
|
43
40
|
if (exitCode !== 0 && !stdout)
|