Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-get-tokens-by-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@adobe/spectrum-tokens": minor
---

Add `getTokensByFile()` export (tokens grouped by filename; complement to `getAllTokens()`).
6 changes: 6 additions & 0 deletions .changeset/mcp-token-value-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@adobe/spectrum-design-data-mcp": minor
---

Fix data loader to use getTokensByFile/getAllTokens from @adobe/spectrum-tokens.
Add query-tokens-by-value tool (search by direct or resolved alias value).
13 changes: 12 additions & 1 deletion packages/tokens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ governing permissions and limitations under the License.

import { glob } from "glob";

import { resolve } from "path";
import { basename, resolve } from "path";
import { readFile } from "fs/promises";
import * as url from "url";
import { writeFile } from "fs/promises";
Expand Down Expand Up @@ -45,6 +45,17 @@ export const isDeprecated = (token) =>
export const getFileTokens = async (tokenFileName) =>
await readJson(resolve(__dirname, "src", tokenFileName));

export const getTokensByFile = async () => {
const result = {};
await Promise.all(
tokenFileNames.map(async (filePath) => {
const fileName = basename(filePath);
result[fileName] = await readJson(filePath);
}),
);
return result;
};

export const getAllTokens = async () => {
return await Promise.all(tokenFileNames.map(getFileTokens)).then(
(tokenFileDataAr) => {
Expand Down
72 changes: 26 additions & 46 deletions tools/spectrum-design-data-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,17 @@ The server runs locally and communicates via stdio with MCP-compatible AI client

#### Token Tools

* **`query-tokens`**: Search and retrieve design tokens by name, type, or category
* **`find-tokens-by-use-case`** ⭐: Find appropriate tokens for specific component use cases (e.g., "button background", "text color", "error state")
* **`get-component-tokens`** ⭐: Get all tokens related to a specific component type
* **`get-design-recommendations`** ⭐: Get token recommendations for design decisions and component states
* **`get-token-categories`**: List all available token categories
* **`query-tokens`**: Search Spectrum tokens by name, type, or category
* **`query-tokens-by-value`**: Find tokens by direct or resolved value (follows aliases)
* **`get-token-details`**: Get detailed information about a specific token
* **`get-component-tokens`**: Get all tokens for a component name

#### Schema Tools

* **`query-component-schemas`**: Search component API schemas
* **`get-component-schema`**: Get the complete schema for a specific component
* **`list-components`**: List all available components with schemas
* **`validate-component-props`**: Validate component properties against schemas
* **`get-type-schemas`**: Get type definitions used in schemas
* **`list-components`**: List available components (no schema payload)
* **`get-component-schema`**: Full schema for one component
* **`validate-component-props`**: Validate props against schema
* **`search-components-by-feature`**: Find components by property name

## Configuration

Expand All @@ -82,7 +79,7 @@ Add to your MCP configuration (e.g., `.cursor/mcp.json` for Cursor IDE):
"mcpServers": {
"spectrum-design-data": {
"command": "npx",
"args": ["@adobe/spectrum-design-data-mcp"]
"args": ["-y", "@adobe/spectrum-design-data-mcp"]
}
}
}
Expand Down Expand Up @@ -138,55 +135,38 @@ The server uses stdio transport and follows the MCP specification. Refer to your

## Examples

### Component Building Workflow
### Component Building Workflow

#### Finding Tokens for Component Use Cases

```
Human: I'm building a primary action button. What design tokens should I use for the background color?

AI: I'll help you find the appropriate tokens for a primary button background.

[Uses find-tokens-by-use-case with useCase="button background" and componentType="button"]

For a primary action button background, I recommend these Spectrum tokens:
- accent-color-100: Primary accent color for default state
- accent-color-200: For hover states
- accent-color-300: For pressed/active states
- floating-action-button-drop-shadow-color: For drop shadows
```

#### Design Intent Recommendations
#### Component-Specific Token Discovery

```
Human: What tokens should I use for error messaging in my form validation?
Human: Show me all available button-related design tokens.

AI: I'll find tokens for error state messaging.
AI: I'll gather all button-related tokens from the Spectrum system.

[Uses get-design-recommendations with intent="negative" and context="text"]
[Uses get-component-tokens with componentName="button"]

For error messaging, use these Spectrum tokens:
- negative-color-100: Primary error text color
- negative-background-color-default: Error background areas
- negative-border-color: Error state borders
Found button-related tokens across categories:
- Color tokens: floating-action-button colors
- Layout tokens: button sizing, padding, spacing
- Examples: radio-button-control-size-small, action-button-edge-to-hold-icon...
```

#### Component-Specific Token Discovery
#### Finding Tokens by Value

```
Human: Show me all available button-related design tokens.
Human: Which tokens resolve to 1px?

AI: I'll gather all button-related tokens from the Spectrum system.
AI: I'll search for tokens whose value is 1px (direct or alias).

[Uses get-component-tokens with componentName="button"]
[Uses query-tokens-by-value with value="1px"]

Found 57 button-related tokens across categories:
- Color tokens (2): floating-action-button colors
- Layout tokens (55): button sizing, padding, spacing
- Examples: radio-button-control-size-small, action-button-edge-to-hold-icon...
Tokens with value 1px:
- border-width-100 (direct)
- picker-border-width (alias to border-width-100)
```

### Traditional Token Queries
### Token Queries

#### Querying Color Tokens

Expand Down Expand Up @@ -291,7 +271,7 @@ src/

* Always verify package integrity using `npm audit signatures`
* Keep the package updated to the latest version
* Use npx for the most secure and up-to-date execution
* Use `npx -y` for the most secure and up-to-date execution
* Report security issues through the [GitHub security advisory](https://github.com/adobe/spectrum-design-data/security/advisories)

## License
Expand Down
81 changes: 5 additions & 76 deletions tools/spectrum-design-data-mcp/src/data/tokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,86 +10,15 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License.
*/

import { readFileSync } from "fs";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
import { getTokensByFile, getAllTokens } from "@adobe/spectrum-tokens";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export const getTokenData = getTokensByFile;

/**
* Get token data from the spectrum-tokens package
* @returns {Promise<Object>} Token data organized by category
*/
export async function getTokenData() {
try {
// Try to import from the workspace package first
const spectrumTokens = await import("@adobe/spectrum-tokens");

// If the package exports token data directly, use it
if (spectrumTokens.default || spectrumTokens.tokens) {
return spectrumTokens.default || spectrumTokens.tokens;
}

// Otherwise, read the token files directly from the package
return await loadTokenFilesFromPackage();
} catch (error) {
console.error(
"Failed to load token data from package, trying direct file access:",
error,
);
return await loadTokenFilesDirectly();
}
}

/**
* Load token files from the spectrum-tokens package structure
* @returns {Promise<Object>} Token data
*/
async function loadTokenFilesFromPackage() {
// This would be the ideal approach - loading from the actual package
// For now, we'll fall back to direct file access
return await loadTokenFilesDirectly();
}

/**
* Load token files directly from the repository structure
* @returns {Promise<Object>} Token data
*/
async function loadTokenFilesDirectly() {
const tokenData = {};

// Path to the tokens source directory
const tokensPath = join(__dirname, "../../../../packages/tokens/src");

// List of token files to load
const tokenFiles = [
"color-aliases.json",
"color-component.json",
"color-palette.json",
"icons.json",
"layout-component.json",
"layout.json",
"semantic-color-palette.json",
"typography.json",
];

for (const fileName of tokenFiles) {
try {
const filePath = join(tokensPath, fileName);
const fileContent = readFileSync(filePath, "utf8");
tokenData[fileName] = JSON.parse(fileContent);
} catch (error) {
console.error(`Failed to load token file ${fileName}:`, error);
// Continue loading other files even if one fails
}
}

return tokenData;
}
/** Flat { tokenName: tokenData } map — used for alias resolution */
export const getFlatTokenMap = getAllTokens;

/**
* Get available token categories
* Get available token categories (filenames without .json)
* @returns {Promise<Array<string>>} List of token categories
*/
export async function getTokenCategories() {
Expand Down
5 changes: 1 addition & 4 deletions tools/spectrum-design-data-mcp/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ export function createMCPServer() {
content: [
{
type: "text",
text:
typeof result === "string"
? result
: JSON.stringify(result, null, 2),
text: typeof result === "string" ? result : JSON.stringify(result),
},
],
};
Expand Down
Loading