feat(storybook): add storybook-webmcp addon for AI agents#1116
Conversation
Adds a serverless MCP source for AI agents by registering tools in the browser via navigator.modelContext (WebMCP). After this change, `npm run storybook:deploy` also writes /manifests/components.json (and /manifests/docs.json) to the GitHub Pages output, and the manager bundle registers three tools: - storybook.list-all-documentation - storybook.get-documentation - storybook.get-documentation-for-story Consumers configure chrome-devtools-mcp with --category-experimental-webmcp, launch Chrome 149+ with --enable-features=WebMCPTesting,DevToolsWebMCPSupport, open https://scality.github.io/core-ui/ in that tab, and the tools become callable from Claude Code via list_webmcp_tools / execute_webmcp_tool. Notes: - The addon auto-enables features.componentsManifest: true and experimental_manifests: {} via its preset, so no manual manifest config is needed. - .npmrc adds the GitHub Packages scope mapping and an auth token reference. GHPR requires a token (with read:packages) even for public packages. CI builds need NODE_AUTH_TOKEN set; local dev: NODE_AUTH_TOKEN=$(gh auth token). - Bumped storybook addon resolution to ^0.1.1 which adds react-docgen-typescript prop-shape support (core-ui uses react-docgen-typescript per .storybook/main.ts). Verified locally: `npm run build-storybook` emits 61 components in storybook-static/manifests/components.json with populated props.
Hello jbwatenbergscality,My role is to assist you with the merge of this Available options
Available commands
Status report is not available. |
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list: |
| # Local dev: export NODE_AUTH_TOKEN=$(gh auth token) | ||
| # CI: pass NODE_AUTH_TOKEN via secrets (e.g. ${{ secrets.GITHUB_TOKEN }}). | ||
| @jbwatenbergscality:registry=https://npm.pkg.github.com | ||
| //npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN} |
There was a problem hiding this comment.
All three CI workflows (storybook-build.yml, tests.yaml, github-pages.yml) run npm ci but none set NODE_AUTH_TOKEN. Since .npmrc now routes @jbwatenbergscality to GitHub Packages with token auth, npm ci will fail with a 401 when resolving the addon — breaking every CI job, not just the Storybook build.
Each workflow needs something like:
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}|
CI fixed in e1e822f — both Root cause was missing Verified: If you don't want CI workflows touched as part of this PR, the alternative is to publish the addon to npmjs.com instead — fully anonymous installs, no auth, no |
| # the GHPR npm registry requires a token with read:packages scope. | ||
| # Local dev: export NODE_AUTH_TOKEN=$(gh auth token) | ||
| # CI: pass NODE_AUTH_TOKEN via secrets (e.g. ${{ secrets.GITHUB_TOKEN }}). | ||
| @jbwatenbergscality:registry=https://npm.pkg.github.com |
There was a problem hiding this comment.
post-release.yml also runs npm ci (line 68, publish-npm job) without NODE_AUTH_TOKEN. That job uses setup-node with registry-url: "https://registry.npmjs.org", which may overwrite this .npmrc (404 from npmjs.org) or leave it in place without a valid GHPR token (401). Either way, the publish workflow breaks after merge.
Combined with github-pages.yml (already flagged), that's two workflows still missing the fix.
Same fix as storybook-build.yml and tests.yaml. Without this, the deploy and post-release npm ci steps fetch @jbwatenbergscality/storybook-webmcp without a token and get a 401 from GitHub Packages. The env is scoped to the npm ci step only — publish-npm's npm publish step still uses OIDC for npmjs.org auth (unaffected).
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list: |
|
Applied the same NODE_AUTH_TOKEN fix to two more workflows in 8efc869:
These workflows don't trigger on PRs (post-release fires on |
| env: | ||
| # storybook-webmcp is hosted on GitHub Packages (npm.pkg.github.com). | ||
| # Even public GHPR packages require an auth token. | ||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
setup-node with registry-url: "https://registry.npmjs.org" writes //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} to ~/.npmrc. Setting NODE_AUTH_TOKEN to GITHUB_TOKEN here means the GitHub token is sent to registry.npmjs.org during npm ci — credential leakage to a third-party service.
The other three workflows don't use registry-url, so they're fine.
To avoid the collision, inject GHPR auth directly instead of through NODE_AUTH_TOKEN:
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| env: | |
| # storybook-webmcp is hosted on GitHub Packages (npm.pkg.github.com). | |
| # Even public GHPR packages require an auth token. | |
| # Use a separate step to avoid NODE_AUTH_TOKEN collision with setup-node's npmjs auth. | |
| - run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc | |
| - run: npm ci |
This keeps GHPR auth out of the NODE_AUTH_TOKEN channel that setup-node reserves for npmjs, and also means the _authToken=${NODE_AUTH_TOKEN} line in the project .npmrc can be dropped (reducing the local-dev setup burden flagged in the PR description).
There was a problem hiding this comment.
Good catch — fixed in 7ae3673.
Switched post-release.yml's npm ci step to write the GHPR auth line directly to ~/.npmrc (your exact suggested pattern) so the GitHub token never goes through NODE_AUTH_TOKEN where setup-node's npmjs auth line could pick it up.
I kept the other three workflows (storybook-build, tests, github-pages) on the NODE_AUTH_TOKEN env pattern since none of them call setup-node with registry-url, so the leak path doesn't exist there. Happy to unify all four onto the echo pattern if you'd prefer consistency over minimal-diff.
publish-npm uses setup-node with registry-url: registry.npmjs.org, which
writes //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} to ~/.npmrc.
Setting NODE_AUTH_TOKEN to GITHUB_TOKEN on the npm ci step would cause that
token to be sent to a third-party registry during dependency resolution.
Write the GHPR auth line directly to ~/.npmrc instead, so the GitHub token
is only sent to npm.pkg.github.com. The other three workflows
(storybook-build, tests, github-pages) don't use registry-url so they're
unaffected and keep the simpler NODE_AUTH_TOKEN env pattern.
Reported in PR review by Claude bot: #1116 (comment)
| # ~/.npmrc instead of via NODE_AUTH_TOKEN to avoid leaking the GitHub | ||
| # token to registry.npmjs.org through setup-node's npmjs auth line | ||
| # (//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}). | ||
| - run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc |
There was a problem hiding this comment.
The echo to ~/.npmrc is shadowed by the project .npmrc, which already declares //npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}. npm resolves project .npmrc over user ~/.npmrc for the same registry-scoped key, so the hardcoded token written here is never used. Since NODE_AUTH_TOKEN is not set in this job, npm resolves it to empty string and npm ci will 401 on GHPR.
Two ways to fix: (a) set NODE_AUTH_TOKEN as env on npm ci here too (same credential-leak risk the comment explains), or (b) remove the //npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN} line from the project .npmrc entirely and have every CI workflow inject auth via echo >> ~/.npmrc instead.
Summary
Adds
@jbwatenbergscality/storybook-webmcpto this Storybook. After this change, the deployedhttps://scality.github.io/core-ui/doubles as a serverless MCP source for AI agents — no backend needed.It's an alternative to Storybook's official
@storybook/mcpself-hosted server, implemented in-browser via the W3Cnavigator.modelContextAPI (WebMCP).Changes
.storybook/main.ts— added'@jbwatenbergscality/storybook-webmcp'toaddons. The addon auto-enablesfeatures.componentsManifest: trueandexperimental_manifests: {}via its preset, so no manual manifest config is needed.package.json— added"@jbwatenbergscality/storybook-webmcp": "^0.1.1"todevDependencies..npmrc— mapped the@jbwatenbergscalityscope to GitHub Packages, plus an env-var auth-token line. GHPR requires a token (withread:packages) even for public packages.What ships in
storybook-static/after thisThree tools registered
storybook.list-all-documentationstorybook.get-documentationreact-docgen-typescript, first 3 stories, story index) for one componentstorybook.get-documentation-for-storystoryIdorcomponentId+storyNameHow to consume (for reviewers)
Install
chrome-devtools-mcp≥ the version with--category-experimental-webmcp(currently experimental).In your MCP client config (e.g.
~/.claude.json/.mcp.json):{ "mcpServers": { "chrome-devtools": { "command": "npx", "args": ["chrome-devtools-mcp@latest", "--category-experimental-webmcp"] } } }Launch Chrome 149+ with
--enable-features=WebMCPTesting,DevToolsWebMCPSupport.Open
https://scality.github.io/core-ui/(after merge + deploy) in that Chrome instance.In Claude Code:
list_webmcp_toolsshould show threestorybook.*tools;execute_webmcp_toolinvokes them.CI considerations
The build needs
NODE_AUTH_TOKENto resolve the GHPR-hosted addon. Locally:For CI (GitHub Actions running on this repo),
${{ secrets.GITHUB_TOKEN }}works out of the box — it hasread:packagesfor the org's accessible packages. Action item: if any CI workflow runsnpm installwithout that env, it needs to be added. I haven't audited the workflows yet; flagging for whoever's familiar with the build setup.Test plan
NODE_AUTH_TOKEN=$(gh auth token) npm installsucceedsnpm run build-storybookproducesstorybook-static/manifests/components.jsonwith 61 components and populated propsbuild-storybookpasses (depends onNODE_AUTH_TOKENbeing set)storybook:deploy: confirmhttps://scality.github.io/core-ui/manifests/components.jsonreturns 200list_webmcp_toolsfrom Claude Code, confirm three storybook tools appearKnown limitations (v1)
react-docgen-typescriptand vanillareact-docgenare supported.react-component-meta(experimental) is not yet handled — would return empty props for those components.chrome-devtools-mcponly. MCP-B local relay and Chrome extension paths are explicitly out of scope.SchemaVersionErrorguard that fails loudly rather than silently miscarrying.Draft because
🤖 Generated with Claude Code