@storybook/addon-mcp 0.1.0 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +50 -3
  2. package/dist/preset.js +61 -14
  3. package/package.json +6 -6
package/README.md CHANGED
@@ -15,7 +15,7 @@ The addon provides tools to improve agents' UI development capabilities, retriev
15
15
  ### Installation and Setup
16
16
 
17
17
  > [!NOTE]
18
- > This addon requires Storybook 10.1 or higher, currently only available as the canary version `0.0.0-pr-32810-sha-6e759c7e`.
18
+ > This addon requires Storybook version 9.1.16 or higher.
19
19
 
20
20
  Use Storybook's CLI to automatically install and configure the addon:
21
21
 
@@ -33,6 +33,52 @@ npm run storybook
33
33
 
34
34
  The MCP server will be available at `<your_storybook_dev_server_origin>/mcp` when Storybook is running.
35
35
 
36
+ ### Configuration
37
+
38
+ #### Addon Options
39
+
40
+ You can configure which toolsets are enabled by default in your `.storybook/main.js`:
41
+
42
+ ```javascript
43
+ // .storybook/main.js
44
+ export default {
45
+ addons: [
46
+ {
47
+ name: '@storybook/addon-mcp',
48
+ options: {
49
+ toolsets: {
50
+ 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)
52
+ },
53
+ },
54
+ },
55
+ ],
56
+ };
57
+ ```
58
+
59
+ **Available Toolsets:**
60
+
61
+ - `dev`: Enables [Dev Tools](#dev-tools)
62
+ - `docs`: Enables [Documentation Tools](#docs-tools-experimental)
63
+
64
+ 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.
65
+
66
+ #### Configuring toolsets with headers
67
+
68
+ You can also configure the available toolsets when setting up the MCP Server in your MCP Client by setting the `X-MCP-Toolsets` header. The header is a comma-separated list of toolset names, `X-MCP-Toolsets: dev,docs`. Eg. to configure your client to only have the Component Documentation Tools, the `.mcp.json`-file could look like this (format depends on the exact client you're using):
69
+
70
+ ```json
71
+ {
72
+ "storybook-mcp": {
73
+ "url": "http://localhost:6006/mcp",
74
+ "type": "http",
75
+ "headers": {
76
+ "X-MCP-Toolsets": "docs"
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
36
82
  ### Configuring Your Agent
37
83
 
38
84
  > [!NOTE]
@@ -88,7 +134,7 @@ This addon provides MCP tools that your agent can use. The goal is that the agen
88
134
 
89
135
  **If you are prompting from an IDE like VSCode or Cursor, be sure to use `Agent` mode and `sonnet-4.5` or better.**
90
136
 
91
- ### Core Tools
137
+ ### Dev Tools
92
138
 
93
139
  These tools are always available when the addon is installed:
94
140
 
@@ -119,12 +165,13 @@ Agent calls tool, gets response:
119
165
  http://localhost:6006/?path=/story/example-button--primary
120
166
  ```
121
167
 
122
- ### Component Documentation Tools (Experimental)
168
+ ### Docs Tools (Experimental)
123
169
 
124
170
  These additional tools are available when the **experimental** component manifest feature is enabled. They provide agents with detailed documentation about your UI components.
125
171
 
126
172
  **Requirements:**
127
173
 
174
+ - Storybook version 10.1.0 or higher (currently only available as prereleases, `storybook@next`)
128
175
  - React-based framework (`react-vite`, `nextjs-vite`, `nextjs`, `react-webpack5`)
129
176
  - Feature flag `features.experimentalComponentsManifest` set to `true` in `.storybook/main.js`
130
177
 
package/dist/preset.js CHANGED
@@ -11,7 +11,7 @@ import { buffer } from "node:stream/consumers";
11
11
 
12
12
  //#region package.json
13
13
  var name = "@storybook/addon-mcp";
14
- var version = "0.1.0";
14
+ var version = "0.1.2";
15
15
  var description = "Help agents automatically write and test stories for your UI components";
16
16
 
17
17
  //#endregion
@@ -69,6 +69,13 @@ const errorToMCPContent = (error) => {
69
69
 
70
70
  //#endregion
71
71
  //#region src/types.ts
72
+ const AddonOptions = v.object({ toolsets: v.optional(v.object({
73
+ dev: v.exactOptional(v.boolean(), true),
74
+ docs: v.exactOptional(v.boolean(), true)
75
+ }), {
76
+ dev: true,
77
+ docs: true
78
+ }) });
72
79
  /**
73
80
  * Schema for a single story input when requesting story URLs.
74
81
  */
@@ -95,7 +102,8 @@ async function addGetStoryUrlsTool(server) {
95
102
  name: GET_STORY_URLS_TOOL_NAME,
96
103
  title: "Get stories' URLs",
97
104
  description: `Get the URL for one or more stories.`,
98
- schema: GetStoryUrlsInput
105
+ schema: GetStoryUrlsInput,
106
+ enabled: () => server.ctx.custom?.toolsets?.dev ?? true
99
107
  }, async (input) => {
100
108
  try {
101
109
  const { origin: origin$1, disableTelemetry } = server.ctx.custom ?? {};
@@ -155,7 +163,8 @@ async function addGetUIBuildingInstructionsTool(server) {
155
163
  description: `Instructions on how to do UI component development.
156
164
 
157
165
  ALWAYS call this tool before doing any UI/frontend/React/component development, including but not
158
- limited to adding or updating new components, pages, screens or layouts.`
166
+ limited to adding or updating new components, pages, screens or layouts.`,
167
+ enabled: () => server.ctx.custom?.toolsets?.dev ?? true
159
168
  }, async () => {
160
169
  try {
161
170
  const { options, disableTelemetry } = server.ctx.custom ?? {};
@@ -217,27 +226,44 @@ const initializeMCPServer = async (options) => {
217
226
  const [features, componentManifestGenerator] = await Promise.all([options.presets.apply("features"), options.presets.apply("experimental_componentManifestGenerator")]);
218
227
  if (features.experimentalComponentsManifest && componentManifestGenerator) {
219
228
  logger.info("Experimental components manifest feature detected - registering component tools");
220
- await addListAllComponentsTool(server);
221
- await addGetComponentDocumentationTool(server);
229
+ const contextAwareEnabled = () => server.ctx.custom?.toolsets?.docs ?? true;
230
+ await addListAllComponentsTool(server, contextAwareEnabled);
231
+ await addGetComponentDocumentationTool(server, contextAwareEnabled);
222
232
  }
223
233
  transport = new HttpTransport(server, { path: null });
224
234
  origin = `http://localhost:${options.port}`;
225
235
  logger.debug("MCP server origin:", origin);
236
+ return server;
226
237
  };
227
- /**
228
- * Vite middleware handler that wraps the MCP handler.
229
- * This converts Node.js IncomingMessage/ServerResponse to Web API Request/Response.
230
- */
231
- const mcpServerHandler = async (req, res, next, options) => {
232
- const { disableTelemetry = false } = await options.presets.apply("core", {});
238
+ const mcpServerHandler = async ({ req, res, next, options, addonOptions }) => {
239
+ const disableTelemetry = options.disableTelemetry ?? false;
233
240
  if (!initialize) initialize = initializeMCPServer(options);
234
- await initialize;
241
+ const server = await initialize;
235
242
  const webRequest = await incomingMessageToWebRequest(req);
236
243
  const addonContext = {
237
244
  options,
245
+ toolsets: getToolsets(webRequest, addonOptions),
238
246
  origin,
239
247
  disableTelemetry,
240
- source: `${origin}/manifests/components.json`
248
+ source: `${origin}/manifests/components.json`,
249
+ ...!disableTelemetry && {
250
+ onListAllComponents: async ({ manifest }) => {
251
+ await collectTelemetry({
252
+ event: "tool:listAllComponents",
253
+ server,
254
+ componentCount: Object.keys(manifest.components).length
255
+ });
256
+ },
257
+ onGetComponentDocumentation: async ({ input, foundComponents, notFoundIds }) => {
258
+ await collectTelemetry({
259
+ event: "tool:getComponentDocumentation",
260
+ server,
261
+ inputComponentCount: input.componentIds.length,
262
+ foundCount: foundComponents.length,
263
+ notFoundCount: notFoundIds.length
264
+ });
265
+ }
266
+ }
241
267
  };
242
268
  const response = await transport.respond(webRequest, addonContext);
243
269
  if (response) await webResponseToServerResponse(response, res);
@@ -278,11 +304,32 @@ async function webResponseToServerResponse(webResponse, nodeResponse) {
278
304
  }
279
305
  nodeResponse.end();
280
306
  }
307
+ function getToolsets(request, addonOptions) {
308
+ const toolsetHeader = request.headers.get("X-MCP-Toolsets");
309
+ if (!toolsetHeader || toolsetHeader.trim() === "") return addonOptions.toolsets;
310
+ const toolsets = {
311
+ dev: false,
312
+ docs: false
313
+ };
314
+ const enabledToolsets = toolsetHeader.split(",");
315
+ for (const enabledToolset of enabledToolsets) {
316
+ const trimmedToolset = enabledToolset.trim();
317
+ if (trimmedToolset in toolsets) toolsets[trimmedToolset] = true;
318
+ }
319
+ return toolsets;
320
+ }
281
321
 
282
322
  //#endregion
283
323
  //#region src/preset.ts
284
324
  const experimental_devServer = (app, options) => {
285
- app.use("/mcp", (req, res, next) => mcpServerHandler(req, res, next, options));
325
+ const addonOptions = v.parse(AddonOptions, { toolsets: options.toolsets ?? {} });
326
+ app.use("/mcp", (req, res, next) => mcpServerHandler({
327
+ req,
328
+ res,
329
+ next,
330
+ options,
331
+ addonOptions
332
+ }));
286
333
  return app;
287
334
  };
288
335
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/addon-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Help agents automatically write and test stories for your UI components",
5
5
  "keywords": [
6
6
  "storybook-addon",
@@ -27,10 +27,10 @@
27
27
  ],
28
28
  "dependencies": {
29
29
  "@tmcp/adapter-valibot": "^0.1.4",
30
- "@tmcp/transport-http": "^0.7.0",
31
- "tmcp": "^1.15.2",
30
+ "@tmcp/transport-http": "^0.8.0",
31
+ "tmcp": "^1.16.0",
32
32
  "valibot": "^1.1.0",
33
- "@storybook/mcp": "0.0.4"
33
+ "@storybook/mcp": "0.0.6"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "20.19.0",
@@ -40,10 +40,10 @@
40
40
  "tsdown": "^0.15.9",
41
41
  "typescript": "^5.9.3",
42
42
  "vite": "^7.0.5",
43
- "vitest": "^3.2.4"
43
+ "vitest": "3.2.4"
44
44
  },
45
45
  "peerDependencies": {
46
- "storybook": "0.0.0-pr-32810-sha-6e759c7e"
46
+ "storybook": "^9.1.16 || ^10.0.0"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public"