Skip to content

Skills M4: Run addon-mcp and @storybook/mcp on the shared core toolsets - #35858

Merged
JReinhold merged 8 commits into
nextfrom
m4-mcp-on-core-toolsets
Aug 13, 2026
Merged

JReinhold merged 8 commits into
nextfrom
m4-mcp-on-core-toolsets

Conversation

@JReinhold

Copy link
Copy Markdown
Contributor

Replacement for #35856 to clear a false GitHub CONFLICTING state.

Evidence the merge is clean:

  • git merge-base --is-ancestor m2b ⊂ m4 (fast-forward)
  • Compare API: ahead_by 7, behind_by 0
  • Local git merge of head into base succeeds with no conflicts

Replacement for #35854 / #35849 / #35677 with a new head branch name (m4-mcp-on-core-toolsets) so GitHub stops treating this layer as already-merged.

Same commits as m4-addon-mcp-core-services tip b0ac81925ed.


Replaces accidentally closed #35677 (a mergeability probe via the GitHub merges API marked that PR merged and deleted this branch; the merge commit on m2b-core-toolsets was reverted and this branch tip was restored to 0a5ad88a6a4).

No intentional code change versus #35677.


Closes #35673 · Closes #35725

Stacked: this PR's base is #35726 — the core toolsets layer this PR consumes; review that one first. #35719 (the storybook tools CLI) stacks on this one. Merge #35726 first; GitHub retargets this PR to next automatically.

What I did

#35726 built Storybook's agent-facing capabilities as core toolsets. This PR is the switch: both MCP surfaces — @storybook/addon-mcp (the dev-server MCP) and @storybook/mcp (the hosted/composition MCP) — now render their tools from those shared definitions, and the engines they each carried are deleted. Net: −11,199 lines.

What remains in each package is an adapter. It resolves a toolset method and maps the outcome onto the MCP reply mechanically: schemas and prose come from the definition, markdown becomes the text blocks, data becomes structuredContent, ok becomes isError, and agent-facing errors surface verbatim. Meaning lives in the toolset — the adapter is not allowed to re-derive it from the data.

Concretely, an MCP tool is now a registry row pointing at a toolset method (real code):

function docsRow(method: 'docs.list' | 'docs.show' | 'docs.showStory'): AddonToolDefinition {
  const forContext = (context: AddonToolRegistryContext): ToolsetToolOptions =>
    context.multiSource
      ? { method, resolveToolset: (server) => compositionDocsToolset(server) }
      : { method };

  return {
    name: MCP_TOOL_NAMES[method],
    toolset: 'docs',
    available: ({ availability }) => availability.docsEnabled,
    getMetadata: (context) => getToolsetToolMetadata(forContext(context)),
    register: async (server, context, enabled) => {
      registerToolsetTool(server, forContext(context), enabled);
    },
  };
}

The one review question

Does the way the MCP uses the toolsets make sense — and is there business logic still in the MCP that belongs in a toolset? Everything in commits 1–3 should read as mechanical: naming, gating, unwrapping, transport. If you find an adapter interpreting a result — branching on domain data, rewriting prose, computing anything the future CLI consumer would have to duplicate — that is the review finding to raise.

You do not need to review the deleted engines: commit 4/7 is −12,570 lines of pure deletions, and behavioral equality with them is pinned by the e2e wire snapshots (evidence below), not by reading them.

How to review (~1½ hours)

The branch's seven commits are these seven blocks, in this order. Each block heading links straight to its commit's diff — review one commit at a time, and read the block's intro here before opening any file.

  1. The addon adapter — 30 min
  2. The hosted adapter — 25 min
  3. Addon rewiring — 15 min
  4. Delete the replaced engines — 0 min
  5. Retire the PUSH_REVIEW channel adapter — 5 min
  6. The adapter tests and the e2e proof — 15 min
  7. Docs and bookkeeping — 5 min

Block 1 · The addon adapter — 30 min

Files: toolset-tools.ts, tool-registry.ts, ui-root.ts, tool-names.ts (4 files, +425 −109)

The entire addon-side integration is two ideas. The first is one generic unwrap that turns any toolset outcome into an MCP result — toolset-tools.ts, 187 lines, read it in full:

callToolsetMethod(server, { method }, input):
  toolset = getToolset(id)                       // throws loudly if missing
  outcome = method.handler(input, ctx(server))   // ctx carries origin, uiRoot, telemetry, consumer:'mcp'
  return {
    content:           one text block per outcome.markdown entry
    structuredContent: outputSchema ? narrowed(outcome.data) : undefined
    isError:           outcome.ok ? undefined : true
  }
  on throw: error.agentFacing ? its message, verbatim
                              : a generic message + logger.error on the server

The second is a declarative registry where every MCP tool is a row pointing at a toolset method — the docsRow snippet above is one real row. tool-registry.ts walks the rows; the availability gate × the toolsets config decides what registers.

What to check: nothing in this block may interpret data — no branching on domain fields, no re-deriving prose from the payload. If you find the adapter deciding what a result means, that is the finding to raise.

Block 2 · The hosted adapter — 25 min

Files: register.ts, error-to-mcp-content.ts, multi-source-manifests.ts, index.ts, types.ts, bin.ts, package.json (7 files, +497 −225)

The same unwrap for @storybook/mcp, with one structural difference: the hosted server builds its docs toolset per request, because the provider and sources belong to the request:

handle(request):
  sources = resolveSources(request)          // which Storybooks, which URLs, which auth
  toolset = createDocsToolset({ sources })   // the portable core factory — no second engine here
  register each method → the same mechanical unwrap as block 1

packaging: 'storybook' becomes a bundled devDependency —
           the published dependencies stay free of it (dist-contract.test.ts pins this)

What to check: register.ts (346 lines) in full — the per-request construction, the twin error mapping, and that the package boundary holds.

Block 3 · Addon rewiring — 15 min

Files: preset, mcp-handler, availability, telemetry, instructions, auth (16 files, +131 −386)

Mechanical re-pointing: everything that used to call an engine now consults the registry. Net −255 lines. Skim with one question: did any logic sneak in here, or is it all naming and plumbing?

Block 4 · Delete the replaced engines — 0 min

Files: the old tools, manifest pipeline, formatter and utils of both packages (47 files, −12,570, zero insertions)

Don't review. This is the point of the PR: every deleted line is an engine the core toolsets replaced. Behavioral equality is proven by block 6, not by reading these.

Block 5 · Retire the PUSH_REVIEW channel adapter — 5 min

Files: common-preset.ts, review-channel.ts (+ test), events.ts (4 files, +3 −200)

before: the addon emits 'storybook/review/push-review' on the channel; a core adapter listens
after : the review toolset method is called directly — the channel surface is deleted

#35726 deliberately kept this adapter alive so released addon-mcp versions kept working against the new core; with the addon switched over in this PR, it retires. One glance.

Block 6 · The adapter tests and the e2e proof — 15 min

Files: adapter unit tests, dist-contract.test.ts, test-storybooks/mcp (22 files, +1,569 −366)

Skim as evidence, not as code under review: the contract tests pin the unwrap (outcome → isError, structuredContent narrowing), gating (including the preview app resource), telemetry, and agentFacing error surfacing; the e2e suite exercises the real wire against real servers.

Block 7 · Docs and bookkeeping — 5 min

Files: AGENTS.md, agent-eval templates, yarn.lock (4 files, +89 −57)

The AGENTS.md architecture section documents the end state of the whole layer — worth an actual read: it is also the text future agents working in this repo obey.

Why skipping the deletions is safe:

Claim Evidence
The wire behavior did not change The MCP e2e suite (46/46 — real dev servers and real hosted manifests) passes with byte-identical inline snapshots before and after the swap
The adapters' contracts are pinned Unit tests cover the outcome→isError mapping, structuredContent narrowing, telemetry, agentFacing error surfacing, and toolset gating (including the preview app resource)
Nothing else regressed The full 9,212-test unit suite, TS 7 per-package checks across 47 projects plus workspace TS 6, and manual QA of the preview, test, docs and review flows
@storybook/mcp ships without storybook at runtime dist-contract.test.ts pins the published dependency surface; the docs toolset arrives through the portable storybook/internal/toolsets-docs entry

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. yarn nx run-many -t compile
  2. cd test-storybooks/mcp && yarn install && yarn vitest run --project=e2e — 46 tests, inline snapshots byte-identical to the old engines
  3. yarn storybook in test-storybooks/mcp, connect an MCP client to http://localhost:6006/mcp — the tool list and every tool response match the released addon
  4. The review flow end-to-end (display-review → UI) — now served by the review toolset; the PUSH_REVIEW channel event no longer exists
  5. Composition: the hosted @storybook/mcp against the Chromatic-hosted Storybooks — listing groups per source, lookups take storybookId

Documentation

  • Add or update documentation reflecting your changes — the AGENTS.md architecture section in this PR documents the end state of the toolset layer and its consumers
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

Made with Cursor

Made with Cursor

Made with Cursor

Made with Cursor

@JReinhold

Copy link
Copy Markdown
Contributor Author

Supersedes #35856 / #35854 / #35849. An empty tip commit was needed to clear a false GitHub CONFLICTING state (local merge into m2b-core-toolsets is a clean fast-forward; compare API was ahead_by: 7, behind_by: 0).

@JReinhold JReinhold self-assigned this Aug 12, 2026
@JReinhold JReinhold added maintenance User-facing maintenance tasks ci:normal Run our default set of CI jobs (choose this for most PRs). qa:skip Pull Requests that do not need any QA. (e.g. documentation) labels Aug 12, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The MCP packages now adapt shared Storybook toolsets. The addon registry and hosted documentation package use shared metadata, schemas, outcomes, telemetry, manifest access, and composition. Obsolete tool implementations, manifest utilities, review-channel plumbing, and local package overrides were removed.

Changes

Shared MCP toolset migration

Layer / File(s) Summary
Toolset contracts and package boundaries
AGENTS.md, code/lib/mcp/..., code/addons/mcp/package.json, agent-eval/lib/...
Shared toolset contracts and portable documentation types replace package-local contracts. Package generation no longer injects a local @storybook/mcp override.
Addon toolset adapter and registry
code/addons/mcp/src/tools/toolset-tools.ts, code/addons/mcp/src/tools/tool-registry.ts, code/addons/mcp/src/tools/ui-root.ts, code/addons/mcp/scripts/generate-tools-api-doc.ts, code/addons/mcp/src/tools/*test.ts
The addon resolves toolset methods, maps outcomes to MCP responses, validates structured output, derives UI roots, registers available tools, and handles missing toolsets per tool.
Hosted documentation registration
code/lib/mcp/src/tools/register.ts, code/lib/mcp/src/utils/*, code/lib/mcp/src/tools/*test.ts, code/lib/mcp/src/types.ts
Hosted documentation tools use request-scoped toolsets, provider-backed manifests, multi-source composition, output validation, telemetry, and explicit MCP error conversion.
Addon runtime wiring and availability
code/addons/mcp/src/preset.ts, code/addons/mcp/src/mcp-handler.ts, code/addons/mcp/src/auth/*, code/addons/mcp/src/telemetry.ts, code/addons/mcp/src/utils/*
Local documentation access, composition providers, CLI context, telemetry consumer classification, and Vitest-enabled availability now flow into the shared registry.
Packaging and integration validation
code/lib/mcp/src/dist-contract.test.ts, test-storybooks/mcp/...
Published artifacts are checked for dependency and import boundaries. End-to-end tests cover disabled Vitest registration and unusable Git handling.

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant AddonMcp
  participant ToolRegistry
  participant SharedToolset
  participant DocsAccess
  MCPClient->>AddonMcp: send MCP request
  AddonMcp->>ToolRegistry: resolve registered tool
  ToolRegistry->>SharedToolset: invoke method with MCP context
  SharedToolset->>DocsAccess: read local or composed documentation data
  DocsAccess-->>SharedToolset: return data or outcome
  SharedToolset-->>MCPClient: return MCP content and structured output
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🧹 Nitpick comments (4)
code/lib/mcp/src/dist-contract.test.ts (1)

88-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Anchor the react check to module references.

The comment on lines 88-90 states the intent is to reject module references to react. The regex on line 91 matches any quoted occurrence of react followed by a quote or a slash. A plain string literal type in the declarations, for example renderer: 'react', therefore fails the assertion even though it is not a module reference. Reuse the same anchoring that STORYBOOK_IMPORT_RE already applies.

♻️ Proposed change to anchor the react check
+/** Same import forms as {`@link` STORYBOOK_IMPORT_RE}, for `react` and its subpaths. */
+const REACT_IMPORT_RE =
+  /(?:\bfrom\s*|\brequire\(\s*|\bimport\(\s*|\bimport\s+)["']react(?:["']|\/)/;
+
 it.runIf(DTS_BUILT)('ships declarations a pure-Node consumer can check', () => {
   const declarations = readFileSync(DTS_ENTRY, 'utf-8');

   // No react (nor any module reference to it, including subpaths like react/jsx-runtime):
   // consumers of this package have no `@types/react`, and `skipLibCheck: false` must keep
   // working for them.
-  expect(declarations).not.toMatch(/["']react(?:["']|\/)/);
+  expect(declarations).not.toMatch(REACT_IMPORT_RE);
   expect(declarations).not.toMatch(STORYBOOK_IMPORT_RE);
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/lib/mcp/src/dist-contract.test.ts` around lines 88 - 92, Update the
`declarations` assertion in `dist-contract.test.ts` to reuse the
module-reference anchoring pattern used by `STORYBOOK_IMPORT_RE`, so only
imports or module references to `react` and its subpaths are rejected. Preserve
acceptance of ordinary declaration string literals such as `renderer: 'react'`.
test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts (1)

3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use explicit .ts extensions for both relative imports.

  • test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts#L3-L3: change ./helpers to ./helpers.ts.
  • test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts#L3-L3: change ./helpers to ./helpers.ts.

As per coding guidelines: “For TypeScript source in the repo, prefer explicit file extensions for relative code imports and exports.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts` at line
3, Update the relative helpers imports to use the explicit TypeScript extension
in both test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts:3-3
and test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts:3-3, changing
./helpers to ./helpers.ts in each file.

Source: Coding guidelines

code/addons/mcp/src/preset.test.ts (1)

422-422: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mock ./utils/addon-vitest.ts with vi.mock(..., { spy: true }) instead of vi.spyOn inside the test.

The changed line mocks a module member directly from within a test case. Declare the file mock at the top of the file, then set the behavior with vi.mocked(isAddonVitestEnabled).

♻️ Proposed refactor
-    vi.spyOn(runStoryTests, 'isAddonVitestEnabled').mockResolvedValue(false);
+    vi.mocked(isAddonVitestEnabled).mockResolvedValue(false);

Add the mock declaration at the top of the file:

vi.mock('./utils/addon-vitest.ts', { spy: true });

As per coding guidelines: "Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests", "Avoid inline mock implementations within test cases in Vitest tests", and "Avoid direct function mocking without vi.mocked() in Vitest tests".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/addons/mcp/src/preset.test.ts` at line 422, Replace the inline
runStoryTests.isAddonVitestEnabled spy in the test with a top-level
vi.mock('./utils/addon-vitest.ts', { spy: true }) declaration, then configure
the imported isAddonVitestEnabled through
vi.mocked(...).mockResolvedValue(false) within the test while preserving the
existing behavior.

Source: Coding guidelines

code/addons/mcp/src/storybook-ai-metadata.test.ts (1)

155-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the disabled-addon mock behavior into setup.

Line 155 configures isAddonVitestEnabled inside the disabled-addon test. Put this behavior in a nested beforeEach block for that test group. Keep the test body limited to the observable tool-surface assertion.

As per coding guidelines, implement mock behaviors in beforeEach blocks and avoid inline mock implementations within test cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/addons/mcp/src/storybook-ai-metadata.test.ts` at line 155, Move the
vi.mocked(isAddonVitestEnabled).mockResolvedValue(false) setup from the
disabled-addon test body into a nested beforeEach for that test group, leaving
the test body focused only on asserting the observable tool surface.

Source: Coding guidelines

🔇 Additional comments (50)
AGENTS.md (1)

99-178: 📐 Maintainability & Code Quality

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify the documented paths and symbol names.

This section states several concrete facts: MCP_TOOL_NAMES lives in open-service/toolset-names.ts, portable-dist.test.ts sits next to the portable entry source, code/core/build-config.ts declares portable: { external: [...] } for toolsets-docs with valibot as the only allowlist entry, and the docs accesses are named createServiceDocsAccess, createManifestDocsAccess, createProviderDocsAccess, createLocalDocsAccess, createCompositionDocsSources, and createDocsToolset. Stale documentation of this kind is hard to detect later. Confirm each name and path matches the code in this PR.

code/lib/mcp/src/types.ts (1)

2-9: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify every re-exported name exists in storybook/internal/toolsets-docs with the correct value or type kind.

Lines 121-129 re-export ComponentManifestMap, ComponentManifestMapV0, ComponentManifestMapV1, DocsManifestMap, DocsManifestMapV0, DocsManifestMapV1, and JsonRef as values. Lines 130-142 re-export the remaining names as types. If any of the names on lines 121-129 is type-only in the source entry, the value re-export fails under isolatedModules. This is a public export surface for embedders, so a mismatch breaks consumers rather than only this package.

Also applies to: 121-142

code/lib/mcp/src/index.ts (1)

17-42: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify the public export surface stayed complete after the module consolidation.

Lines 17-27 forward getDocumentationToolMetadata, getListAllDocumentationToolMetadata, getStoryDocumentationToolMetadata, GET_STORY_TOOL_NAME, GET_TOOL_NAME, and LIST_TOOL_NAME from ./tools/register.ts. Lines 30-40 move the manifest adapters and resolvers to storybook/internal/toolsets-docs. Embedders consume this root entry, so a name dropped during the consolidation is a breaking change. Confirm that ./tools/register.ts exports each forwarded name and that no previously public name disappeared.

code/lib/mcp/bin.ts (1)

19-24: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Confirm the built bin artifact bundles storybook/internal/toolsets-docs.

package.json lists storybook as a devDependency only. So every shipped artifact that imports storybook/internal/toolsets-docs must inline it. code/lib/mcp/src/dist-contract.test.ts asserts this for dist/index.js alone. It does not check the bin output. If the bin bundle keeps the bare specifier, the CLI fails at a consumer's runtime with an unresolvable module, and no test catches it.

Consider extending the contract test to the bin artifact.

code/lib/mcp/package.json (1)

52-52: LGTM!

code/lib/mcp/src/dist-contract.test.ts (1)

53-77: LGTM!

agent-eval/lib/templates.test.ts (1)

79-79: LGTM!

agent-eval/lib/templates.ts (1)

559-589: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify no sandbox manifest still needs a local file: override.

The removal of the override is correct only if code/addons/mcp/package.json no longer lists @storybook/mcp. If that dependency remains, rewriteDependencySpec now converts its workspace:* spec to a registry version, so the sandbox installs the published @storybook/mcp instead of the locally built copy and the eval silently tests the wrong code.

A second point needs the same check. code/lib/mcp/package.json now adds "storybook": "workspace:*" to devDependencies, and rewritePackageSpecsForNpm rewrites devDependencies as well. The sandbox manifest will therefore request storybook at the monorepo version. Confirm that the sandbox install either skips devDependencies or can resolve that version from the registry.

Also applies to: 614-629

code/addons/mcp/src/types.ts (1)

45-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Reuse ManifestProvider in the hosted package too.

This file now types the provider through the shared ManifestProvider alias. code/lib/mcp/src/types.ts still declares the same contract inline on its StorybookContext.manifestProvider field as (request: Request | undefined, path: string, source?: Source) => Promise<string>. Both packages feed providers into the same docs toolset, so two hand-maintained copies of one signature can drift. Import ManifestProvider from storybook/internal/toolsets-docs in the hosted package as well, so the compiler enforces the single shape.

code/lib/mcp/src/tools/register.ts (1)

41-46: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Add the required format field to ctx.

ctx is passed to every shared toolset handler in call(). It omits the required format field. This violates the toolset handler contract and can prevent compilation or select an incorrect rendering mode.

Set format to the format required by the MCP adapter.

Based on learnings: “handlers receive (input, ctx) with consumer, optional origin, required format, and getService.”

code/lib/mcp/src/tools/outcome-unwrap.test.ts (2)

26-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Use the required Vitest spy mock pattern.

Lines 26-42 replace a package module without { spy: true }. They also define the mock behavior outside beforeEach. Use a spy mock, access createDocsToolset with vi.mocked(), and configure its behavior in beforeEach.

As per coding guidelines, use vi.mock() with spy: true, use vi.mocked(), and implement mock behaviors in beforeEach.


67-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Move manifest-provider mock behavior into beforeEach.

These helpers create vi.fn(async ...) implementations outside beforeEach. Create the provider spy in beforeEach, configure it with vi.mocked(), and keep each test limited to fixture-state changes.

  • code/lib/mcp/src/tools/outcome-unwrap.test.ts#L67-L74: initialize the manifest-provider spy and its implementation in beforeEach.
  • code/lib/mcp/src/tools/get-documentation-for-story.test.ts#L25-L44: initialize the manifest-provider spy and its implementation in beforeEach.
  • code/lib/mcp/src/tools/get-documentation.test.ts#L26-L45: initialize the manifest-provider spy and its implementation in beforeEach.
  • code/lib/mcp/src/tools/list-all-documentation.test.ts#L31-L50: initialize the manifest-provider spy and its implementation in beforeEach.

As per coding guidelines, implement mock behaviors in beforeEach and use vi.mocked() for mocked functions.

test-storybooks/mcp/.storybook-no-vitest/main.ts (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Use explicit .ts extensions for local TypeScript imports.

Both paths target local TypeScript modules. Make the module format explicit.

  • test-storybooks/mcp/.storybook-no-vitest/main.ts#L2-L2: import ../.storybook/main.ts.
  • test-storybooks/mcp/.storybook-no-vitest/preview.ts#L1-L1: re-export from ../.storybook/preview.ts.

As per coding guidelines, prefer explicit file extensions for local TypeScript imports and exports.

code/addons/mcp/src/tools/toolset-tools.ts (4)

9-31: LGTM!


97-117: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

Confirm the ToolsetCtx contract no longer requires format.

buildContext supplies consumer, origin, uiRoot, getService, and telemetry, but no format. A retrieved learning records format as a required context field for toolset handlers. If the field is still required, this adapter and getToolsetToolMetadata do not satisfy the contract.

Verify the current ToolsetCtx definition:


119-149: LGTM!


159-161: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

The zero-input detection reads a Valibot-internal property.

Line 160 inspects schema.entries to decide whether to publish an input schema. entries is a Valibot object-schema field, not part of the Standard Schema surface that StandardSchemaV1 guarantees. Any method whose schema is wrapped (for example v.pipe(v.object({}), ...)) or produced by another Standard Schema library reports no entries, so hasInput becomes true and the tool publishes an input schema. That changes the observable MCP metadata.

Confirm that every toolset method schema is a plain Valibot object schema, or key the decision off an explicit method-level declaration.

code/addons/mcp/src/tools/ui-root.ts (1)

35-50: LGTM!

code/addons/mcp/src/tools/tool-names.ts (1)

1-13: LGTM!

code/addons/mcp/src/tools/tool-registry.ts (6)

5-8: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

Confirm storybook/internal/toolsets-docs is a valid entry point here.

This file imports createDocsToolset and createCompositionDocsSources from storybook/internal/toolsets-docs, while code/addons/mcp/src/test-support/register-core-toolsets.ts imports createDocsToolset from storybook/internal/core-server. Two entry points for the same factory can produce two bundle copies, which the comment on Lines 18-20 identifies as a real hazard for cross-entry identity. The repository guideline also states that toolset factories are exported from storybook/internal/core-server.

Verify that the toolsets-docs entry exists in the core package exports and that both import paths resolve to one module.


87-121: LGTM!


123-140: LGTM!


238-287: LGTM!


289-316: LGTM!


212-227: 🔒 Security & Privacy

Keep the async enabled callback. tmcp supports enabled callbacks that return boolean | Promise<boolean> and awaits the result when it lists tools.

			> Likely an incorrect or invalid review comment.
code/addons/mcp/src/test-support/register-core-toolsets.ts (2)

10-21: LGTM!


23-60: LGTM!

code/addons/mcp/scripts/generate-tools-api-doc.ts (3)

45-52: 🩺 Stability & Availability

⚠️ Unverified finding
Sandbox verification was unavailable.

toolMetadataFor mutates a shared registry, so concurrent section rendering can mix modes.

toolMetadataFor calls registerCoreToolsetsForTest, which clears and rebuilds the global toolset registry. The returned metadata is only correct while the registry still holds that reviewEnabled setting. renderServerSection reads metadata synchronously, then awaits renderTool, so a caller that renders the review-off and review-on sections with Promise.all would leave the registry in the last-registered state during those awaits. Confirm that the top-level orchestration renders the two modes sequentially.


231-231: LGTM!

Also applies to: 248-250


315-315: LGTM!

code/addons/mcp/src/tools/toolset-tools.test.ts (3)

1-13: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Add a spy mock for storybook/internal/node-logger.

Line 66 calls vi.mocked(logger.error).mockClear(), and Lines 202, 217, and 218 assert on logger.error. This file mocks only storybook/internal/core-server and ../telemetry.ts. If no shared setup file mocks the logger, logger.error is the real function and mockClear is undefined, so beforeEach throws.

🔧 Proposed fix
 vi.mock('storybook/internal/core-server', { spy: true });
+vi.mock('storybook/internal/node-logger', { spy: true });
 vi.mock('../telemetry.ts', { spy: true });

Verify whether a setup file already mocks the logger:

The spy-mocking guideline requires vi.mock() with spy: true for all package and file mocks, and requires mocking all dependencies the test subject uses.


60-71: LGTM!


73-261: LGTM!

code/core/src/shared/review/events.ts (1)

1-6: 🗄️ Data Integrity & Integration

⚠️ Unverified finding
Sandbox verification was unavailable.

Confirm no remaining references to PUSH_REVIEW.

This change removes an exported channel event from the public review contract. Any leftover emitter, subscriber, or documentation reference now points at a symbol that no longer exists.

code/addons/mcp/src/tools/tool-registry.test.ts (1)

130-144: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

⚠️ Unverified finding
Sandbox verification was unavailable.

Move mock setup into beforeEach.

  • code/addons/mcp/src/tools/tool-registry.test.ts#L130-L144: Create resource spies and attach them to the server fixture in beforeEach.
  • code/addons/mcp/src/telemetry.test.ts#L54-L61: Add a top-level vi.mock(..., { spy: true }) for telemetry and configure its default resolved value in beforeEach. Keep the test case limited to setting cliClient and asserting the emitted payload.

As per coding guidelines, “Implement mock behaviors in beforeEach blocks in Vitest tests,” “Avoid inline mock implementations within test cases in Vitest tests,” and “Avoid mocking without the spy: true option in Vitest tests.”

code/addons/mcp/src/tools/tool-registry-composition.test.ts (1)

14-15: LGTM!

Also applies to: 70-134

code/addons/mcp/src/auth/composition-auth.ts (1)

9-13: LGTM!

Also applies to: 155-159

code/addons/mcp/src/auth/resolve-composition-sources.ts (1)

1-1: LGTM!

code/addons/mcp/src/preset.ts (1)

17-18: LGTM!

Also applies to: 43-75

code/addons/mcp/src/mcp-handler.ts (1)

5-10: LGTM!

Also applies to: 121-121, 134-134, 144-144, 154-161

code/addons/mcp/src/utils/addon-vitest.ts (1)

1-18: LGTM!

code/addons/mcp/src/utils/get-tool-availability.ts (1)

5-5: LGTM!

Also applies to: 28-31, 97-102, 114-114

code/addons/mcp/src/instructions/build-server-instructions.ts (1)

6-6: LGTM!

Also applies to: 92-97

code/addons/mcp/src/storybook-ai-metadata.test.ts (1)

2-13: LGTM!

Also applies to: 44-49, 65-65, 490-539

code/addons/mcp/src/mcp-handler.test.ts (1)

2-2: LGTM!

Also applies to: 209-210, 445-445

code/addons/mcp/src/tools/get-storybook-story-instructions.test.ts (1)

4-4: LGTM!

Also applies to: 17-17, 27-27, 67-67

code/addons/mcp/src/tools/get-storybook-story-instructions.ts (1)

3-3: LGTM!

Also applies to: 50-54, 202-203

code/addons/mcp/src/tools/preview-stories.ts (1)

2-18: LGTM!

Also applies to: 60-60

code/addons/mcp/src/tools/preview-stories/preview-stories-app-script.ts (1)

9-9: LGTM!

code/addons/mcp/src/utils/module-graph.ts (1)

109-110: LGTM!

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@code/addons/mcp/src/preset.test.ts`:
- Around line 14-16: Update the test setup around beforeEach and the disabled
addon-vitest case so registerCoreToolsetsForTest uses { testToolset: false }
when isAddonVitestEnabled resolves to false. Keep default registration for tests
that require the test toolset, ensuring the assertion exercises the real
disabled-addon registry state.

In `@code/addons/mcp/src/telemetry.ts`:
- Around line 21-24: Update the telemetry payload construction so the spread of
payload occurs before the derived consumer field, ensuring caller-provided
payload.consumer cannot override the CLI-versus-MCP classification.

In `@code/addons/mcp/src/tools/ui-root.ts`:
- Around line 19-23: Update the root-path calculation around normalizedEndpoint
and normalizedPathname to compare the pathname suffix against the endpoint with
a leading slash, ensuring matching occurs on a path-segment boundary. Preserve
the existing slicing behavior for valid endpoint matches and fallback behavior
for non-matches.

In `@code/lib/mcp/src/tools/outcome-unwrap.test.ts`:
- Around line 184-195: Update the unexpected-error handling exercised by
callListTool so MCP clients receive a fixed generic error message instead of the
exception text. Keep the complete exception details in the server-side
consoleError log, and adjust the test assertion while preserving the existing
isError and single-log expectations.

---

Nitpick comments:
In `@code/addons/mcp/src/preset.test.ts`:
- Line 422: Replace the inline runStoryTests.isAddonVitestEnabled spy in the
test with a top-level vi.mock('./utils/addon-vitest.ts', { spy: true })
declaration, then configure the imported isAddonVitestEnabled through
vi.mocked(...).mockResolvedValue(false) within the test while preserving the
existing behavior.

In `@code/addons/mcp/src/storybook-ai-metadata.test.ts`:
- Line 155: Move the vi.mocked(isAddonVitestEnabled).mockResolvedValue(false)
setup from the disabled-addon test body into a nested beforeEach for that test
group, leaving the test body focused only on asserting the observable tool
surface.

In `@code/lib/mcp/src/dist-contract.test.ts`:
- Around line 88-92: Update the `declarations` assertion in
`dist-contract.test.ts` to reuse the module-reference anchoring pattern used by
`STORYBOOK_IMPORT_RE`, so only imports or module references to `react` and its
subpaths are rejected. Preserve acceptance of ordinary declaration string
literals such as `renderer: 'react'`.

In `@test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts`:
- Line 3: Update the relative helpers imports to use the explicit TypeScript
extension in both
test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts:3-3 and
test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts:3-3, changing ./helpers
to ./helpers.ts in each file.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69dc0ee6-4ac6-4765-953e-8b41039062d1

📥 Commits

Reviewing files that changed from the base of the PR and between a5ab56c and 28e9284.

⛔ Files ignored due to path filters (3)
  • code/lib/mcp/src/utils/manifest-formatter/__snapshots__/markdown.test.ts.snap is excluded by !**/*.snap
  • test-storybooks/mcp/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (101)
  • AGENTS.md
  • agent-eval/lib/templates.test.ts
  • agent-eval/lib/templates.ts
  • code/addons/mcp/package.json
  • code/addons/mcp/scripts/generate-tools-api-doc.ts
  • code/addons/mcp/src/auth/composition-auth.test.ts
  • code/addons/mcp/src/auth/composition-auth.ts
  • code/addons/mcp/src/auth/resolve-composition-sources.ts
  • code/addons/mcp/src/constants.ts
  • code/addons/mcp/src/instructions/build-server-instructions.ts
  • code/addons/mcp/src/manifests/__fixtures__/core-manifest.fixture.json
  • code/addons/mcp/src/manifests/core-format-contract.test.ts
  • code/addons/mcp/src/manifests/in-process-provider.test.ts
  • code/addons/mcp/src/manifests/in-process-provider.ts
  • code/addons/mcp/src/manifests/service-access.test.ts
  • code/addons/mcp/src/manifests/service-access.ts
  • code/addons/mcp/src/manifests/vendored.ts
  • code/addons/mcp/src/mcp-handler.test.ts
  • code/addons/mcp/src/mcp-handler.ts
  • code/addons/mcp/src/preset.test.ts
  • code/addons/mcp/src/preset.ts
  • code/addons/mcp/src/storybook-ai-metadata.test.ts
  • code/addons/mcp/src/telemetry.test.ts
  • code/addons/mcp/src/telemetry.ts
  • code/addons/mcp/src/test-support/register-core-toolsets.ts
  • code/addons/mcp/src/tools/display-review.test.ts
  • code/addons/mcp/src/tools/display-review.ts
  • code/addons/mcp/src/tools/get-changed-stories.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.ts
  • code/addons/mcp/src/tools/get-stories-by-component.test.ts
  • code/addons/mcp/src/tools/get-stories-by-component.ts
  • code/addons/mcp/src/tools/get-storybook-story-instructions.test.ts
  • code/addons/mcp/src/tools/get-storybook-story-instructions.ts
  • code/addons/mcp/src/tools/preview-stories.test.ts
  • code/addons/mcp/src/tools/preview-stories.ts
  • code/addons/mcp/src/tools/preview-stories/preview-stories-app-script.ts
  • code/addons/mcp/src/tools/run-story-tests.test.ts
  • code/addons/mcp/src/tools/run-story-tests.ts
  • code/addons/mcp/src/tools/tool-names.ts
  • code/addons/mcp/src/tools/tool-registry-composition.test.ts
  • code/addons/mcp/src/tools/tool-registry.test.ts
  • code/addons/mcp/src/tools/tool-registry.ts
  • code/addons/mcp/src/tools/toolset-tools.test.ts
  • code/addons/mcp/src/tools/toolset-tools.ts
  • code/addons/mcp/src/tools/ui-root.ts
  • code/addons/mcp/src/types.ts
  • code/addons/mcp/src/utils/addon-vitest.ts
  • code/addons/mcp/src/utils/build-args-param.test.ts
  • code/addons/mcp/src/utils/build-args-param.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.test.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.ts
  • code/addons/mcp/src/utils/estimate-tokens.test.ts
  • code/addons/mcp/src/utils/estimate-tokens.ts
  • code/addons/mcp/src/utils/find-story-ids.test.ts
  • code/addons/mcp/src/utils/find-story-ids.ts
  • code/addons/mcp/src/utils/get-tool-availability.ts
  • code/addons/mcp/src/utils/module-graph.ts
  • code/addons/mcp/src/utils/resolve-component-stories.test.ts
  • code/addons/mcp/src/utils/resolve-component-stories.ts
  • code/addons/mcp/src/utils/slash.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/core/src/shared/review/events.ts
  • code/lib/mcp/bin.ts
  • code/lib/mcp/package.json
  • code/lib/mcp/src/dist-contract.test.ts
  • code/lib/mcp/src/globals.d.ts
  • code/lib/mcp/src/index.ts
  • code/lib/mcp/src/instructions.md
  • code/lib/mcp/src/tools/get-documentation-for-story.test.ts
  • code/lib/mcp/src/tools/get-documentation-for-story.ts
  • code/lib/mcp/src/tools/get-documentation.test.ts
  • code/lib/mcp/src/tools/get-documentation.ts
  • code/lib/mcp/src/tools/list-all-documentation.test.ts
  • code/lib/mcp/src/tools/list-all-documentation.ts
  • code/lib/mcp/src/tools/outcome-unwrap.test.ts
  • code/lib/mcp/src/tools/register.ts
  • code/lib/mcp/src/types.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.test.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.ts
  • code/lib/mcp/src/utils/dedent.ts
  • code/lib/mcp/src/utils/error-to-mcp-content.test.ts
  • code/lib/mcp/src/utils/error-to-mcp-content.ts
  • code/lib/mcp/src/utils/get-manifest.test.ts
  • code/lib/mcp/src/utils/get-manifest.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.ts
  • code/lib/mcp/src/utils/map-with-concurrency.ts
  • code/lib/mcp/src/utils/multi-source-manifests.ts
  • code/lib/mcp/src/utils/parse-react-docgen.test.ts
  • code/lib/mcp/src/utils/parse-react-docgen.ts
  • code/lib/mcp/src/utils/requires-own-mcp.test.ts
  • code/lib/mcp/src/utils/requires-own-mcp.ts
  • test-storybooks/mcp/.storybook-no-vitest/main.ts
  • test-storybooks/mcp/.storybook-no-vitest/preview.ts
  • test-storybooks/mcp/tests/helpers.ts
  • test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts
  • test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts
💤 Files with no reviewable changes (52)
  • code/addons/mcp/src/tools/display-review.test.ts
  • code/lib/mcp/src/utils/requires-own-mcp.ts
  • code/addons/mcp/src/utils/estimate-tokens.test.ts
  • code/addons/mcp/src/utils/slash.ts
  • code/lib/mcp/src/utils/map-with-concurrency.ts
  • code/addons/mcp/src/utils/build-args-param.ts
  • code/addons/mcp/src/utils/build-args-param.test.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/addons/mcp/src/manifests/service-access.test.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.ts
  • code/addons/mcp/src/tools/get-stories-by-component.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.test.ts
  • code/lib/mcp/src/tools/get-documentation-for-story.ts
  • code/lib/mcp/src/instructions.md
  • code/lib/mcp/src/globals.d.ts
  • code/addons/mcp/src/utils/find-story-ids.ts
  • code/addons/mcp/src/manifests/in-process-provider.ts
  • code/addons/mcp/src/manifests/in-process-provider.test.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.ts
  • code/addons/mcp/src/tools/run-story-tests.test.ts
  • code/lib/mcp/src/tools/get-documentation.ts
  • code/lib/mcp/src/utils/dedent.ts
  • code/addons/mcp/src/tools/display-review.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.ts
  • code/lib/mcp/src/utils/parse-react-docgen.ts
  • code/addons/mcp/src/utils/resolve-component-stories.ts
  • code/addons/mcp/src/utils/resolve-component-stories.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.test.ts
  • code/addons/mcp/src/tools/preview-stories.test.ts
  • code/lib/mcp/src/tools/list-all-documentation.ts
  • code/addons/mcp/src/manifests/fixtures/core-manifest.fixture.json
  • code/lib/mcp/src/utils/requires-own-mcp.test.ts
  • code/lib/mcp/src/utils/parse-react-docgen.test.ts
  • code/addons/mcp/src/manifests/core-format-contract.test.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.test.ts
  • code/addons/mcp/src/tools/get-stories-by-component.ts
  • code/addons/mcp/src/manifests/service-access.ts
  • code/addons/mcp/src/utils/estimate-tokens.ts
  • code/addons/mcp/src/utils/find-story-ids.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/addons/mcp/src/auth/composition-auth.test.ts
  • code/addons/mcp/src/tools/run-story-tests.ts
  • code/lib/mcp/src/utils/get-manifest.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.ts
  • code/addons/mcp/package.json
  • code/addons/mcp/src/utils/detect-unreachable-changes.test.ts
  • code/addons/mcp/src/manifests/vendored.ts
  • code/addons/mcp/src/constants.ts
  • code/lib/mcp/src/utils/get-manifest.test.ts

Comment thread code/addons/mcp/src/preset.test.ts
Comment thread code/addons/mcp/src/telemetry.ts
Comment thread code/addons/mcp/src/tools/ui-root.ts
Comment thread code/lib/mcp/src/tools/outcome-unwrap.test.ts
@JReinhold
JReinhold force-pushed the m4-mcp-on-core-toolsets branch from 28e9284 to 2a585e1 Compare August 12, 2026 12:38
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
code/addons/mcp/src/tools/tool-registry-composition.test.ts (1)

101-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the failing source in the partial-failure test.

The test name states that one source fails. The assertions only confirm that the readable source appears and that sourceCount is 2. The listing still passes if the unreadable local source is silently dropped instead of reported as failed. Add an assertion on the failure text, so the partial-failure contract is covered.

♻️ Proposed assertion
     expect(result.content[0].text).toContain('# Design System');
+    expect(result.content[0].text).toContain('Local');
+    expect(result.content[0].text).toMatch(/Failed to fetch manifest for local/i);
     expect(collectTelemetry).toHaveBeenCalledWith(
       expect.objectContaining({ event: 'tool:listAllDocumentation', sourceCount: 2 })
     );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/addons/mcp/src/tools/tool-registry-composition.test.ts` around lines 101
- 111, Add an assertion in the partial-failure test around makeServer and
list-all-documentation to verify the result content includes the failure text
for the unreadable local source, while preserving the existing readable-source
and telemetry assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@code/lib/mcp/src/tools/register.ts`:
- Around line 234-243: Update the block normalization in call so
outcome.markdown always yields at least one text block: replace an empty
markdown array or an undefined single value with an appropriate fallback text
value before mapping. Preserve existing markdown content when present, ensuring
callers reading result.content[0].text cannot encounter an empty array or
undefined text.

---

Nitpick comments:
In `@code/addons/mcp/src/tools/tool-registry-composition.test.ts`:
- Around line 101-111: Add an assertion in the partial-failure test around
makeServer and list-all-documentation to verify the result content includes the
failure text for the unreadable local source, while preserving the existing
readable-source and telemetry assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d4db8548-35dd-448f-b175-f70f5c8d4a14

📥 Commits

Reviewing files that changed from the base of the PR and between 1f90471 and 2a585e1.

⛔ Files ignored due to path filters (2)
  • code/lib/mcp/src/utils/manifest-formatter/__snapshots__/markdown.test.ts.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (100)
  • AGENTS.md
  • agent-eval/lib/templates.test.ts
  • agent-eval/lib/templates.ts
  • code/addons/mcp/package.json
  • code/addons/mcp/scripts/generate-tools-api-doc.ts
  • code/addons/mcp/src/auth/composition-auth.test.ts
  • code/addons/mcp/src/auth/composition-auth.ts
  • code/addons/mcp/src/auth/resolve-composition-sources.ts
  • code/addons/mcp/src/constants.ts
  • code/addons/mcp/src/instructions/build-server-instructions.ts
  • code/addons/mcp/src/manifests/__fixtures__/core-manifest.fixture.json
  • code/addons/mcp/src/manifests/core-format-contract.test.ts
  • code/addons/mcp/src/manifests/in-process-provider.test.ts
  • code/addons/mcp/src/manifests/in-process-provider.ts
  • code/addons/mcp/src/manifests/service-access.test.ts
  • code/addons/mcp/src/manifests/service-access.ts
  • code/addons/mcp/src/manifests/vendored.ts
  • code/addons/mcp/src/mcp-handler.test.ts
  • code/addons/mcp/src/mcp-handler.ts
  • code/addons/mcp/src/preset.test.ts
  • code/addons/mcp/src/preset.ts
  • code/addons/mcp/src/storybook-ai-metadata.test.ts
  • code/addons/mcp/src/telemetry.test.ts
  • code/addons/mcp/src/telemetry.ts
  • code/addons/mcp/src/test-support/register-core-toolsets.ts
  • code/addons/mcp/src/tools/display-review.test.ts
  • code/addons/mcp/src/tools/display-review.ts
  • code/addons/mcp/src/tools/get-changed-stories.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.ts
  • code/addons/mcp/src/tools/get-stories-by-component.test.ts
  • code/addons/mcp/src/tools/get-stories-by-component.ts
  • code/addons/mcp/src/tools/get-storybook-story-instructions.test.ts
  • code/addons/mcp/src/tools/get-storybook-story-instructions.ts
  • code/addons/mcp/src/tools/preview-stories.test.ts
  • code/addons/mcp/src/tools/preview-stories.ts
  • code/addons/mcp/src/tools/preview-stories/preview-stories-app-script.ts
  • code/addons/mcp/src/tools/run-story-tests.test.ts
  • code/addons/mcp/src/tools/run-story-tests.ts
  • code/addons/mcp/src/tools/tool-names.ts
  • code/addons/mcp/src/tools/tool-registry-composition.test.ts
  • code/addons/mcp/src/tools/tool-registry.test.ts
  • code/addons/mcp/src/tools/tool-registry.ts
  • code/addons/mcp/src/tools/toolset-tools.test.ts
  • code/addons/mcp/src/tools/toolset-tools.ts
  • code/addons/mcp/src/tools/ui-root.ts
  • code/addons/mcp/src/types.ts
  • code/addons/mcp/src/utils/addon-vitest.ts
  • code/addons/mcp/src/utils/build-args-param.test.ts
  • code/addons/mcp/src/utils/build-args-param.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.test.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.ts
  • code/addons/mcp/src/utils/estimate-tokens.test.ts
  • code/addons/mcp/src/utils/estimate-tokens.ts
  • code/addons/mcp/src/utils/find-story-ids.test.ts
  • code/addons/mcp/src/utils/find-story-ids.ts
  • code/addons/mcp/src/utils/get-tool-availability.ts
  • code/addons/mcp/src/utils/module-graph.ts
  • code/addons/mcp/src/utils/resolve-component-stories.test.ts
  • code/addons/mcp/src/utils/resolve-component-stories.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/core/src/shared/review/events.ts
  • code/lib/mcp/bin.ts
  • code/lib/mcp/package.json
  • code/lib/mcp/src/dist-contract.test.ts
  • code/lib/mcp/src/globals.d.ts
  • code/lib/mcp/src/index.ts
  • code/lib/mcp/src/instructions.md
  • code/lib/mcp/src/tools/get-documentation-for-story.test.ts
  • code/lib/mcp/src/tools/get-documentation-for-story.ts
  • code/lib/mcp/src/tools/get-documentation.test.ts
  • code/lib/mcp/src/tools/get-documentation.ts
  • code/lib/mcp/src/tools/list-all-documentation.test.ts
  • code/lib/mcp/src/tools/list-all-documentation.ts
  • code/lib/mcp/src/tools/outcome-unwrap.test.ts
  • code/lib/mcp/src/tools/register.ts
  • code/lib/mcp/src/types.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.test.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.ts
  • code/lib/mcp/src/utils/dedent.ts
  • code/lib/mcp/src/utils/error-to-mcp-content.test.ts
  • code/lib/mcp/src/utils/error-to-mcp-content.ts
  • code/lib/mcp/src/utils/get-manifest.test.ts
  • code/lib/mcp/src/utils/get-manifest.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.ts
  • code/lib/mcp/src/utils/map-with-concurrency.ts
  • code/lib/mcp/src/utils/multi-source-manifests.ts
  • code/lib/mcp/src/utils/parse-react-docgen.test.ts
  • code/lib/mcp/src/utils/parse-react-docgen.ts
  • code/lib/mcp/src/utils/requires-own-mcp.test.ts
  • code/lib/mcp/src/utils/requires-own-mcp.ts
  • test-storybooks/mcp/.storybook-no-vitest/main.ts
  • test-storybooks/mcp/.storybook-no-vitest/preview.ts
  • test-storybooks/mcp/tests/helpers.ts
  • test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts
  • test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts
💤 Files with no reviewable changes (51)
  • code/lib/mcp/src/instructions.md
  • code/lib/mcp/src/utils/parse-react-docgen.test.ts
  • code/addons/mcp/src/utils/resolve-component-stories.test.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/addons/mcp/src/tools/get-stories-by-component.ts
  • code/lib/mcp/src/utils/requires-own-mcp.test.ts
  • code/addons/mcp/src/manifests/core-format-contract.test.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/addons/mcp/src/tools/get-changed-stories.test.ts
  • code/lib/mcp/src/globals.d.ts
  • code/addons/mcp/src/tools/display-review.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.test.ts
  • code/addons/mcp/src/utils/build-args-param.test.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts
  • code/addons/mcp/src/auth/composition-auth.test.ts
  • code/addons/mcp/src/manifests/fixtures/core-manifest.fixture.json
  • code/lib/mcp/src/utils/dedent.ts
  • code/addons/mcp/src/tools/preview-stories.test.ts
  • code/addons/mcp/src/manifests/in-process-provider.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.test.ts
  • code/lib/mcp/src/utils/map-with-concurrency.ts
  • code/lib/mcp/src/utils/get-manifest.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/extract-docs-summary.ts
  • code/addons/mcp/src/utils/find-story-ids.test.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.ts
  • code/lib/mcp/src/utils/adapt-core-manifest.test.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.test.ts
  • code/lib/mcp/src/tools/get-documentation-for-story.ts
  • code/lib/mcp/src/utils/parse-react-docgen.ts
  • code/addons/mcp/src/utils/estimate-tokens.test.ts
  • code/addons/mcp/package.json
  • code/lib/mcp/src/utils/requires-own-mcp.ts
  • code/addons/mcp/src/tools/run-story-tests.ts
  • code/addons/mcp/src/utils/build-args-param.ts
  • code/addons/mcp/src/tools/run-story-tests.test.ts
  • code/lib/mcp/src/utils/manifest-formatter/markdown.ts
  • code/addons/mcp/src/tools/get-stories-by-component.test.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.ts
  • code/addons/mcp/src/manifests/vendored.ts
  • code/addons/mcp/src/utils/find-story-ids.ts
  • code/lib/mcp/src/tools/list-all-documentation.ts
  • code/addons/mcp/src/utils/resolve-component-stories.ts
  • code/addons/mcp/src/tools/get-changed-stories.ts
  • code/addons/mcp/src/manifests/service-access.test.ts
  • code/lib/mcp/src/tools/get-documentation.ts
  • code/addons/mcp/src/utils/estimate-tokens.ts
  • code/addons/mcp/src/tools/display-review.ts
  • code/addons/mcp/src/manifests/in-process-provider.ts
  • code/addons/mcp/src/manifests/service-access.ts
  • code/lib/mcp/src/utils/get-manifest.ts
  • code/addons/mcp/src/constants.ts
🚧 Files skipped from review as they are similar to previous changes (45)
  • code/addons/mcp/src/telemetry.ts
  • test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts
  • code/lib/mcp/src/utils/error-to-mcp-content.test.ts
  • code/lib/mcp/package.json
  • test-storybooks/mcp/.storybook-no-vitest/preview.ts
  • code/addons/mcp/src/utils/addon-vitest.ts
  • code/addons/mcp/src/tools/ui-root.ts
  • code/lib/mcp/src/utils/error-to-mcp-content.ts
  • code/lib/mcp/src/utils/multi-source-manifests.ts
  • code/lib/mcp/src/tools/outcome-unwrap.test.ts
  • code/addons/mcp/src/auth/resolve-composition-sources.ts
  • code/lib/mcp/bin.ts
  • code/addons/mcp/src/tools/get-storybook-story-instructions.test.ts
  • test-storybooks/mcp/.storybook-no-vitest/main.ts
  • code/addons/mcp/src/auth/composition-auth.ts
  • test-storybooks/mcp/tests/helpers.ts
  • test-storybooks/mcp/tests/mcp-addon-vitest-not-enabled.e2e.test.ts
  • code/addons/mcp/src/tools/preview-stories.ts
  • agent-eval/lib/templates.ts
  • code/addons/mcp/src/test-support/register-core-toolsets.ts
  • code/addons/mcp/src/utils/get-tool-availability.ts
  • code/addons/mcp/src/telemetry.test.ts
  • code/addons/mcp/src/utils/module-graph.ts
  • code/addons/mcp/src/instructions/build-server-instructions.ts
  • code/addons/mcp/src/preset.ts
  • code/addons/mcp/src/preset.test.ts
  • code/addons/mcp/src/tools/preview-stories/preview-stories-app-script.ts
  • code/lib/mcp/src/dist-contract.test.ts
  • code/addons/mcp/src/tools/toolset-tools.ts
  • AGENTS.md
  • code/addons/mcp/src/tools/tool-names.ts
  • code/addons/mcp/src/mcp-handler.test.ts
  • code/addons/mcp/src/tools/get-storybook-story-instructions.ts
  • code/addons/mcp/scripts/generate-tools-api-doc.ts
  • code/addons/mcp/src/tools/tool-registry.ts
  • code/addons/mcp/src/types.ts
  • code/lib/mcp/src/index.ts
  • code/core/src/shared/review/events.ts
  • code/lib/mcp/src/tools/list-all-documentation.test.ts
  • code/addons/mcp/src/tools/toolset-tools.test.ts
  • code/addons/mcp/src/mcp-handler.ts
  • code/lib/mcp/src/tools/get-documentation-for-story.test.ts
  • code/addons/mcp/src/storybook-ai-metadata.test.ts
  • code/lib/mcp/src/tools/get-documentation.test.ts
  • agent-eval/lib/templates.test.ts

Comment thread code/lib/mcp/src/tools/register.ts
@storybook-app-bot

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 2a585e1, ran on 12 August 2026 at 12:51:32 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-mcp

Before After Difference
Dependency count 13 11 🎉 -2 🎉
Self size 191 KB 129 KB 🎉 -63 KB 🎉
Dependency size 2.79 MB 2.64 MB 🎉 -145 KB 🎉
Bundle Size Analyzer Link Link

@storybook/mcp

Before After Difference
Dependency count 11 11 0
Self size 107 KB 144 KB 🚨 +36 KB 🚨
Dependency size 2.64 MB 2.64 MB 0 B
Bundle Size Analyzer Link Link

Base automatically changed from m2b-core-toolsets to next August 13, 2026 11:48
@JReinhold

Copy link
Copy Markdown
Contributor Author

"Self-merging" as this is originally a PR by @kasperpeulen that I approved but had to recreate here.

@JReinhold
JReinhold merged commit 4aeb67e into next Aug 13, 2026
148 of 149 checks passed
@JReinhold
JReinhold deleted the m4-mcp-on-core-toolsets branch August 13, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). maintenance User-facing maintenance tasks qa:skip Pull Requests that do not need any QA. (e.g. documentation)

Projects

None yet

3 participants