Skip to content

feat(storybook): expose component docs to agents via official MCP addon (#3527) - #3736

Open
chinawch007 wants to merge 2 commits into
apache:mainfrom
chinawch007:feat/storybook-mcp-3527
Open

feat(storybook): expose component docs to agents via official MCP addon (#3527)#3736
chinawch007 wants to merge 2 commits into
apache:mainfrom
chinawch007:feat/storybook-mcp-3527

Conversation

@chinawch007

Copy link
Copy Markdown
Contributor

Summary

Agents writing UI code in this repo had no machine-readable interface to
learn which components exist and how to use them, so they grepped and read
component sources to guess props and usage. This PR self-hosts Storybook's
official MCP addon at http://localhost:6006/mcp, exposing the docs
toolset only, so agents can query the existing story catalog before
writing code.

  • apps/desktop: install @storybook/addon-mcp and register it in
    .storybook/main.ts with toolsets: { dev: false, test: false, docs: true }
    (test toolset needs @storybook/addon-vitest and stays a follow-up per
    the issue)
  • new root .mcp.json registering the endpoint for agent clients
  • new root AGENTS.md: start Storybook on demand, query
    list-all-documentation / get-documentation before writing UI code,
    prefer existing packages/ui components

Fixes #3527

Verification

Manual verification succeeded against a running dev server:

  • npm --workspace @maka/desktop run storybook -- --no-open boots
    unchanged; existing stories render as before

  • MCP initialize over POST /mcp returns a session id

  • tools/list exposes exactly the three docs tools — list-all-documentation,
    get-documentation, get-documentation-for-story — confirming the
    dev/test toolsets are off:

    tool count: 3
    - list-all-documentation
    - get-documentation
    - get-documentation-for-story
    
  • all three tools return real content, e.g. get-documentation for
    primitives-toast returns the story list with usage snippets

  • npm run lint and npm run format:check pass

Not run / known gaps: full npm run build and npm test (config-only
change, no unit suite covers Storybook config); desktop-workspace
typecheck reports 40 pre-existing errors that reproduce identically on
clean main in this environment (stale workspace dists) — none touch the
changed files, which typecheck clean.

Review focus

  • .mcp.json uses the "type": "http" + "url" client convention
    (Claude Code / Cursor-class agent CLIs), not an MCP spec format; it is
    dev-time tooling config, unrelated to packages/mcp's product config.
    $schema is omitted — no official schema covers this client format.
  • .github/copilot-instructions.md (code-review guidance only) and the new
    AGENTS.md cover disjoint topics; AGENTS.md is the cross-tool
    canonical location. Mirroring into copilot-instructions.md is left as a
    maintainer decision.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: ZCode authored the config and documentation changes and
ran the verification above; the human contributor reviewed the result and
performed the final verification on a live server.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

…on (apache#3527)

Self-host the Storybook MCP endpoint at http://localhost:6006/mcp with only
the docs toolset enabled:

- install @storybook/addon-mcp in apps/desktop and register it in
  .storybook/main.ts with dev/test toolsets off (test needs
  @storybook/addon-vitest and stays a follow-up per the issue)
- register the endpoint for agent clients in a new root .mcp.json
  ("type": "http" client convention; $schema omitted since no official
  schema covers this client config format)
- add AGENTS.md guidance to query the MCP before writing UI code in
  packages/ui or apps/desktop, preferring existing components

Verified: storybook boots unchanged, tools/list exposes exactly the three
docs tools, and list-all-documentation / get-documentation /
get-documentation-for-story return real story docs over the endpoint.

Generated-by: ZCode

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this head and found blocking issues.

[P2] MCP addon docs-only claim is not a server boundary and the endpoint is exposed on LAN

@storybook/addon-mcp replaces options via X-MCP-Toolsets (main.ts:45). The live tools/list with a dev header changes from 3 docs tools to 4 dev tools. The storybook script does not bind to loopback, so *:6006 is reachable from 10.7.0.13:6006 without auth — an on-LAN caller can re-enable the dev toolset and obtain a filesystem existence oracle (/etc/passwd vs pathNotFound).

Fix: bind to loopback (and --exact-port) and intersect request-selected toolsets with the configured allowlist; cover with header-injection tests.

[P2] Root .mcp.json is not discovered by Codex

AGENTS.md claims the endpoint is registered, but Codex discovers via .codex/config.toml [mcp_servers], not the Claude-style root JSON. Result: Codex sees the mandatory query instruction but has no tools.

Fix: ship a real project config for each claimed client or narrow the claim; verify via actual client discovery.

Checks on d75281cb67 are test: failure (unrelated CLI EOF backoff flake, but still red — not green). Code issues are independent of CI.

简体中文存在局域网暴露与 Codex 发现失败两项阻断。

…pe (apache#3527)

Review follow-up addressing the two P2s:

- storybook script now passes --host 127.0.0.1 --exact-port, so the
  unauthenticated /mcp endpoint is loopback-only. The X-MCP-Toolsets
  override itself is addon-level behavior (see getToolsets() in
  @storybook/addon-mcp) and needs an upstream fix; with loopback-only
  binding a caller already has direct local filesystem access, so the
  override grants nothing it could not do directly.
- .storybook/main.ts comment now states the toolsets config is a default
  selection, not an allowlist.
- AGENTS.md no longer claims universal .mcp.json registration: clients
  that read the root .mcp.json auto-discover the endpoint; other clients
  (Codex, Cursor) register the same URL in their own config.

Verified: lsof reports 127.0.0.1:6006 (previously *:6006); MCP initialize,
tools/list, and get-documentation still work over both localhost and
127.0.0.1; lint and format:check pass.

Generated-by: ZCode
@chinawch007

Copy link
Copy Markdown
Contributor Author

Thanks — both P2s are addressed in d9671e0. Details per finding:

[P2] Toolset override + LAN exposure

  • storybook dev now runs with --host 127.0.0.1 --exact-port. Verified on a
    live server: lsof reports TCP 127.0.0.1:6006 where it previously reported
    *:6006, and the endpoint still serves the three docs tools (initialize →
    tools/list → get-documentation) over both localhost and 127.0.0.1.
  • On intersecting the header selection with a configured allowlist: agreed in
    principle, but the X-MCP-Toolsets handling lives inside
    @storybook/addon-mcp itself — getToolsets() in dist/preset.js replaces
    the configured selection wholesale whenever the header is present — so the
    intersection has to happen upstream in storybookjs/mcp. I've filed
    addon-mcp: X-MCP-Toolsets request header fully replaces the configured toolsets — config acts as a default, not an allowlist storybookjs/mcp#406. With loopback-only binding the residual audience is
    local processes, which have no need of an MCP detour to probe the
    filesystem, so the attack path you demonstrated is closed.
  • The main.ts comment now states explicitly that the toolsets config is a
    default selection, not an allowlist, so no reader mistakes it for a
    boundary. Happy to add a small source-contract test pinning the loopback
    flags on the script if you want that locked.
  • Header-injection tests would be testing the addon's behavior, which lives
    in node_modules; once upstream ships the allowlist semantics I'll revisit
    what can be asserted from this repo.

[P2] Root .mcp.json not discovered by Codex

  • Went with narrowing the claim, as suggested. AGENTS.md is now client-neutral:
    the endpoint URL is stated up front, clients that read the root .mcp.json
    discover it automatically, and other clients (Codex, Cursor) are pointed at
    a one-time registration of the same URL in their own config.
  • I did not ship per-client configs: Cursor would need a separate
    .cursor/mcp.json, and Codex only reads the user-global
    ~/.codex/config.toml, which a repo cannot provision — so per-client files
    would be unshippable or untestable from here. Can add .cursor/mcp.json on
    top if maintainers prefer explicit opt-in files per client.
  • On verification: confirmed at the protocol level (initialize / tools/list /
    tool call). For discovery I can only vouch for the agent client used to
    develop this change, whose native discovery is the root .mcp.json; I have
    no Codex or Cursor environment available, which is exactly why the claim no
    longer extends to them.

CI

The red run is the CLI-workspace EOF-backoff flake you identified. Nothing in
this PR is consumed by that workspace; re-running now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adopt Storybook's official MCP addon to give agents a queryable component interface

2 participants