Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion docs/content/docs/1.getting-started/7.ai/1.mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,16 @@ The Nuxt UI MCP server provides the following tools organized by category:

- **`list_components`**: Lists all available Nuxt UI components with their categories and basic information
- **`list_composables`**: Lists all available Nuxt UI composables with their categories and basic information
- **`get_component`**: Retrieves component documentation and details
- **`list_component_sections`**: Lists all available documentation sections for a specific component. Use this to discover what sections you can fetch (e.g., props, slots, theme, usage, examples)
- **`get_component`**: Retrieves component documentation and details. Supports optional `sections` parameter to fetch only specific parts (e.g., "props,slots") instead of full documentation to save tokens
- **`get_component_sections`**: Token-efficient tool to retrieve only specific sections of component documentation (e.g., props, slots, theme). Recommended when you only need certain information
- **`get_component_metadata`**: Retrieves detailed metadata for a component including props, slots, and events
- **`search_components_by_category`**: Searches components by category or text filter

::note{icon="i-lucide-lightbulb"}
**Token Optimization Tip**: Use `get_component_sections` or pass the `sections` parameter to `get_component` when you only need specific information like props or slots. This can reduce token usage by 70-90% compared to fetching full documentation.
::

### Template Tools

- **`list_templates`**: Lists all available Nuxt UI templates with optional category filtering
Expand Down Expand Up @@ -236,6 +242,8 @@ Once configured, you can ask your AI assistant questions like:
- "List all available Nuxt UI components"
- "Get Button component documentation"
- "What props does Input accept?"
- "What slots are available for the Chip component?"
- "Show me only the theme configuration for Button"
- "Find form-related components"
- "List dashboard templates"
- "Get template setup instructions"
Expand All @@ -245,3 +253,25 @@ Once configured, you can ask your AI assistant questions like:
- "Get ContactForm example code"

The AI assistant will use the MCP server to fetch structured JSON data and provide guided assistance for Nuxt UI during development.

### Token-Efficient Queries

When working with component documentation, you can request specific sections to save tokens:

- "What sections are available for the Button component?" (uses `list_component_sections`)
- "Get only the props section for the Button component" (uses `get_component_sections`)
- "Show me just the slots and emits for Card" (uses `get_component_sections`)
- "What's in the theme section for Input?" (uses `get_component_sections`)

The AI will automatically use the appropriate tool to fetch only the requested information, significantly reducing token usage while still providing the exact information you need.

#### Discovery Workflow

For best results, the AI can follow this pattern:
1. First, use `list_component_sections` to see what sections are available
2. Then, use `get_component_sections` to fetch only the sections you need

Example interaction:
- User: "I need to customize the Button component"
- AI uses `list_component_sections` β†’ discovers: props, slots, theme, usage, examples
- AI uses `get_component_sections` with `sections=theme,props` β†’ fetches only relevant parts
63 changes: 63 additions & 0 deletions docs/server/api/mcp/get-component-sections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { z } from 'zod'
import { kebabCase } from 'scule'
import { normalizeComponentName } from '~~/server/utils/normalizeComponentName'
import { parseMarkdownSections, getAvailableSections } from '~~/server/utils/parseMarkdownSections'
import { queryCollection } from '@nuxt/content/server'

const querySchema = z.object({
componentName: z.string(),
sections: z.string().optional().transform((val) => {
// Parse comma-separated sections or return all common sections
if (!val) return ['props', 'slots', 'emits', 'theme']
return val.split(',').map(s => s.trim().toLowerCase())
})
})

export default defineCachedEventHandler(async (event) => {
const { componentName, sections } = await getValidatedQuery(event, querySchema.parse)

// Normalize component name by removing "U" or "u-" prefix if present
const normalizedName = normalizeComponentName(componentName)

// Convert to kebab-case for path lookup
const kebabName = kebabCase(normalizedName)

// Get component documentation using queryCollection
const page = await queryCollection(event, 'docs')
.where('path', 'LIKE', `%/components/${kebabName}`)
.where('extension', '=', 'md')
.select('id', 'title', 'description', 'path', 'category', 'links')
.first()

if (!page) {
throw createError({
statusCode: 404,
statusMessage: `Component '${componentName}' not found in documentation`
})
}

// Fetch the raw markdown documentation
const documentation = await $fetch<string>(`/raw${page.path}.md`)

// Parse and extract only the requested sections
const extractedSections = parseMarkdownSections(documentation, sections)

// Get list of available sections for reference
const availableSections = getAvailableSections(documentation)

return {
name: normalizedName,
title: page.title,
description: page.description,
category: page.category,
documentation_url: `https://ui.nuxt.com${page.path}`,
requested_sections: sections,
available_sections: availableSections,
sections: extractedSections,
// Provide a hint if requested sections weren't found
missing_sections: sections.filter(s => !Object.keys(extractedSections).some(k => k.includes(s)))
}
}, {
name: 'mcp-get-component-sections',
maxAge: 1800 // 30 minutes
})
25 changes: 23 additions & 2 deletions docs/server/api/mcp/get-component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { z } from 'zod'
import { kebabCase } from 'scule'
import { normalizeComponentName } from '~~/server/utils/normalizeComponentName'
import { parseMarkdownSections } from '~~/server/utils/parseMarkdownSections'
import { queryCollection } from '@nuxt/content/server'

const querySchema = z.object({
componentName: z.string()
componentName: z.string(),
sections: z.string().optional().transform((val) => {
// Parse comma-separated sections if provided
if (!val) return null
return val.split(',').map(s => s.trim().toLowerCase())
})
})

export default defineCachedEventHandler(async (event) => {
const { componentName } = await getValidatedQuery(event, querySchema.parse)
const { componentName, sections } = await getValidatedQuery(event, querySchema.parse)

// Normalize component name by removing "U" or "u-" prefix if present
const normalizedName = normalizeComponentName(componentName)
Expand All @@ -32,6 +38,21 @@ export default defineCachedEventHandler(async (event) => {

const documentation = await $fetch<string>(`/raw${page.path}.md`)

// If sections are requested, parse and filter the documentation
if (sections) {
const extractedSections = parseMarkdownSections(documentation, sections)

return {
name: normalizedName,
title: page.title,
description: page.description,
category: page.category,
sections: extractedSections,
documentation_url: `https://ui.nuxt.com${page.path}`
}
}

// Otherwise return full documentation (backward compatible)
return {
name: normalizedName,
title: page.title,
Expand Down
78 changes: 78 additions & 0 deletions docs/server/api/mcp/list-component-sections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { z } from 'zod'
import { kebabCase } from 'scule'
import { normalizeComponentName } from '~~/server/utils/normalizeComponentName'
import { getAvailableSections } from '~~/server/utils/parseMarkdownSections'
import { queryCollection } from '@nuxt/content/server'

const querySchema = z.object({
componentName: z.string()
})

export default defineCachedEventHandler(async (event) => {
const { componentName } = await getValidatedQuery(event, querySchema.parse)

// Normalize component name by removing "U" or "u-" prefix if present
const normalizedName = normalizeComponentName(componentName)

// Convert to kebab-case for path lookup
const kebabName = kebabCase(normalizedName)

// Get component documentation using queryCollection
const page = await queryCollection(event, 'docs')
.where('path', 'LIKE', `%/components/${kebabName}`)
.where('extension', '=', 'md')
.select('id', 'title', 'description', 'path', 'category', 'links')
.first()

if (!page) {
throw createError({
statusCode: 404,
statusMessage: `Component '${componentName}' not found in documentation`
})
}

// Fetch the raw markdown documentation
const documentation = await $fetch<string>(`/raw${page.path}.md`)

// Get list of available sections
const availableSections = getAvailableSections(documentation)

// Group sections by common categories for easier understanding
const categorizedSections = {
api: availableSections.filter(s => ['props', 'slots', 'emits'].some(term => s.includes(term))),
configuration: availableSections.filter(s => s.includes('theme')),
documentation: availableSections.filter(s => ['usage', 'examples'].some(term => s.includes(term))),
meta: availableSections.filter(s => ['changelog', 'intellisense', 'api'].includes(s)),
other: [] as string[]
}

// Collect sections that don't fit in any category
const categorized = new Set([
...categorizedSections.api,
...categorizedSections.configuration,
...categorizedSections.documentation,
...categorizedSections.meta
])
categorizedSections.other = availableSections.filter(s => !categorized.has(s))

// Common sections that are typically useful
const commonSections = ['props', 'slots', 'emits', 'theme', 'usage', 'examples']
const recommendedSections = availableSections.filter(s =>
commonSections.some(common => s.includes(common))
)

return {
name: normalizedName,
title: page.title,
description: page.description,
category: page.category,
documentation_url: `https://ui.nuxt.com${page.path}`,
available_sections: availableSections,
recommended_sections: recommendedSections,
categorized_sections: categorizedSections,
total_sections: availableSections.length
}
}, {
name: 'mcp-list-component-sections',
maxAge: 1800 // 30 minutes
})
30 changes: 28 additions & 2 deletions docs/server/routes/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,10 @@ function createServer() {

server.tool(
'get_component',
'Retrieves Nuxt UI component documentation and details. Parameters: componentName (string, required) - the component name in PascalCase. Returns: A JSON object containing name, title, description, category, documentation, and documentation_url.',
'Retrieves Nuxt UI component documentation and details. Parameters: componentName (string, required) - the component name in PascalCase; sections (string, optional) - comma-separated list of sections to retrieve (e.g., "props,slots,theme") to save tokens by fetching only specific parts. Returns: A JSON object containing name, title, description, category, and either full documentation or filtered sections.',
{
componentName: z.string().describe('The name of the component (PascalCase)')
componentName: z.string().describe('The name of the component (PascalCase)'),
sections: z.string().optional().describe('Comma-separated sections to retrieve (e.g., "props,slots,emits,theme"). Use this to save tokens by fetching only needed sections instead of full documentation.')
},
async (params) => {
const result = await $fetch('/api/mcp/get-component', { query: params })
Expand All @@ -239,6 +240,31 @@ function createServer() {
}
)

server.tool(
'get_component_sections',
'Retrieves specific sections of Nuxt UI component documentation. This is a token-efficient alternative to get_component when you only need certain parts like props, slots, or theme. Parameters: componentName (string, required) - the component name in PascalCase; sections (string, optional) - comma-separated sections to retrieve. Common sections: "props", "slots", "emits", "theme", "usage", "examples". Defaults to "props,slots,emits,theme" if not specified. Returns: A JSON object with filtered sections and metadata about available sections.',
{
componentName: z.string().describe('The name of the component (PascalCase)'),
sections: z.string().optional().describe('Comma-separated sections to retrieve (e.g., "props,slots"). Common sections: props, slots, emits, theme, usage, examples. Defaults to props,slots,emits,theme')
},
async (params) => {
const result = await $fetch('/api/mcp/get-component-sections', { query: params })
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }
}
)

server.tool(
'list_component_sections',
'Lists all available documentation sections for a specific Nuxt UI component. Use this tool first to discover what sections are available before fetching specific content. Parameters: componentName (string, required) - the component name in PascalCase. Returns: A JSON object with available_sections array, recommended_sections array, and categorized sections grouped by type (api, configuration, documentation, meta).',
{
componentName: z.string().describe('The name of the component (PascalCase)')
},
async (params) => {
const result = await $fetch('/api/mcp/list-component-sections', { query: params })
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }
}
)

server.tool(
'list_templates',
'Lists all available Nuxt UI templates with optional category filtering. Parameters: category (string, optional) - filter by template category. Returns: A JSON object containing templates array, categories array, and total count.',
Expand Down
Loading
Loading