From 1d9a5b5d0445ad3d6d94572cdcad35197791b1ef Mon Sep 17 00:00:00 2001 From: david ornelas Date: Tue, 5 May 2026 13:31:28 -0700 Subject: [PATCH] feat: add MCP config for all storybooks along with agent instructions --- .github/copilot-instructions.md | 37 ++++++++ .storybook-config/index.js | 4 + .vscode/mcp.json | 36 ++++++++ package.json | 1 + yarn.lock | 155 +++++++++++++++++++++++++++++++- 5 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 .vscode/mcp.json diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 729623a3e2..59e91c3113 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -88,6 +88,43 @@ yarn storybook # Primary development environment - **Auto-cleanup**: Merged PR environments cleaned from S3 after 14 days or immediately after merging to dev branch (dev is main branch for this repo) - **Slack integration**: `#prd-uds` and `#prdfam-uds-ci` channels for alerts +## Storybook MCP + +This monorepo has Storybook MCP servers available for all component packages. When doing UI development, always use the MCP tools to find and reuse existing components before creating new ones. + +### Available MCP servers + +Each package runs its own Storybook dev server with an MCP endpoint. Start the relevant Storybook first, then use the corresponding MCP toolset: + +| Package | Storybook command | MCP endpoint | +|---|---|---| +| `unity-react-core` | `cd packages/unity-react-core && yarn storybook` | `http://localhost:9200/mcp` | +| `unity-bootstrap-theme` | `cd packages/unity-bootstrap-theme && yarn storybook` | `http://localhost:9000/mcp` | +| `app-degree-pages` | `cd packages/app-degree-pages && yarn storybook` | `http://localhost:9010/mcp` | +| `app-rfi` | `cd packages/app-rfi && yarn storybook` | `http://localhost:9020/mcp` | +| `app-webdir-ui` | `cd packages/app-webdir-ui && yarn storybook` | `http://localhost:9030/mcp` | +| `component-events` | `cd packages/component-events && yarn storybook` | `http://localhost:9060/mcp` | +| `component-header-footer` | `cd packages/component-header-footer && yarn storybook` | `http://localhost:9080/mcp` | +| `component-news` | `cd packages/component-news && yarn storybook` | `http://localhost:9090/mcp` | + +### Workflow + +1. **Before building any UI**, use `list-all-documentation` on the relevant MCP server to discover available components. +2. **Before using a component**, call `get-documentation` to understand its props, variants, and usage patterns. +3. **After generating UI**, use `get-storybook-story-instructions` and write stories so the work can be previewed and tested. +4. **Run tests** using `run-story-tests` to validate interaction behavior and accessibility. Fix any failures before considering the task done. +5. **Preview work** using `preview-stories` to show live story renders inline. + +### Key conventions for this codebase + +- Components live in `packages/unity-react-core/src/components/` — this is the foundational library. Always check here first. +- Styles come from `unity-bootstrap-theme` (Bootstrap 5 + ASU brand tokens). Use Bootstrap utility classes before writing custom CSS. +- There are lots of components that arent yet in `packages/unity-react-core/src/components/`, also check `packages/unity-bootstrap-theme/stories/` for components that aren't in `packages/unity-react-core/src/components/`. +- The exception is `component-header-footer`, which uses styled-components and does not depend on the theme. +- All components use JSDoc TypeScript comments for prop documentation — these are surfaced in the MCP docs toolset. +- Always prefer typescript when creating any new components or updating any components in unity-react-core. Refactor only javascript files you modify in unity-react-core to typescript when you have to modify them but always ask user and let them know that this should be udpated to Typescript if they are modifying a javascript file in unity-react-core. +- Google Analytics events use `trackGAEvent` / `GaEventWrapper` — preserve these when modifying existing components. + ## Key Files for Understanding Context - `/packages/unity-react-core/src/components/` - Core React component patterns - `/packages/unity-bootstrap-theme/src/` - Theme structure (CSS/SCSS + JS) diff --git a/.storybook-config/index.js b/.storybook-config/index.js index 5a110620ae..3ce643e57b 100644 --- a/.storybook-config/index.js +++ b/.storybook-config/index.js @@ -16,6 +16,10 @@ const favicon = ` import { fileURLToPath } from "url"; +export function addons() { + return ["@storybook/addon-mcp"]; +} + export function previewAnnotations(entry = []) { return [...entry, fileURLToPath(import.meta.resolve('./preset/preview.js'))]; } diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000000..0254da3439 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,36 @@ +{ + "servers": { + "asu-unity-react-core": { + "type": "http", + "url": "http://localhost:9200/mcp" + }, + "asu-unity-bootstrap-theme": { + "type": "http", + "url": "http://localhost:9000/mcp" + }, + "asu-app-degree-pages": { + "type": "http", + "url": "http://localhost:9010/mcp" + }, + "asu-app-rfi": { + "type": "http", + "url": "http://localhost:9020/mcp" + }, + "asu-app-webdir-ui": { + "type": "http", + "url": "http://localhost:9030/mcp" + }, + "asu-component-events": { + "type": "http", + "url": "http://localhost:9060/mcp" + }, + "asu-component-header-footer": { + "type": "http", + "url": "http://localhost:9080/mcp" + }, + "asu-component-news": { + "type": "http", + "url": "http://localhost:9090/mcp" + } + } +} diff --git a/package.json b/package.json index 862ec139ee..6be2b7d737 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@siteimprove/alfa-playwright": "^0.78.1", "@siteimprove/alfa-test-utils": "^0.78.1", "@storybook/addon-docs": "^10.0.0", + "@storybook/addon-mcp": "^0.6.0", "@storybook/react": "^10.0.0", "@types/node": "^20.0.0", "@types/react-dom": "^18.3.0", diff --git a/yarn.lock b/yarn.lock index 6906eec95c..1b67f32461 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7562,7 +7562,7 @@ __metadata: languageName: node linkType: hard -"@standard-schema/spec@npm:^1.1.0": +"@standard-schema/spec@npm:^1.0.0, @standard-schema/spec@npm:^1.1.0": version: 1.1.0 resolution: "@standard-schema/spec@npm:1.1.0" checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526 @@ -7598,6 +7598,26 @@ __metadata: languageName: node linkType: hard +"@storybook/addon-mcp@npm:^0.6.0": + version: 0.6.0 + resolution: "@storybook/addon-mcp@npm:0.6.0" + dependencies: + "@storybook/mcp": "npm:0.7.0" + "@tmcp/adapter-valibot": "npm:^0.1.5" + "@tmcp/transport-http": "npm:^0.8.5" + picoquery: "npm:^2.5.0" + tmcp: "npm:^1.19.3" + valibot: "npm:1.2.0" + peerDependencies: + "@storybook/addon-vitest": ^0.0.0-0 || ^9.1.16 || ^10.0.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 + storybook: ^0.0.0-0 || ^9.1.16 || ^10.0.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 + peerDependenciesMeta: + "@storybook/addon-vitest": + optional: true + checksum: 10c0/f1edf6edd3ee242a54f3fb6cfb967a71504cca3ae160b43012d9d25d5485ad521b10d382010732428714ba58ad691c6638ec0a1393f7d16b0e736221f8ded8c0 + languageName: node + linkType: hard + "@storybook/builder-vite@npm:10.3.3": version: 10.3.3 resolution: "@storybook/builder-vite@npm:10.3.3" @@ -7652,6 +7672,18 @@ __metadata: languageName: node linkType: hard +"@storybook/mcp@npm:0.7.0": + version: 0.7.0 + resolution: "@storybook/mcp@npm:0.7.0" + dependencies: + "@tmcp/adapter-valibot": "npm:^0.1.5" + "@tmcp/transport-http": "npm:^0.8.5" + tmcp: "npm:^1.19.3" + valibot: "npm:1.2.0" + checksum: 10c0/56c90e597684e55e40451da47fc41e581d21365f405990c3cfbaaf8a19b71da17ede83399ed1524c6a1726050b0e0ba55474de5344cdeefe0cf9045faccb92b8 + languageName: node + linkType: hard + "@storybook/react-dom-shim@npm:10.3.3": version: 10.3.3 resolution: "@storybook/react-dom-shim@npm:10.3.3" @@ -8003,6 +8035,45 @@ __metadata: languageName: node linkType: hard +"@tmcp/adapter-valibot@npm:^0.1.5": + version: 0.1.5 + resolution: "@tmcp/adapter-valibot@npm:0.1.5" + dependencies: + "@standard-schema/spec": "npm:^1.0.0" + "@valibot/to-json-schema": "npm:^1.3.0" + valibot: "npm:^1.1.0" + peerDependencies: + tmcp: ^1.17.0 + valibot: ^1.1.0 + checksum: 10c0/176be80a74285f986ba8900116bf1ec2b97d249177b48127940b06bd08c70965a2e50d0aaa3785d4bdadd70f8e3f341fd881ce24c317a9d890cdb24ebf059399 + languageName: node + linkType: hard + +"@tmcp/session-manager@npm:^0.2.1": + version: 0.2.1 + resolution: "@tmcp/session-manager@npm:0.2.1" + peerDependencies: + tmcp: ^1.16.3 + checksum: 10c0/dadcfe6cf0e2be2536f0969aab3782355f2ff705d0a782ee9017e644b31c7eb57a593954676c252373a7d042ec6cd026e27db27460085b1c1036f7dcb1b37af5 + languageName: node + linkType: hard + +"@tmcp/transport-http@npm:^0.8.5": + version: 0.8.5 + resolution: "@tmcp/transport-http@npm:0.8.5" + dependencies: + "@tmcp/session-manager": "npm:^0.2.1" + esm-env: "npm:^1.2.2" + peerDependencies: + "@tmcp/auth": ^0.3.3 || ^0.4.0 + tmcp: ^1.18.0 + peerDependenciesMeta: + "@tmcp/auth": + optional: true + checksum: 10c0/208ba54571188e69ec57a33cc316ece812f3013c2e5c2355be62cb17e90665b258e069bd7eadce7898612018a7bd0ce958db95357a409930ca7a119a00d3c28e + languageName: node + linkType: hard + "@tootallnate/once@npm:1": version: 1.1.2 resolution: "@tootallnate/once@npm:1.1.2" @@ -9204,6 +9275,15 @@ __metadata: languageName: node linkType: hard +"@valibot/to-json-schema@npm:^1.3.0": + version: 1.6.0 + resolution: "@valibot/to-json-schema@npm:1.6.0" + peerDependencies: + valibot: ^1.3.0 + checksum: 10c0/3dabbb9ed0f135c436a9f4a22ff1ad3df500e0bdff1b771eb9a03f4ba7a412bb1873a9cc1ff32c09ff47d10be8d1834a540705229380b9fc46fb65a9b41dbae2 + languageName: node + linkType: hard + "@vitejs/plugin-react@npm:^4.3.1": version: 4.4.1 resolution: "@vitejs/plugin-react@npm:4.4.1" @@ -10373,6 +10453,7 @@ __metadata: "@siteimprove/alfa-playwright": "npm:^0.78.1" "@siteimprove/alfa-test-utils": "npm:^0.78.1" "@storybook/addon-docs": "npm:^10.0.0" + "@storybook/addon-mcp": "npm:^0.6.0" "@storybook/react": "npm:^10.0.0" "@types/node": "npm:^20.0.0" "@types/react-dom": "npm:^18.3.0" @@ -15168,6 +15249,13 @@ __metadata: languageName: node linkType: hard +"esm-env@npm:^1.2.2": + version: 1.2.2 + resolution: "esm-env@npm:1.2.2" + checksum: 10c0/3d25c973f2fd69c25ffff29c964399cea573fe10795ecc1d26f6f957ce0483d3254e1cceddb34bf3296a0d7b0f1d53a28992f064ba509dfe6366751e752c4166 + languageName: node + linkType: hard + "espree@npm:^10.0.1, espree@npm:^10.4.0": version: 10.4.0 resolution: "espree@npm:10.4.0" @@ -20652,6 +20740,13 @@ __metadata: languageName: node linkType: hard +"json-rpc-2.0@npm:^1.7.1": + version: 1.7.1 + resolution: "json-rpc-2.0@npm:1.7.1" + checksum: 10c0/260f573fd2f38c04bce63076b9293ed0c222c10bff12dd14fed8b926555af6d390c4bcc888b01dd42f28a8759056b8e4420b9f65f09e64d12d042a541fd88695 + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -24940,6 +25035,13 @@ __metadata: languageName: node linkType: hard +"picoquery@npm:^2.5.0": + version: 2.5.0 + resolution: "picoquery@npm:2.5.0" + checksum: 10c0/ac22a7622ecf6f6c0d2657b04d2ca346f814ff4d343827e6ca53d2d5cecfebee18d80b1290b916d11db6f62866bec26e92bb0a0d7939bd15971e60320db8d265 + languageName: node + linkType: hard + "pidtree@npm:^0.3.0": version: 0.3.1 resolution: "pidtree@npm:0.3.1" @@ -28668,6 +28770,13 @@ __metadata: languageName: node linkType: hard +"sqids@npm:^0.3.0": + version: 0.3.0 + resolution: "sqids@npm:0.3.0" + checksum: 10c0/2ce528b83f2780166b2e8025ece1e8262ee217ed51ab5656959cb6e1a885eee5b6ea86627ce6b0321d7b0eeb34a2ed455476c01c44e6e55e18cee52b3e1b9eb3 + languageName: node + linkType: hard + "ssim.js@npm:^3.1.1": version: 3.5.0 resolution: "ssim.js@npm:3.5.0" @@ -29948,6 +30057,19 @@ __metadata: languageName: node linkType: hard +"tmcp@npm:^1.19.3": + version: 1.19.3 + resolution: "tmcp@npm:1.19.3" + dependencies: + "@standard-schema/spec": "npm:^1.0.0" + json-rpc-2.0: "npm:^1.7.1" + sqids: "npm:^0.3.0" + uri-template-matcher: "npm:^1.1.1" + valibot: "npm:^1.1.0" + checksum: 10c0/c310c21b32aa6716037eebd126eb39a62e86ef99a9d95b8dc53b7e5d212b7109beefa56506a489193018e3caed471809da8d1b07de00e747b259d0396b9b49c3 + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -31013,6 +31135,13 @@ __metadata: languageName: node linkType: hard +"uri-template-matcher@npm:^1.1.1": + version: 1.1.2 + resolution: "uri-template-matcher@npm:1.1.2" + checksum: 10c0/27bf1880a9110b85aff4d09157869b3b37c4355f1c8212e17f698394116fc79da1896c2f03f795eb5bee0007434b448c4f3002ade257e604a1176c14b8157d12 + languageName: node + linkType: hard + "urix@npm:^0.1.0": version: 0.1.0 resolution: "urix@npm:0.1.0" @@ -31139,6 +31268,30 @@ __metadata: languageName: node linkType: hard +"valibot@npm:1.2.0": + version: 1.2.0 + resolution: "valibot@npm:1.2.0" + peerDependencies: + typescript: ">=5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/e6897ed2008fc900380a6ce39b62bc5fca45fd5e070f70571c6380ede3ba026d0b7016230215d87f7f3d672a28dbde5a0522d39830b493fdc3dccd1a59ef4ee6 + languageName: node + linkType: hard + +"valibot@npm:^1.1.0": + version: 1.3.1 + resolution: "valibot@npm:1.3.1" + peerDependencies: + typescript: ">=5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/e20a4097fa726f57530da1e64558af47ddd2303129c77978fe93c522c66cf4c79540ea3af864523589283ea25e347c3d65b8044fa4913376208dde576b9f6382 + languageName: node + linkType: hard + "validate-npm-package-license@npm:3.0.4, validate-npm-package-license@npm:^3.0.1, validate-npm-package-license@npm:^3.0.4": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4"