list-components
Retrieve all available UI components from Storybook files to query and analyze design system elements.
Instructions
Returns all available components
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Path to the index.json or stories.json file (optional if default path is provided) |
Implementation Reference
- src/tools/list-components.ts:7-22 (handler)The main handler function for the 'list-components' tool. It calls getComponents to fetch the list and returns it formatted as JSON text content.export const listComponents = async (storybookStaticDir: string) => { try { const components = await getComponents(storybookStaticDir); return { content: [ { type: 'text', text: JSON.stringify(components, null, 2), }, ], }; } catch (error) { console.error('Error listing components:', error); throw new McpError(ErrorCode.InternalError, 'Failed to list components'); } };
- src/index.ts:37-39 (schema)Zod schema defining the optional 'path' input parameter for the list-components tool.const ListComponentsParamsSchema = z.object({ path: z.string().optional().describe('Path to the index.json or stories.json file (optional if default path is provided)'), });
- src/index.ts:54-57 (registration)Registration of the 'list-components' tool in the ListTools response, including name, description, and input schema.name: 'list-components', description: 'Returns all available components', inputSchema: zodToJsonSchema(ListComponentsParamsSchema.describe('Parameters for listing components')) as ToolInput, },
- src/index.ts:82-83 (registration)Dispatch in the CallTool handler that invokes the listComponents function for the 'list-components' tool.case 'list-components': return listComponents(storybookStaticDir);
- src/storybook-api.ts:68-128 (helper)Core helper function that parses the Storybook stories.json file into a structured list of components with variants.export const getComponents = async (storybookStaticDir: string): Promise<Component[]> => { try { const storiesJsonContent = await fs.readFile(storybookStaticDir, 'utf-8'); const storiesData: StorybookData = JSON.parse(storiesJsonContent); const components: Component[] = []; const storyEntries = storiesData.entries || storiesData.stories; for (const storyId in storyEntries) { const story = storyEntries[storyId]; if (!story.id) { continue; // Skip stories without a title } // example-button--primary => example-button const componentId = story.id.split('--')[0]; const componentName = componentId .replace(/-/g, '/') .replace(/(^|\/)(\w)/g, (_, separator, char) => `${separator}${char.toUpperCase()}`); // Check if the story already exists in the components array let component = components.find(c => c.name === story.title); if (!component) { component = { id: componentId, name: componentName, description: '', props: [], variants: {}, }; components.push(component); } if (component) { const storybookStaticDirname = path.dirname(storybookStaticDir); const storyFileFullPath = getAbsolutePath(path.resolve(storybookStaticDirname, '../', story.importPath || '')); const componentFullPath = getAbsolutePath(path.resolve(storybookStaticDirname, '../', story.componentPath || '')); component.variants[story.id] = { name: story.name, parameters: story.parameters, id: story.id, title: story.title, importPath: story.importPath, componentPath: story.componentPath, kind: story.kind, story: story.story, storyFileFullPath, componentFullPath, }; } } return components; } catch (error) { console.error('Error reading or parsing stories.json:', error); return []; } };