Skip to content

Commit 3dd5b2a

Browse files
authored
Merge branch 'main' into copilot/implement-mcp-server-instructions
2 parents 9fd9130 + 07f8d07 commit 3dd5b2a

16 files changed

Lines changed: 129 additions & 53 deletions

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ export { addMyTool, MY_TOOL_NAME } from './tools/my-tool.ts';
253253
- `addon-mcp` depends on `@storybook/mcp` (workspace dependency)
254254
- `AddonContext` extends `StorybookContext` to ensure type compatibility
255255
- Component manifest tools are conditionally registered based on feature flags:
256-
- Checks `features.experimentalComponentsManifest` flag
256+
- Checks `features.componentsManifest` flag (or `features.experimentalComponentsManifest` for backwards compatibility)
257257
- Checks for `experimental_manifests` preset
258258
- Only registers `addListAllDocumentationTool` and `addGetDocumentationTool` when enabled
259259
- Context includes `request` (HTTP Request object) which tools use to determine manifest location

.github/instructions/addon-mcp.instructions.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ The addon supports two toolsets that can be enabled/disabled:
3131
2. **`docs`** (default: true)
3232
- `list-all-documentation`: List all available components from manifest
3333
- `get-documentation`: Get detailed component documentation
34-
- Requires experimental feature flag `features.experimentalComponentsManifest`
3534

3635
**Configuration Methods:**
3736

eval/templates/grading/.storybook/main.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,5 @@ const config: StorybookConfig = {
99
'@storybook/addon-mcp',
1010
],
1111
framework: '@storybook/react-vite',
12-
features: {
13-
experimentalComponentsManifest: true,
14-
},
1512
};
1613
export default config;

packages/addon-mcp/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# @storybook/addon-mcp
22

3+
## 0.3.4
4+
5+
### Patch Changes
6+
7+
- [#179](https://github.com/storybookjs/mcp/pull/179) [`ec300bd`](https://github.com/storybookjs/mcp/commit/ec300bd9bf76169f537ae3358418db8973628bcf) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Improve `/mcp` HTML response
8+
9+
- [#181](https://github.com/storybookjs/mcp/pull/181) [`ff217d8`](https://github.com/storybookjs/mcp/commit/ff217d8d901b3b6ec932613792df17118b452fe3) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Rename feature flag `experimentalComponentsManifest``componentsManifest`
10+
11+
The Storybook feature flag has been renamed from `experimentalComponentsManifest` to `componentsManifest` and now defaults to `true` in Storybook core.
12+
13+
- Updated dependencies [[`ff217d8`](https://github.com/storybookjs/mcp/commit/ff217d8d901b3b6ec932613792df17118b452fe3)]:
14+
- @storybook/mcp@0.5.1
15+
316
## 0.3.3
417

518
### Patch Changes

packages/addon-mcp/README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,19 @@ export default {
4848
options: {
4949
toolsets: {
5050
dev: true, // Tools for story URL retrieval and UI building instructions (default: true)
51-
docs: true, // Tools for component manifest and documentation (default: true, requires experimental feature flag below 👇)
51+
docs: true, // Tools for component manifest and documentation (default: true)
5252
},
5353
},
5454
},
5555
],
56-
features: {
57-
experimentalComponentsManifest: true, // Enable manifest generation for the docs toolset, only supported in React-based setups.
58-
},
56+
// componentsManifest is enabled by default in recent Storybook versions, no need to set it
5957
};
6058
```
6159

6260
**Available Toolsets:**
6361

6462
- `dev`: Enables [Dev Tools](#dev-tools)
65-
- `docs`: Enables [Documentation Tools](#docs-tools-experimental)
63+
- `docs`: Enables [Documentation Tools](#docs-tools)
6664

6765
Disabling the Dev Tools is useful when you want to try out the same experience that your external component consumers will get, because they only get the Component Documentation Tools.
6866

@@ -172,24 +170,31 @@ Agent calls tool, gets response:
172170
http://localhost:6006/?path=/story/example-button--primary
173171
```
174172

175-
### Docs Tools (Experimental)
173+
### Docs Tools
176174

177-
These additional tools are available when the **experimental** component manifest feature is enabled. They provide agents with detailed documentation about your UI components.
175+
These additional tools are available when the component manifest feature is enabled. They provide agents with detailed documentation about your UI components.
178176

179177
**Requirements:**
180178

181179
- Storybook version 10.1.0 or higher (currently only available as prereleases, `storybook@next`)
182180
- React-based framework (`react-vite`, `nextjs-vite`, `nextjs`, `react-webpack5`)
183-
- Feature flag `features.experimentalComponentsManifest` set to `true` in `.storybook/main.js`
181+
- Feature flag `features.componentsManifest` enabled (defaults to `true` in recent Storybook versions)
184182

185183
**To enable:**
186184

185+
The `componentsManifest` feature is enabled by default in recent Storybook versions — no configuration needed.
186+
187+
If you are on an older Storybook version that doesn't default to `true`, you may need to enable it explicitly. Use the flag that matches your Storybook version:
188+
187189
```javascript
188190
// .storybook/main.js
189191
export default {
190192
// ... other config
191193
features: {
192-
experimentalComponentsManifest: true,
194+
// For Storybook 10.3.x and later:
195+
componentsManifest: true,
196+
// For older Storybook versions (before the flag was renamed):
197+
// experimentalComponentsManifest: true,
193198
},
194199
};
195200
```

packages/addon-mcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@storybook/addon-mcp",
3-
"version": "0.3.3",
3+
"version": "0.3.4",
44
"description": "Help agents automatically write and test stories for your UI components",
55
"keywords": [
66
"ai",

packages/addon-mcp/src/mcp-handler.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ describe('mcpServerHandler', () => {
398398
return { disableTelemetry: false };
399399
}
400400
if (key === 'features') {
401-
return { experimentalComponentsManifest: true };
401+
return { componentsManifest: true };
402402
}
403403
if (key === 'experimental_manifests') {
404404
return vi.fn();

packages/addon-mcp/src/preset.test.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, it, expect, vi, beforeEach } from 'vitest';
22
import type { Options } from 'storybook/internal/types';
33
import { experimental_devServer } from './preset.ts';
4+
import * as runStoryTests from './tools/run-story-tests.ts';
45

56
describe('experimental_devServer', () => {
67
let mockApp: any;
@@ -19,7 +20,7 @@ describe('experimental_devServer', () => {
1920
presets: {
2021
apply: vi.fn((key: string) => {
2122
if (key === 'features') {
22-
return Promise.resolve({ experimentalComponentsManifest: false });
23+
return Promise.resolve({ componentsManifest: false });
2324
}
2425
return Promise.resolve(undefined);
2526
}),
@@ -67,6 +68,53 @@ describe('experimental_devServer', () => {
6768
expect(mockRes.end).toHaveBeenCalledWith(expect.stringContaining('<html'));
6869
});
6970

71+
it('should show Storybook version requirement for addon-vitest and a manual manifest link', async () => {
72+
vi.spyOn(runStoryTests, 'getAddonVitestConstants').mockResolvedValue(undefined);
73+
const manifestEnabledOptions = {
74+
presets: {
75+
apply: vi.fn((key: string) => {
76+
if (key === 'features') {
77+
return Promise.resolve({ experimentalComponentsManifest: true });
78+
}
79+
if (key === 'experimental_manifests') {
80+
return Promise.resolve({});
81+
}
82+
return Promise.resolve(undefined);
83+
}),
84+
},
85+
} as unknown as Options;
86+
87+
const handlers: Record<string, any> = {};
88+
mockApp.get = vi.fn((path: string, handler: any) => {
89+
handlers[path] = handler;
90+
});
91+
92+
await (experimental_devServer as any)(mockApp, manifestEnabledOptions);
93+
const getMcpHandler = handlers['/mcp'];
94+
expect(getMcpHandler).toBeDefined();
95+
96+
const mockReq = {
97+
headers: {
98+
accept: 'text/html',
99+
},
100+
} as any;
101+
const mockRes = {
102+
writeHead: vi.fn(),
103+
end: vi.fn(),
104+
} as any;
105+
106+
await getMcpHandler(mockReq, mockRes);
107+
108+
expect(mockRes.end).toHaveBeenCalledWith(
109+
expect.stringContaining('This toolset requires Storybook 10.3.0+ with'),
110+
);
111+
expect(mockRes.end).toHaveBeenCalledWith(
112+
expect.stringContaining(
113+
'View the <a href="/manifests/components.html">component manifest debugger</a>.',
114+
),
115+
);
116+
});
117+
70118
it('should handle POST requests as MCP protocol', async () => {
71119
await (experimental_devServer as any)(mockApp, mockOptions);
72120

@@ -124,7 +172,7 @@ describe('experimental_devServer', () => {
124172
presets: {
125173
apply: vi.fn((key: string) => {
126174
if (key === 'features') {
127-
return Promise.resolve({ experimentalComponentsManifest: false });
175+
return Promise.resolve({ componentsManifest: false });
128176
}
129177
return Promise.resolve(undefined);
130178
}),
@@ -217,7 +265,7 @@ describe('experimental_devServer', () => {
217265
});
218266
}
219267
if (key === 'features') {
220-
return Promise.resolve({ experimentalComponentsManifest: false });
268+
return Promise.resolve({ componentsManifest: false });
221269
}
222270
return Promise.resolve(undefined);
223271
}),
@@ -237,7 +285,7 @@ describe('experimental_devServer', () => {
237285
apply: vi.fn((key: string) => {
238286
if (key === 'refs') return Promise.resolve(null);
239287
if (key === 'features') {
240-
return Promise.resolve({ experimentalComponentsManifest: false });
288+
return Promise.resolve({ componentsManifest: false });
241289
}
242290
return Promise.resolve(undefined);
243291
}),
@@ -256,7 +304,7 @@ describe('experimental_devServer', () => {
256304
apply: vi.fn((key: string) => {
257305
if (key === 'refs') return Promise.reject(new Error('Config error'));
258306
if (key === 'features') {
259-
return Promise.resolve({ experimentalComponentsManifest: false });
307+
return Promise.resolve({ componentsManifest: false });
260308
}
261309
return Promise.resolve(undefined);
262310
}),

packages/addon-mcp/src/preset.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const experimental_devServer: PresetPropertyFn<'experimental_devServer'>
120120
});
121121
}
122122

123-
// Browser request - send HTML with redirect
123+
// Browser request - send HTML
124124
res.writeHead(200, { 'Content-Type': 'text/html' });
125125

126126
let docsNotice = '';
@@ -137,7 +137,7 @@ export const experimental_devServer: PresetPropertyFn<'experimental_devServer'>
137137

138138
const testNoticeLines = [
139139
!addonVitestConstants &&
140-
`This toolset requires <code>@storybook/addon-vitest</code>. <a target="_blank" href="https://storybook.js.org/docs/writing-tests/test-addon">Learn how to set it up</a>`,
140+
`This toolset requires Storybook 10.3.0+ with <code>@storybook/addon-vitest</code>. <a target="_blank" href="https://storybook.js.org/docs/writing-tests/test-addon">Learn how to set it up</a>`,
141141
!a11yEnabled &&
142142
`Add <code>@storybook/addon-a11y</code> for accessibility testing. <a target="_blank" href="https://storybook.js.org/docs/writing-tests/accessibility-testing">Learn more</a>`,
143143
].filter(Boolean);
@@ -150,19 +150,17 @@ export const experimental_devServer: PresetPropertyFn<'experimental_devServer'>
150150
: '';
151151

152152
const html = htmlTemplate
153-
.replace(
154-
'{{REDIRECT_META}}',
155-
manifestStatus.available
156-
? // redirect the user to the component manifest page after 10 seconds
157-
'<meta http-equiv="refresh" content="10;url=/manifests/components.html" />'
158-
: // ... or hide the message about redirection
159-
'<style>#redirect-message { display: none; }</style>',
160-
)
161153
.replaceAll('{{DEV_STATUS}}', isDevEnabled ? 'enabled' : 'disabled')
162154
.replaceAll('{{DOCS_STATUS}}', isDocsEnabled ? 'enabled' : 'disabled')
163155
.replace('{{DOCS_NOTICE}}', docsNotice)
164156
.replaceAll('{{TEST_STATUS}}', isTestEnabled ? 'enabled' : 'disabled')
165157
.replace('{{TEST_NOTICE}}', testNotice)
158+
.replace(
159+
'{{MANIFEST_DEBUGGER_LINK}}',
160+
manifestStatus.available
161+
? '<p>View the <a href="/manifests/components.html">component manifest debugger</a>.</p>'
162+
: '',
163+
)
166164
.replace('{{A11Y_BADGE}}', a11yBadge);
167165
res.end(html);
168166
});

packages/addon-mcp/src/template.html

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<!doctype html>
22
<html>
33
<head>
4-
{{REDIRECT_META}}
54
<style>
65
@font-face {
76
font-family: 'Nunito Sans';
@@ -233,21 +232,7 @@ <h3>Available Toolsets</h3>
233232
</div>
234233
</div>
235234

236-
<p id="redirect-message">
237-
Automatically redirecting to
238-
<a href="/manifests/components.html">component manifest</a>
239-
in <span id="countdown">10</span> seconds...
240-
</p>
235+
{{MANIFEST_DEBUGGER_LINK}}
241236
</div>
242-
<script>
243-
let countdown = 10;
244-
const countdownElement = document.getElementById('countdown');
245-
if (countdownElement) {
246-
setInterval(() => {
247-
countdown -= 1;
248-
countdownElement.textContent = countdown.toString();
249-
}, 1000);
250-
}
251-
</script>
252237
</body>
253238
</html>

0 commit comments

Comments
 (0)