Skip to content

Commit 8265596

Browse files
authored
Merge pull request #33 from storybookjs/proxy-storybook-mcp-tools
Add tools from `@storybook/mcp` to `@storybook/addon-mcp`
2 parents 9e8915d + 6a67e3d commit 8265596

File tree

16 files changed

+399
-246
lines changed

16 files changed

+399
-246
lines changed

.changeset/gold-shirts-repeat.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@storybook/mcp': patch
3+
---
4+
5+
Export tools to be merged into other MCP servers.
6+
7+
Currently only [tmcp](https://github.com/paoloricciuti/tmcp)-based MCP servers supports using these tools directly.

.changeset/soft-chairs-push.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@storybook/addon-mcp': patch
3+
---
4+
5+
Add tools to get documentation for components, based on the component manifest being generated in the Storybook dev server.
6+
7+
Requirements:
8+
9+
1. That the **experimental** feature flag `features.experimentalComponentsManifest` is set to `true` in the main config.
10+
2. Only React-based frameworks supports component manifest generation for now.
11+
3. Requires Storybook v10.1 (prereleases), which at the time of writing is available as a canary version `0.0.0-pr-32810-sha-af0645cd`.

.github/copilot-instructions.md

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
This is a **pnpm monorepo** with two MCP implementations:
66

77
- **`packages/addon-mcp`**: Storybook addon using `tmcp`, exposes MCP server at `/mcp` via Vite middleware
8+
- Provides addon-specific tools (story URLs, UI building instructions)
9+
- **Imports and reuses tools from `@storybook/mcp` package** for component manifest features
10+
- Extends `StorybookContext` with addon-specific configuration (`AddonContext`)
811
- **`packages/mcp`**: Standalone MCP library using `tmcp`, reusable outside Storybook
12+
- Provides reusable component manifest tools (list components, get documentation)
13+
- Exports tools and types for consumption by addon-mcp
914
- **`apps/internal-storybook`**: Test environment for addon integration
1015

1116
**Both packages use `tmcp`** with HTTP transport and Valibot schema validation for consistent APIs.
@@ -25,6 +30,7 @@ The `@storybook/mcp` package (in `packages/mcp`) is framework-agnostic:
2530
- Uses `tmcp` with HTTP transport and Valibot schema validation
2631
- Factory pattern: `createStorybookMcpHandler()` returns a request handler
2732
- Context-based: handlers accept `StorybookContext` to override source URLs
33+
- **Exports tools and types** for reuse by `addon-mcp` and other consumers
2834

2935
## Development Environment
3036

@@ -95,6 +101,8 @@ import pkgJson from '../package.json' with { type: 'json' };
95101

96102
### In addon package (`packages/addon-mcp`):
97103

104+
**Option 1: Addon-specific tools** (for tools that require Storybook addon context):
105+
98106
1. Create `src/tools/my-tool.ts`:
99107

100108
```typescript
@@ -104,8 +112,8 @@ import type { AddonContext } from '../types.ts';
104112

105113
export const MY_TOOL_NAME = 'my_tool';
106114

107-
const MyToolInput = v.object({
108-
param: v.string()
115+
const MyToolInput = v.object({
116+
param: v.string(),
109117
});
110118

111119
type MyToolInput = v.InferOutput<typeof MyToolInput>;
@@ -128,30 +136,65 @@ export async function addMyTool(server: McpServer<any, AddonContext>) {
128136
}
129137
```
130138

131-
2. Import and call in `src/mcp-handler.ts` within `createAddonMcpHandler`
139+
2. Import and call in `src/mcp-handler.ts` within `initializeMCPServer`
140+
141+
**Option 2: Reuse tools from `@storybook/mcp`** (for component manifest features):
142+
143+
1. Import the tool from `@storybook/mcp` in `src/mcp-handler.ts`:
144+
145+
```typescript
146+
import { addMyTool, MY_TOOL_NAME } from '@storybook/mcp';
147+
```
148+
149+
2. Call it conditionally based on feature flags (see component manifest tools example)
150+
3. Ensure `AddonContext` extends `StorybookContext` for compatibility
151+
4. Pass the `source` URL in context for manifest-based tools
132152

133153
### In mcp package (`packages/mcp`):
134154

135155
1. Create `src/tools/my-tool.ts`:
136156

137157
```typescript
158+
export const MY_TOOL_NAME = 'my-tool';
159+
138160
export async function addMyTool(server: McpServer<any, StorybookContext>) {
139-
server.tool({ name: 'my_tool', description: 'What it does' }, async () => ({
140-
content: [{ type: 'text', text: 'result' }],
141-
}));
161+
server.tool(
162+
{ name: MY_TOOL_NAME, description: 'What it does' },
163+
async () => ({
164+
content: [{ type: 'text', text: 'result' }],
165+
}),
166+
);
142167
}
143168
```
144169

145170
2. Import and call in `src/index.ts` within `createStorybookMcpHandler`
146171

172+
3. **Export for reuse** in `src/index.ts`:
173+
174+
```typescript
175+
export { addMyTool, MY_TOOL_NAME } from './tools/my-tool.ts';
176+
```
177+
147178
## Integration Points
148179

180+
**Tool Reuse Between Packages:**
181+
182+
- `addon-mcp` depends on `@storybook/mcp` (workspace dependency)
183+
- `AddonContext` extends `StorybookContext` to ensure type compatibility
184+
- Component manifest tools are conditionally registered based on feature flags:
185+
- Checks `features.experimentalComponentsManifest` flag
186+
- Checks for `experimental_componentManifestGenerator` preset
187+
- Only registers `addListAllComponentsTool` and `addGetComponentDocumentationTool` when enabled
188+
- Context includes `source` URL pointing to `/manifests/components.json` endpoint
189+
149190
**Storybook internals used:**
150191

151192
- `storybook/internal/csf` - `storyNameFromExport()` for story name conversion
152193
- `storybook/internal/types` - TypeScript types for Options, StoryIndex
153194
- `storybook/internal/node-logger` - Logging utilities
154195
- Framework detection via `options.presets.apply('framework')`
196+
- Feature flags via `options.presets.apply('features')`
197+
- Component manifest generator via `options.presets.apply('experimental_componentManifestGenerator')`
155198

156199
**Story URL generation:**
157200

.github/workflows/check.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ jobs:
6969
- name: Setup Node.js and Install Dependencies
7070
uses: ./.github/actions/setup-node-and-install
7171

72+
- name: Build @storybook/mcp (dependency)
73+
run: pnpm build --filter @storybook/mcp
74+
7275
- name: Run tests
7376
run: pnpm --filter @storybook/addon-mcp test -- run
7477

@@ -95,6 +98,9 @@ jobs:
9598
- name: Setup Node.js and Install Dependencies
9699
uses: ./.github/actions/setup-node-and-install
97100

101+
- name: Build @storybook/mcp (dependency)
102+
run: pnpm build --filter @storybook/mcp
103+
98104
- name: Run type checking
99105
run: pnpm --filter @storybook/addon-mcp typecheck
100106

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
{
2-
"permissions": {
3-
"allow": [
4-
"mcp__storybook-addon-mcp__get-ui-building-instructions",
5-
"mcp__storybook-addon-mcp__get-story-urls"
6-
]
7-
},
8-
"enabledMcpjsonServers": [
9-
"storybook-addon-mcp",
10-
"storybook-mcp"
11-
]
2+
"permissions": {
3+
"allow": [
4+
"mcp__storybook-addon-mcp__get-ui-building-instructions",
5+
"mcp__storybook-addon-mcp__get-story-urls",
6+
"mcp__storybook-addon-mcp__list-all-components",
7+
"mcp__storybook-addon-mcp__get-component-documentation"
8+
]
9+
},
10+
"enabledMcpjsonServers": ["storybook-addon-mcp", "storybook-mcp"]
1211
}

apps/internal-storybook/.storybook/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ const config = defineMain({
1616
core: {
1717
disableTelemetry: true,
1818
},
19+
features: {
20+
experimentalComponentsManifest: true,
21+
},
1922
});
2023

2124
export default config;

apps/internal-storybook/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
"typecheck": "tsc --noEmit"
1010
},
1111
"devDependencies": {
12-
"@storybook/addon-docs": "^10.0.0-0",
12+
"@storybook/addon-docs": "0.0.0-pr-32810-sha-af0645cd",
1313
"@storybook/addon-mcp": "workspace:*",
14-
"@storybook/react-vite": "^10.0.0-0",
14+
"@storybook/react-vite": "0.0.0-pr-32810-sha-af0645cd",
1515
"@types/react": "^18.2.65",
1616
"@types/react-dom": "^18.2.21",
1717
"@vitejs/plugin-react": "^4.7.0",
1818
"react": "^18.2.0",
1919
"react-dom": "^18.2.0",
20-
"storybook": "^10.0.0-0"
20+
"storybook": "0.0.0-pr-32810-sha-af0645cd"
2121
}
2222
}

apps/internal-storybook/stories/components/Button.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ interface ButtonProps {
2626

2727
/**
2828
* Primary UI component for user interaction
29+
*
30+
* @import import { Button } from '@my-org/my-component-library';
31+
* @summary A customizable button component for user interactions.
2932
*/
3033
export const Button = ({
3134
primary = false,

packages/addon-mcp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"typecheck": "tsc --noEmit"
3535
},
3636
"dependencies": {
37+
"@storybook/mcp": "workspace:*",
3738
"@tmcp/adapter-valibot": "catalog:",
3839
"@tmcp/transport-http": "catalog:",
3940
"tmcp": "catalog:",

0 commit comments

Comments
 (0)