Skip to content

Commit 29ec8df

Browse files
poltorakSzymon.Poltorak
andauthored
#6 MCP refactoring - make storybookDocsRoot and deprecatedCssClassesPath optional in MCP config (#15)
* Remove .cursor/mcp.json from tracking (now in .gitignore) * refactor: make storybookDocsRoot and deprecatedCssClassesPath optional in MCP config * fix(): update prompts to fully respect missing param * chore: formatting * fix: error message about missing param, unify if condition --------- Co-authored-by: Szymon.Poltorak <[email protected]>
1 parent 619fa8a commit 29ec8df

File tree

16 files changed

+175
-94
lines changed

16 files changed

+175
-94
lines changed

.cursor/flows/ds-refactoring-flow/01-find-violations.mdc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ Step 1: Find violations
1919
Store the result in a variable called scanResult.
2020

2121
2. Perform first-level error handling:
22-
- If the function call returns an error, respond with:
22+
- If the function call returns an error or result containing "Missing ds.deprecatedCssClassesPath", respond with:
23+
<commentary>⚠️ *Cannot proceed: Missing required configuration parameter* – The `ds.deprecatedCssClassesPath` parameter must be provided when starting the MCP server to use violation detection tools. Please restart the server with this parameter configured.</commentary>
24+
Then stop execution.
25+
- If the function call returns any other error, respond with:
2326
<commentary>🚨 *Tool execution failed* – [error message]</commentary>
2427
Then stop execution.
2528
- If scanResult.totalViolations is 0, respond with:
@@ -57,7 +60,10 @@ Once the user provides a subfolder choice, proceed as follows:
5760
- Store the result in a variable called fileScan.
5861

5962
3. Perform error handling and validation:
60-
- If the function call returns an error, respond with:
63+
- If the function call returns an error containing "Missing ds.deprecatedCssClassesPath", respond with:
64+
<commentary>⚠️ *Cannot proceed: Missing required configuration parameter* – The `ds.deprecatedCssClassesPath` parameter must be provided when starting the MCP server to use violation detection tools. Please restart the server with this parameter configured.</commentary>
65+
Then stop execution.
66+
- If the function call returns any other error, respond with:
6167
<commentary>🚨 *Tool execution failed* – [error message]</commentary>
6268
Then stop execution.
6369
- If fileScan.rows.length is 0, respond with:

.cursor/flows/ds-refactoring-flow/01b-find-all-violations.mdc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ Step 1: Find violations
1717
Store the result in a variable called scanResult.
1818

1919
2. Perform first-level error handling:
20-
- If the function call returns an error, respond with:
20+
- If the function call returns an error or result containing "Missing ds.deprecatedCssClassesPath", respond with:
21+
<commentary>⚠️ *Cannot proceed: Missing required configuration parameter* – The `ds.deprecatedCssClassesPath` parameter must be provided when starting the MCP server to use violation detection tools. Please restart the server with this parameter configured.</commentary>
22+
Then stop execution.
23+
- If the function call returns any other error, respond with:
2124
<commentary>🚨 *Tool execution failed* – [error message]</commentary>
2225
Then stop execution.
2326
- If no violations are found, respond with:
@@ -54,7 +57,10 @@ Once the user provides a subfolder choice, proceed as follows:
5457
- Store the result in a variable called fileScan.
5558

5659
3. Perform error handling and validation:
57-
- If the function call returns an error, respond with:
60+
- If the function call returns an error containing "Missing ds.deprecatedCssClassesPath", respond with:
61+
<commentary>⚠️ *Cannot proceed: Missing required configuration parameter* – The `ds.deprecatedCssClassesPath` parameter must be provided when starting the MCP server to use violation detection tools. Please restart the server with this parameter configured.</commentary>
62+
Then stop execution.
63+
- If the function call returns any other error, respond with:
5864
<commentary>🚨 *Tool execution failed* – [error message]</commentary>
5965
Then stop execution.
6066
- If fileScan.rows.length is 0, respond with:

.cursor/mcp.json

Lines changed: 0 additions & 22 deletions
This file was deleted.

README.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ Copy `.cursor/mcp.json.example` to the project you're working on. Copied file sh
6767
}
6868
```
6969

70+
> Note: `ds.storybookDocsRoot` and `ds.deprecatedCssClassesPath` are optional. The server will start without them. Tools that require these paths will return a clear error prompting you to provide the missing parameter.
71+
7072
> **Note**: The example file contains configuration for `ESLint` official MCP which is required for the toolkit to work properly.
7173
7274
### Configuration Parameters
@@ -76,10 +78,20 @@ Copy `.cursor/mcp.json.example` to the project you're working on. Copied file sh
7678
| Parameter | Type | Description | Example |
7779
|-----------|------|-------------|---------|
7880
| `workspaceRoot` | Absolute path | Root directory of your Angular workspace | `/Users/dev/my-angular-app` |
79-
| `ds.storybookDocsRoot` | Relative path | Root directory containing Storybook documentation | `storybook/docs` |
80-
| `ds.deprecatedCssClassesPath` | Relative path | JavaScript file mapping deprecated CSS classes | `design-system/component-options.js` |
8181
| `ds.uiRoot` | Relative path | Directory containing UI components | `packages/ui` |
8282

83+
#### Optional Parameters
84+
85+
| Parameter | Type | Description | Example |
86+
|-----------|------|-------------|---------|
87+
| `ds.storybookDocsRoot` | Relative path | Root directory containing Storybook documentation used by documentation-related tools | `storybook/docs` |
88+
| `ds.deprecatedCssClassesPath` | Relative path | JavaScript file mapping deprecated CSS classes used by violation and deprecated CSS tools | `design-system/component-options.js` |
89+
90+
When optional parameters are omitted:
91+
92+
- `ds.storybookDocsRoot`: Tools will skip Storybook documentation lookups (e.g., `get-ds-component-data` will still return implementation/import data but may have no docs files).
93+
- `ds.deprecatedCssClassesPath`: Tools that require the mapping will fail fast with a clear error. Affected tools include: `get-deprecated-css-classes`, `report-deprecated-css`, `report-all-violations`, and `report-violations`.
94+
8395
#### Deprecated CSS Classes File Format
8496

8597
The `component-options.js` file should export an array of component configurations:
@@ -141,6 +153,29 @@ my-angular-workspace/
141153

142154
- **`build-component-usage-graph`**: Maps where given Angular components are imported (modules, specs, templates, styles) so refactors touch every file
143155

156+
### Tool behavior with optional parameters
157+
158+
The following tools work without optional params:
159+
160+
- `get-project-dependencies`
161+
- `build-component-usage-graph`
162+
- `get-ds-component-data` (documentation section is empty if `ds.storybookDocsRoot` is not set)
163+
- Component contract tools:
164+
- `build_component_contract`
165+
- `diff_component_contract`
166+
- `list_component_contracts`
167+
168+
The following tools require optional params to work:
169+
170+
- Requires `ds.deprecatedCssClassesPath`:
171+
- `get-deprecated-css-classes`
172+
- `report-deprecated-css`
173+
- `report-all-violations`
174+
- `report-violations`
175+
176+
- Requires `ds.storybookDocsRoot` for docs lookup (skipped otherwise):
177+
- `get-ds-component-data` (docs files discovery only)
178+
144179
### Component Contracts
145180

146181
- **`build_component_contract`**: Generate a static surface contract for a component's template and SCSS

packages/angular-mcp-server/src/lib/angular-mcp-server.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import { validateDeprecatedCssClassesFile } from './validation/ds-components-fil
2525
export class AngularMcpServerWrapper {
2626
private readonly mcpServer: McpServer;
2727
private readonly workspaceRoot: string;
28-
private readonly storybookDocsRoot: string;
29-
private readonly deprecatedCssClassesPath: string;
28+
private readonly storybookDocsRoot?: string;
29+
private readonly deprecatedCssClassesPath?: string;
3030
private readonly uiRoot: string;
3131

3232
/**
@@ -71,11 +71,13 @@ export class AngularMcpServerWrapper {
7171
// Validate config using the Zod schema - only once here
7272
const validatedConfig = AngularMcpServerOptionsSchema.parse(config);
7373

74-
// Validate file existence
74+
// Validate file existence (optional keys are checked only when provided)
7575
validateAngularMcpServerFilesExist(validatedConfig);
7676

77-
// Load and validate deprecatedCssClassesPath content
78-
await validateDeprecatedCssClassesFile(validatedConfig);
77+
// Load and validate deprecatedCssClassesPath content only if provided
78+
if (validatedConfig.ds.deprecatedCssClassesPath) {
79+
await validateDeprecatedCssClassesFile(validatedConfig);
80+
}
7981

8082
return new AngularMcpServerWrapper(validatedConfig);
8183
}
@@ -140,6 +142,12 @@ export class AngularMcpServerWrapper {
140142

141143
// Scan available design system components to add them as discoverable resources
142144
try {
145+
if (!this.storybookDocsRoot) {
146+
return {
147+
resources,
148+
};
149+
}
150+
143151
const dsUiPath = path.resolve(
144152
process.cwd(),
145153
this.storybookDocsRoot,

packages/angular-mcp-server/src/lib/tools/ds/component/get-deprecated-css-classes.tool.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ export const getDeprecatedCssClassesHandler = createHandler<
2828
>(
2929
getDeprecatedCssClassesSchema.name,
3030
async ({ componentName }, { cwd, deprecatedCssClassesPath }) => {
31+
if (!deprecatedCssClassesPath) {
32+
throw new Error(
33+
'Missing ds.deprecatedCssClassesPath. Provide --ds.deprecatedCssClassesPath in mcp.json file.',
34+
);
35+
}
3136
return getDeprecatedCssClasses(
3237
componentName,
3338
deprecatedCssClassesPath,

packages/angular-mcp-server/src/lib/tools/ds/component/get-ds-component-data.tool.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -137,31 +137,34 @@ export const getDsComponentDataHandler = createHandler<
137137
}
138138

139139
const documentationFiles: string[] = [];
140-
if (includeDocumentation) {
140+
141+
let storiesFilePaths: string[] = [];
142+
if (storybookDocsRoot) {
141143
const docsBasePath = resolveCrossPlatformPath(cwd, storybookDocsRoot);
142-
const docPaths = getComponentDocPathsForName(
143-
docsBasePath,
144-
componentName,
145-
);
146144

147-
if (fs.existsSync(docPaths.paths.api)) {
148-
documentationFiles.push(`file://${docPaths.paths.api}`);
145+
if (includeDocumentation) {
146+
const docPaths = getComponentDocPathsForName(
147+
docsBasePath,
148+
componentName,
149+
);
150+
151+
if (fs.existsSync(docPaths.paths.api)) {
152+
documentationFiles.push(`file://${docPaths.paths.api}`);
153+
}
154+
if (fs.existsSync(docPaths.paths.overview)) {
155+
documentationFiles.push(`file://${docPaths.paths.overview}`);
156+
}
149157
}
150-
if (fs.existsSync(docPaths.paths.overview)) {
151-
documentationFiles.push(`file://${docPaths.paths.overview}`);
152-
}
153-
}
154158

155-
let storiesFilePaths: string[] = [];
156-
if (includeStories) {
157-
const docsBasePath = resolveCrossPlatformPath(cwd, storybookDocsRoot);
158-
const componentFolderName = componentNameToKebabCase(componentName);
159-
const storiesComponentFolderPath = path.join(
160-
docsBasePath,
161-
componentFolderName,
162-
);
163-
const storiesFiles = findStoriesFiles(storiesComponentFolderPath);
164-
storiesFilePaths = storiesFiles.map((file) => `file://${file}`);
159+
if (includeStories) {
160+
const componentFolderName = componentNameToKebabCase(componentName);
161+
const storiesComponentFolderPath = path.join(
162+
docsBasePath,
163+
componentFolderName,
164+
);
165+
const storiesFiles = findStoriesFiles(storiesComponentFolderPath);
166+
storiesFilePaths = storiesFiles.map((file) => `file://${file}`);
167+
}
165168
}
166169

167170
return {

packages/angular-mcp-server/src/lib/tools/ds/component/list-ds-components.tool.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ export const listDsComponentsHandler = createHandler<
150150
});
151151

152152
const components: DsComponentInfo[] = [];
153-
const docsBasePath = resolveCrossPlatformPath(cwd, storybookDocsRoot);
154153

155154
const includeAll = sections.includes('all');
156155
const includeImplementation =
@@ -172,28 +171,36 @@ export const listDsComponentsHandler = createHandler<
172171
}
173172

174173
const documentationFiles: string[] = [];
175-
if (includeDocumentation) {
176-
const docPaths = getComponentDocPathsForName(
177-
docsBasePath,
178-
componentName,
174+
175+
let storiesFilePaths: string[] = [];
176+
if (storybookDocsRoot) {
177+
const docsBasePath = resolveCrossPlatformPath(
178+
cwd,
179+
storybookDocsRoot,
179180
);
180181

181-
if (fs.existsSync(docPaths.paths.api)) {
182-
documentationFiles.push(`file://${docPaths.paths.api}`);
182+
if (includeDocumentation) {
183+
const docPaths = getComponentDocPathsForName(
184+
docsBasePath,
185+
componentName,
186+
);
187+
188+
if (fs.existsSync(docPaths.paths.api)) {
189+
documentationFiles.push(`file://${docPaths.paths.api}`);
190+
}
191+
if (fs.existsSync(docPaths.paths.overview)) {
192+
documentationFiles.push(`file://${docPaths.paths.overview}`);
193+
}
183194
}
184-
if (fs.existsSync(docPaths.paths.overview)) {
185-
documentationFiles.push(`file://${docPaths.paths.overview}`);
186-
}
187-
}
188195

189-
let storiesFilePaths: string[] = [];
190-
if (includeStories) {
191-
const storiesComponentFolderPath = path.join(
192-
docsBasePath,
193-
folderName,
194-
);
195-
const storiesFiles = findStoriesFiles(storiesComponentFolderPath);
196-
storiesFilePaths = storiesFiles.map((file) => `file://${file}`);
196+
if (includeStories) {
197+
const storiesComponentFolderPath = path.join(
198+
docsBasePath,
199+
folderName,
200+
);
201+
const storiesFiles = findStoriesFiles(storiesComponentFolderPath);
202+
storiesFilePaths = storiesFiles.map((file) => `file://${file}`);
203+
}
197204
}
198205

199206
components.push({

packages/angular-mcp-server/src/lib/tools/ds/project/report-deprecated-css.tool.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ export const reportDeprecatedCssHandler = createHandler<
4242
async (params, { cwd, deprecatedCssClassesPath }) => {
4343
const { directory, componentName } = params;
4444

45+
if (!deprecatedCssClassesPath) {
46+
throw new Error(
47+
'Missing ds.deprecatedCssClassesPath. Provide --ds.deprecatedCssClassesPath in mcp.json file.',
48+
);
49+
}
50+
4551
const deprecated = getDeprecatedCssClasses(
4652
componentName,
4753
deprecatedCssClassesPath,

packages/angular-mcp-server/src/lib/tools/ds/report-violations/report-all-violations.tool.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export const reportAllViolationsHandler = createHandler<
4747
>(
4848
reportAllViolationsSchema.name,
4949
async (params, { cwd, deprecatedCssClassesPath }) => {
50+
if (!deprecatedCssClassesPath) {
51+
throw new Error(
52+
'Missing ds.deprecatedCssClassesPath. Provide --ds.deprecatedCssClassesPath in mcp.json file.',
53+
);
54+
}
5055
const groupBy = params.groupBy || 'file';
5156
const dsComponents = await loadAndValidateDsComponentsFile(
5257
cwd,

0 commit comments

Comments
 (0)