Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 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
147 changes: 75 additions & 72 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.
Comment thread
ghengeveld marked this conversation as resolved.
}
43 changes: 31 additions & 12 deletions apps/internal-storybook/tests/mcp-composition.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
const STARTUP_TIMEOUT = 30_000;

let storybookProcess: ReturnType<typeof x> | null = null;
let hasRemoteSource = false;

async function mcpRequest(method: string, params: any = {}) {
const response = await fetch(MCP_ENDPOINT, {
Expand All @@ -34,6 +35,13 @@
await killPort(PORT);
storybookProcess = startStorybook('.storybook-composition', PORT);
await waitForMcpEndpoint(MCP_ENDPOINT);

const docsResponse = await mcpRequest('tools/call', {
name: 'list-all-documentation',
arguments: {},
});
const docsText = docsResponse.result.content[0].text as string;
hasRemoteSource = docsText.includes('id: storybook-ui') || docsText.includes('# Storybook UI');
}, STARTUP_TIMEOUT);

afterAll(async () => {
Expand All @@ -51,7 +59,7 @@
const text = response.result.content[0].text;

// Should contain Local source
expect(text).toContain('# Local');

Check failure on line 62 in apps/internal-storybook/tests/mcp-composition.e2e.test.ts

View workflow job for this annotation

GitHub Actions / Test

tests/mcp-composition.e2e.test.ts > MCP Composition E2E Tests > Multi-Source Documentation > should list documentation from both local and remote sources

AssertionError: expected '# Components\n\n- Button (example-but…' to contain '# Local' - Expected + Received - # Local + # Components + + - Button (example-button): A customizable button component for user interactions. + - Header (header) + - Page (page) + - Card (other-ui-card): Card component with title, image, content, and action button + + # Docs + + - getting-started (getting-started--docs): # Getting Started This is the getting started documentation of this design system. ## Usag... ❯ tests/mcp-composition.e2e.test.ts:62:17
expect(text).toContain('id: local');

// Should contain remote Storybook UI source
Expand All @@ -61,7 +69,7 @@
// Local components should be present
expect(text).toContain('Button (example-button)');

// Remote components should be present (from storybook-ui)
// Remote source output should include its own documentation sections.
expect(text).toContain('## Components');
});

Expand Down Expand Up @@ -209,17 +217,28 @@
},
});

expect(response.result).toMatchInlineSnapshot(`
{
"content": [
{
"text": "Invalid arguments for tool get-documentation: [{"kind":"schema","type":"object","expected":"\\"storybookId\\"","received":"undefined","message":"Invalid key: Expected \\"storybookId\\" but received undefined","path":[{"type":"object","origin":"key","input":{"id":"example-button"},"key":"storybookId"}]}]",
"type": "text",
},
],
"isError": true,
}
`);
if (hasRemoteSource) {
expect(response.result).toMatchObject({
isError: true,
content: [
{
type: 'text',
text: expect.stringContaining('storybookId is required'),
},
],
});
return;
}

expect(response.result).toMatchObject({
content: [
{
type: 'text',
text: expect.stringContaining('ID: example-button'),
},
],
});
expect(response.result).not.toHaveProperty('isError');
});
Comment thread
ghengeveld marked this conversation as resolved.
});

Expand All @@ -241,7 +260,7 @@
const getDocTool = response.result.tools.find((t: any) => t.name === 'get-documentation');

expect(getDocTool).toBeDefined();
expect(getDocTool.inputSchema.properties).toHaveProperty('storybookId');

Check failure on line 263 in apps/internal-storybook/tests/mcp-composition.e2e.test.ts

View workflow job for this annotation

GitHub Actions / Test

tests/mcp-composition.e2e.test.ts > MCP Composition E2E Tests > Tools Schema > should include storybookId parameter in get-documentation schema

AssertionError: expected { id: { type: 'string', …(1) } } to have property "storybookId" ❯ tests/mcp-composition.e2e.test.ts:263:46
expect(getDocTool.inputSchema.properties.storybookId).toMatchObject({
type: 'string',
description: expect.stringContaining('source'),
Expand Down
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 @@

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 @@
"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 @@
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 @@ -886,9 +896,10 @@
const data = await parseMCPResponse(response);
const toolNames = data.result.tools.map((tool: any) => tool.name);

expect(toolNames).toMatchInlineSnapshot(`

Check failure on line 899 in apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts

View workflow job for this annotation

GitHub Actions / Test

tests/mcp-endpoint.e2e.test.ts > MCP Endpoint E2E Tests > Toolset Filtering > should respect X-MCP-Toolsets header for dev tools only

Error: Snapshot `MCP Endpoint E2E Tests > Toolset Filtering > should respect X-MCP-Toolsets header for dev tools only 1` mismatched - Expected + Received [ "preview-stories", - "get-changed-stories", "get-storybook-story-instructions", + "get-changed-stories", ] ❯ tests/mcp-endpoint.e2e.test.ts:899:22
[
"preview-stories",
"get-changed-stories",
"get-storybook-story-instructions",
]
`);
Expand Down
101 changes: 52 additions & 49 deletions eval/pnpm-lock.yaml

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

Loading
Loading