Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
32ceb08
Add get-changed-stories tool and update documentation
ghengeveld Apr 22, 2026
aee78f6
Update Storybook packages
ghengeveld Apr 22, 2026
8ed1d0d
Enhance E2E tests and improve Storybook shutdown process
ghengeveld Apr 22, 2026
c7cf5a4
Refactor get-changed-stories tool to avoid structuredContent and enha…
ghengeveld Apr 28, 2026
63a1fb1
Cleanup
ghengeveld Apr 28, 2026
0f33863
Implement early return in getChangedStories tool when no relevant sta…
ghengeveld Apr 28, 2026
7403d35
Add coverage for status-store compatibility paths.
ghengeveld Apr 28, 2026
85aa4f4
Normalize dev instruction markdown formatting.
ghengeveld Apr 28, 2026
8f1bce8
Refine story-linking fallback guidance in instructions.
ghengeveld Apr 28, 2026
6684af6
Add changeset
ghengeveld Apr 28, 2026
46c2771
Formatting
ghengeveld Apr 28, 2026
0f314df
Update get-changed-stories tests to include type assertion for story …
ghengeveld Apr 28, 2026
144b4b1
Align E2E tools-list snapshot with get-changed-stories contract.
ghengeveld Apr 28, 2026
793240c
Update change detection terminology from "affected" to "related"
ghengeveld Apr 29, 2026
0e606fb
Remove newline
ghengeveld Apr 29, 2026
9b0836e
Fix mcp-composition E2E test to branch assertion on hasRemoteSource a…
Copilot Apr 29, 2026
1057a64
Update packages/addon-mcp/src/tools/get-changed-stories.ts
ghengeveld Apr 29, 2026
0b508c9
Cleanup and tweaks
ghengeveld Apr 29, 2026
2a0a7c5
Cleanup
ghengeveld Apr 29, 2026
ecc6804
Revert "Fix mcp-composition E2E test to branch assertion on hasRemote…
ghengeveld Apr 29, 2026
fed0101
Update apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts
ghengeveld Apr 29, 2026
99aff8a
Cleanup
ghengeveld Apr 29, 2026
825c292
Extended timeout should not be necessary
ghengeveld Apr 29, 2026
ac063ec
Refactor MCP Composition E2E tests to remove reliance on hasRemoteSou…
ghengeveld Apr 29, 2026
8b51f0d
Add change detection feature to Storybook configuration and update E2…
ghengeveld Apr 29, 2026
3bf69df
Swap import
ghengeveld Apr 30, 2026
d2d0c5c
Do not include get-changed-stories instructions when changeDetection …
ghengeveld Apr 30, 2026
60ce580
Handle Copilot review feedback
ghengeveld Apr 30, 2026
ef1008d
Upgrade to latest Storybook prerelease
ghengeveld Apr 30, 2026
7eae68b
Fix tool order
ghengeveld Apr 30, 2026
69a656d
Revert e2e test changes
ghengeveld Apr 30, 2026
c7ff8dd
Improve type
ghengeveld Apr 30, 2026
27f434f
Omit changes for stories that are not in the index
ghengeveld Apr 30, 2026
1bae9bd
Update packages/addon-mcp/src/instructions/build-server-instructions.ts
ghengeveld Apr 30, 2026
80654ab
Update test to omit stories not in the index
ghengeveld Apr 30, 2026
61787b2
Add changeDetectionEnabled flag to buildServerInstructions tests
ghengeveld Apr 30, 2026
ca2c9fa
Upgrade storybook
ghengeveld Apr 30, 2026
f922ce0
Update packages/addon-mcp/src/tools/get-storybook-story-instructions.…
ghengeveld Apr 30, 2026
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
6 changes: 6 additions & 0 deletions .changeset/icy-walls-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@storybook/addon-mcp": minor
---

Introduced the `get-changed-stories` tool to retrieve metadata for stories marked as new, modified, or affected.
Comment thread
ghengeveld marked this conversation as resolved.
Updated `dev-instructions.md` and `storybook-story-instructions.md` to reflect the new workflow for calling `get-changed-stories` before `preview-stories`.
1 change: 1 addition & 0 deletions apps/internal-storybook/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const config = defineMain({
disableTelemetry: true,
},
features: {
changeDetection: true,
experimentalComponentsManifest: true,
},
// No refs - single source mode
Expand Down
180 changes: 107 additions & 73 deletions apps/internal-storybook/pnpm-lock.yaml

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions apps/internal-storybook/tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,20 @@ export async function stopStorybook(storybookProcess: ReturnType<typeof x> | nul
if (!storybookProcess || !storybookProcess.process) {
return;
}
const kill = Promise.withResolvers<void>();
storybookProcess.process.on('exit', kill.resolve);
const exitSignal = Promise.withResolvers<void>();
storybookProcess.process.on('exit', exitSignal.resolve);
storybookProcess.kill('SIGTERM');
await kill.promise;

// Storybook can ignore SIGTERM while workers are shutting down.
// Escalate to SIGKILL after a short grace period to keep tests bounded.
const killTimeout = setTimeout(() => {
try {
storybookProcess.kill('SIGKILL');
} catch {
// Process may already be gone.
}
}, 10_000);

await exitSignal.promise;
clearTimeout(killTimeout);
Comment thread
ghengeveld marked this conversation as resolved.
}
13 changes: 12 additions & 1 deletion apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('MCP Endpoint E2E Tests', () => {

expect(response.result).toHaveProperty('tools');
// Dev, docs, and test tools should be present
expect(response.result.tools).toHaveLength(6);
expect(response.result.tools).toHaveLength(7);

Comment thread
ghengeveld marked this conversation as resolved.
expect(response.result.tools).toMatchInlineSnapshot(`
[
Expand Down Expand Up @@ -369,6 +369,15 @@ describe('MCP Endpoint E2E Tests', () => {
"name": "get-storybook-story-instructions",
"title": "Storybook Story Development Instructions",
},
{
"description": "Get Storybook stories marked as new, modified, or related. Returns story metadata only (no URLs).",
"inputSchema": {
"properties": {},
"type": "object",
},
"name": "get-changed-stories",
"title": "Get changed stories metadata",
},
{
"description": "Run story tests.
Provide stories for focused runs (faster while iterating),
Expand Down Expand Up @@ -846,6 +855,7 @@ describe('MCP Endpoint E2E Tests', () => {
expect(result1.result).toBeDefined();
expect(result1.result.content).toBeDefined();
expect(result1.result.content.length).toBeGreaterThan(0);

expect(result1.result.content[0].text).toContain('example-button--primary');
expect(result1.result.content[0].text).toContain('Passing Stories');

Expand Down Expand Up @@ -890,6 +900,7 @@ describe('MCP Endpoint E2E Tests', () => {
[
"preview-stories",
"get-storybook-story-instructions",
"get-changed-stories",
]
`);
});
Expand Down
124 changes: 75 additions & 49 deletions eval/pnpm-lock.yaml

Large diffs are not rendered by default.

50 changes: 28 additions & 22 deletions packages/addon-mcp/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('buildServerInstructions', () => {
devEnabled: true,
testEnabled: true,
docsEnabled: true,
changeDetectionEnabled: true,
});

expect(instructions).toMatchInlineSnapshot(`
Expand All @@ -16,7 +17,7 @@ describe('buildServerInstructions', () => {

- Before creating or editing components or stories, call **get-storybook-story-instructions**.
- Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions.
- After changing any component or story, call **preview-stories**.
- After changing any component or story, call **get-changed-stories** to discover new/modified/related stories, then call **preview-stories** to retrieve preview URLs.
- Always include every returned preview URL in your user-facing response so the user can verify the visual result.

## Validation Workflow
Expand Down Expand Up @@ -51,6 +52,7 @@ describe('buildServerInstructions', () => {
devEnabled: true,
testEnabled: false,
docsEnabled: false,
changeDetectionEnabled: true,
});

expect(instructions).toMatchInlineSnapshot(`
Expand All @@ -60,7 +62,27 @@ describe('buildServerInstructions', () => {

- Before creating or editing components or stories, call **get-storybook-story-instructions**.
- Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions.
- After changing any component or story, call **preview-stories**.
- After changing any component or story, call **get-changed-stories** to discover new/modified/related stories, then call **preview-stories** to retrieve preview URLs.
- Always include every returned preview URL in your user-facing response so the user can verify the visual result."
`);
});

it('omits get-changed-stories step when change detection is disabled', () => {
const instructions = buildServerInstructions({
devEnabled: true,
testEnabled: false,
docsEnabled: false,
changeDetectionEnabled: false,
});

expect(instructions).toMatchInlineSnapshot(`
"Follow these workflows when working with UI and/or Storybook.

## UI Building and Story Writing Workflow

- Before creating or editing components or stories, call **get-storybook-story-instructions**.
- Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions.
- After changing any component or story, call **preview-stories** to retrieve preview URLs.
- Always include every returned preview URL in your user-facing response so the user can verify the visual result."
`);
});
Expand Down
12 changes: 11 additions & 1 deletion packages/addon-mcp/src/instructions/build-server-instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@ export type BuildServerInstructionsOptions = {
devEnabled: boolean;
testEnabled: boolean;
docsEnabled: boolean;
changeDetectionEnabled?: boolean;
};

export function buildServerInstructions(options: BuildServerInstructionsOptions): string {
const sections = ['Follow these workflows when working with UI and/or Storybook.'];

if (options.devEnabled) {
sections.push(devInstructions.trim());
sections.push(
devInstructions
.replace(
'{{PREVIEW_STORIES_STEP}}',
(options.changeDetectionEnabled ?? false)
? 'After changing any component or story, call **get-changed-stories** to discover new/modified/related stories, then call **preview-stories** to retrieve preview URLs.'
: 'After changing any component or story, call **preview-stories** to retrieve preview URLs.',
)
.trim(),
);
}

if (options.testEnabled) {
Expand Down
2 changes: 1 addition & 1 deletion packages/addon-mcp/src/instructions/dev-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

- Before creating or editing components or stories, call **get-storybook-story-instructions**.
- Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions.
- After changing any component or story, call **preview-stories**.
- {{PREVIEW_STORIES_STEP}}
- Always include every returned preview URL in your user-facing response so the user can verify the visual result.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### Workflow

1. Make your change
2. Run `{{RUN_STORY_TESTS_TOOL_NAME}}` with affected stories for focused feedback (faster while iterating)
2. Run `{{RUN_STORY_TESTS_TOOL_NAME}}` with related stories for focused feedback (faster while iterating)
3. If tests fail: analyze, fix{{A11Y_FIX_SUFFIX}}, re-run
4. Repeat until all tests pass

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,7 @@ play: async ({ canvas }) => {
## Story Linking Agent Behavior

- ALWAYS provide story links after any changes to stories files, including changes to existing stories.
- {{STORY_LINKING_WORKFLOW}}
- When sharing links, choose the most relevant subset for the user and avoid long lists (generally no more than 5 links).
- {{CHANGED_STORY_FALLBACK_LINK_GUIDANCE}}
- After changing any UI components, ALWAYS search for related stories that might cover the changes you've made. If you find any, provide the story links to the user. THIS IS VERY IMPORTANT, as it allows the user to visually inspect the changes you've made. Even later in a session when changing UI components or stories that have already been linked to previously, YOU MUST PROVIDE THE LINKS AGAIN.
- Use the {{PREVIEW_STORIES_TOOL_NAME}} tool to get the correct URLs for links to stories.
8 changes: 8 additions & 0 deletions packages/addon-mcp/src/mcp-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot';
import { HttpTransport } from '@tmcp/transport-http';
import pkgJson from '../package.json' with { type: 'json' };
import { addPreviewStoriesTool } from './tools/preview-stories.ts';
import { addGetChangedStoriesTool } from './tools/get-changed-stories.ts';
import { addGetUIBuildingInstructionsTool } from './tools/get-storybook-story-instructions.ts';
import {
addListAllDocumentationTool,
Expand Down Expand Up @@ -32,6 +33,8 @@ let a11yEnabled: boolean | undefined;

const initializeMCPServer = async (options: Options, multiSource?: boolean) => {
const core = await options.presets.apply('core', {});
const features = await options.presets.apply('features', {});
const changeDetectionEnabled = features?.changeDetection ?? false;
disableTelemetry = core?.disableTelemetry ?? false;

// Determine tool availability before creating server so instructions can be tailored
Expand All @@ -48,6 +51,7 @@ const initializeMCPServer = async (options: Options, multiSource?: boolean) => {
devEnabled: server?.ctx.custom?.toolsets?.dev ?? true,
testEnabled: (server?.ctx.custom?.toolsets?.test ?? true) && !!addonVitestConstants,
docsEnabled: (server?.ctx.custom?.toolsets?.docs ?? true) && manifestStatus.available,
changeDetectionEnabled,
});
},
capabilities: {
Expand Down Expand Up @@ -75,6 +79,10 @@ const initializeMCPServer = async (options: Options, multiSource?: boolean) => {
await addPreviewStoriesTool(server);
await addGetUIBuildingInstructionsTool(server);

if (changeDetectionEnabled) {
await addGetChangedStoriesTool(server);
}

Comment thread
ghengeveld marked this conversation as resolved.
// Register test addon tools
await addRunStoryTestsTool(server, { a11yEnabled });

Expand Down
Loading
Loading