Skip to content

Commit 4002b9e

Browse files
authored
Merge pull request #3 from storybookjs/story-link-tool
Add Get Story URLs tool
2 parents 2c56bd8 + c14330b commit 4002b9e

20 files changed

+296
-36
lines changed

β€Ž.claude/settings.local.jsonβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"Bash(git merge:*)",
55
"Bash(git checkout:*)",
66
"Bash(git add:*)",
7-
"mcp__storyboook-mcp__add"
7+
"mcp__storyboook-mcp__add",
8+
"mcp__storyboook-mcp__get_story_urls",
9+
"mcp__storyboook-mcp__get_ui_building_instructions"
810
],
911
"deny": [],
1012
"ask": []

β€Ž.storybook/main.tsβ€Ž

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import { defineMain } from "@storybook/react-vite/node";
22

33
const config = defineMain({
4-
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
4+
stories: [
5+
"../src/**/*.mdx",
6+
"../src/stories/components/**/*.stories.@(js|jsx|ts|tsx)",
7+
{
8+
titlePrefix: "Other UI",
9+
directory: "../src/stories/other",
10+
files: "**/*.stories.@(js|jsx|ts|tsx)",
11+
},
12+
],
513
addons: ["@storybook/addon-docs", import.meta.resolve("../dist/preset.js")],
614
framework: "@storybook/react-vite",
15+
logLevel: "debug",
716
});
817

918
export default config;

β€Žpackage.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"prerelease": "zx scripts/prepublish-checks.js",
3939
"release": "npm run build && auto shipit",
4040
"start": "run-p build:watch \"storybook --quiet\"",
41-
"storybook": "storybook dev -p 6006",
41+
"storybook": "storybook dev --port 6006 --loglevel debug",
4242
"test": "echo \"Error: no test specified\" && exit 1"
4343
},
4444
"dependencies": {

β€Žsrc/mcp-handler.tsβ€Ž

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
44
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
55
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
66
import pkgJson from "../package.json" with { type: "json" };
7-
import { registerAdditionTool } from "./tools/addition";
8-
import { registerUIBuildingTool } from "./tools/getUIBuildingInstructions";
7+
import { registerStoryUrlsTool } from "./tools/get-story-urls";
8+
import { registerUIBuildingTool } from "./tools/get-ui-building-instructions";
9+
import type { Options } from "storybook/internal/types";
10+
import type { IncomingMessage, ServerResponse } from "node:http";
911

10-
function createMcpServer() {
12+
function createMcpServer(options: Options) {
1113
// New initialization request
1214
const transport = new StreamableHTTPServerTransport({
1315
sessionIdGenerator: () => randomUUID(),
@@ -27,7 +29,8 @@ function createMcpServer() {
2729
name: pkgJson.name,
2830
version: pkgJson.version,
2931
});
30-
registerAdditionTool(server);
32+
33+
registerStoryUrlsTool({ server, options });
3134
registerUIBuildingTool(server);
3235

3336
server.connect(transport);
@@ -44,7 +47,11 @@ async function getJson(req: Connect.IncomingMessage) {
4447
}
4548

4649
// Handle POST requests for client-to-server communication
47-
const handlePostRequest: Connect.SimpleHandleFunction = async (req, res) => {
50+
const handlePostRequest = async (
51+
req: IncomingMessage,
52+
res: ServerResponse,
53+
options: Options,
54+
) => {
4855
const sessionId = req.headers["mcp-session-id"] as string | undefined;
4956
let transport: StreamableHTTPServerTransport;
5057

@@ -54,7 +61,7 @@ const handlePostRequest: Connect.SimpleHandleFunction = async (req, res) => {
5461
// Reuse existing transport
5562
transport = transports[sessionId];
5663
} else if (!sessionId && isInitializeRequest(body)) {
57-
transport = await createMcpServer();
64+
transport = await createMcpServer(options);
5865
} else {
5966
// Invalid request
6067
res.statusCode = 400;
@@ -93,14 +100,15 @@ const handleSessionRequest: Connect.SimpleHandleFunction = async (req, res) => {
93100
return await transport.handleRequest(req, res);
94101
};
95102

96-
export const mcpServerHandler: Connect.NextHandleFunction = async (
97-
req,
98-
res,
99-
next,
103+
export const mcpServerHandler = async (
104+
req: IncomingMessage,
105+
res: ServerResponse,
106+
next: Connect.NextFunction,
107+
options: Options,
100108
) => {
101109
switch (req.method) {
102110
case "POST":
103-
return await handlePostRequest(req, res);
111+
return await handlePostRequest(req, res, options);
104112
case "GET":
105113
case "DELETE":
106114
return await handleSessionRequest(req, res);

β€Žsrc/preset.tsβ€Ž

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import type { Plugin } from "vite";
22
import { mcpServerHandler } from "./mcp-handler";
3+
import type { Options } from "storybook/internal/types";
34

45
// This is a workaround for Storybook not having an API for addons to register server middlewares/handlers
56
// We can do it through Vite's plugin API instead, which gets added to Storybook's dev server in the end. 😈
6-
export const viteFinal = async (config: any) => {
7+
export const viteFinal = async (config: any, options: Options) => {
78
const mcpHandlerPlugin: Plugin = {
89
name: "storybook:mcp-server",
910
configureServer(server) {
10-
server.middlewares.use("/mcp", mcpServerHandler);
11+
server.middlewares.use("/mcp", (req, res, next) =>
12+
mcpServerHandler(req, res, next, options),
13+
);
1114
},
1215
};
1316
return {
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite";
22
import { Header } from "./Header";
33

44
const meta: Meta<typeof Header> = {
5-
title: "Example/Header",
65
component: Header,
76
parameters: {
87
// More on Story layout: https://storybook.js.org/docs/react/configure/story-layout
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { within, userEvent } from "storybook/test";
44
import { Page } from "./Page";
55

66
const meta: Meta<typeof Page> = {
7-
title: "Example/Page",
87
component: Page,
98
parameters: {
109
// More on Story layout: https://storybook.js.org/docs/react/configure/story-layout

0 commit comments

Comments
Β (0)