Skip to content

Commit 0fc05b7

Browse files
committed
docs(mcp): consolidate tools and add icons search
1 parent 472851d commit 0fc05b7

10 files changed

Lines changed: 170 additions & 116 deletions

docs/content/docs/1.getting-started/7.ai/1.mcp.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,26 @@ You're able to access these resources with tools like Claude Code by using `@`.
2626

2727
The Nuxt UI MCP server provides the following tools organized by category:
2828

29+
### Search Tools
30+
31+
- **`search_components`**: Search components by name, description, or category. With no params, lists all components
32+
- **`search_composables`**: Search composables by name or description. With no params, lists all composables
33+
- **`search_icons`**: Search for icons across Iconify collections (defaults to `lucide`). Returns icon names in the `i-{prefix}-{name}` format used by Nuxt UI
34+
2935
### Component Tools
3036

31-
- **`list_components`**: Lists all available Nuxt UI components with their categories and basic information
32-
- **`list_composables`**: Lists all available Nuxt UI composables with their categories and basic information
3337
- **`get_component`**: Retrieves component documentation and details. Supports a `sections` parameter (`usage`, `examples`, `api`, `theme`, `changelog`) to fetch only specific parts and reduce response size
3438
- **`get_component_metadata`**: Retrieves detailed metadata for a component including props, slots, and events (lightweight, no documentation content)
35-
- **`search_components_by_category`**: Searches components by category or text filter
3639

37-
### Template Tools
40+
### Documentation Tools
3841

39-
- **`list_templates`**: Lists all available Nuxt UI templates with optional category filtering
40-
- **`get_template`**: Retrieves template details and setup instructions
42+
- **`search_documentation`**: Search documentation pages by title, description, or section. With no params, lists all pages. Use `section` to filter (e.g., `"getting-started"`, `"components"`)
43+
- **`get_documentation_page`**: Retrieves documentation page content by URL path. Supports a `headings` parameter to fetch only specific h2 sections (e.g., `["Usage", "API"]`) and reduce response size
4144

42-
### Documentation Tools
45+
### Template Tools
4346

44-
- **`list_documentation_pages`**: Lists all documentation pages
45-
- **`get_documentation_page`**: Retrieves documentation page content by URL path. Supports a `sections` parameter to fetch only specific h2 sections (e.g., `["Usage", "API"]`) and reduce response size
46-
- **`list_getting_started_guides`**: Lists all getting started guides and installation instructions
47+
- **`list_templates`**: Lists all available Nuxt UI templates with optional framework filtering
48+
- **`get_template`**: Retrieves template details and setup instructions
4749

4850
### Example Tools
4951

@@ -340,6 +342,7 @@ Once configured, you can ask your AI assistant questions like:
340342
- "Show me just the Button usage examples"
341343
- "What props does Input accept?"
342344
- "Find form-related components"
345+
- "Search for arrow icons in lucide"
343346
- "List dashboard templates"
344347
- "Get template setup instructions"
345348
- "Show installation guide"
@@ -350,5 +353,5 @@ Once configured, you can ask your AI assistant questions like:
350353
The AI assistant will use the MCP server to fetch structured JSON data and provide guided assistance for Nuxt UI during development.
351354

352355
::tip
353-
For large documentation pages, the AI can use the `sections` parameter to fetch only relevant parts (like "Usage" or "API"), reducing response size and improving performance.
356+
For component docs, the AI can use the `sections` parameter (`usage`, `examples`, `api`, `theme`, `changelog`) to fetch only relevant parts. For other pages, use the `headings` parameter with h2 titles (e.g., `["Usage", "API"]`).
354357
::

docs/server/mcp/tools/get-documentation-page.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { z } from 'zod'
22

33
export default defineMcpTool({
4-
description: 'Retrieves documentation page content by URL path. Use the `sections` parameter to fetch only specific h2 sections to reduce response size.',
4+
description: 'Retrieves documentation page content by URL path. Use the `headings` parameter to fetch only specific h2 sections to reduce response size.',
55
annotations: {
66
readOnlyHint: true,
77
destructiveHint: false,
@@ -10,24 +10,23 @@ export default defineMcpTool({
1010
},
1111
inputSchema: {
1212
path: z.string().describe('The path to the content page (e.g., /docs/components/button)'),
13-
sections: z.array(z.string()).optional().describe('Specific h2 section titles to return (e.g., ["Usage", "API"]). If omitted, returns full documentation.')
13+
headings: z.array(z.string()).optional().describe('Specific h2 heading titles to extract (e.g., ["Usage", "API"]). If omitted, returns full page.')
1414
},
1515
inputExamples: [
16-
{ path: '/docs/components/button', sections: ['Usage', 'API'] },
16+
{ path: '/docs/components/button', headings: ['Usage', 'API'] },
1717
{ path: '/docs/getting-started/installation' }
1818
],
1919
cache: '30m',
20-
async handler({ path, sections }) {
20+
async handler({ path, headings }) {
2121
let content
2222
try {
2323
content = await $fetch<string>(`/raw${path}.md`)
2424
} catch {
2525
throw createError({ statusCode: 404, message: `Documentation page not found at path: ${path}` })
2626
}
2727

28-
// If sections are specified, extract only those sections
29-
if (sections && sections.length > 0) {
30-
content = extractSections(content, sections)
28+
if (headings && headings.length > 0) {
29+
content = extractSections(content, headings)
3130
}
3231

3332
return content

docs/server/mcp/tools/list-components.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

docs/server/mcp/tools/list-composables.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

docs/server/mcp/tools/list-documentation-pages.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.

docs/server/mcp/tools/list-getting-started-guides.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

docs/server/mcp/tools/search-components-by-category.ts renamed to docs/server/mcp/tools/search-components.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { z } from 'zod'
22
import { queryCollection } from '@nuxt/content/server'
33

44
export default defineMcpTool({
5-
description: 'Searches components by category or text filter',
5+
description: 'Search components by name, description, or category',
66
annotations: {
77
readOnlyHint: true,
88
destructiveHint: false,
@@ -44,7 +44,6 @@ export default defineMcpTool({
4444
links: component.links
4545
}))
4646

47-
// Apply search filter if provided
4847
if (search) {
4948
const searchLower = search.toLowerCase()
5049
results = results.filter(component =>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { z } from 'zod'
2+
import { queryCollection } from '@nuxt/content/server'
3+
4+
export default defineMcpTool({
5+
description: 'Search composables by name or description',
6+
annotations: {
7+
readOnlyHint: true,
8+
destructiveHint: false,
9+
idempotentHint: true,
10+
openWorldHint: false
11+
},
12+
inputSchema: {
13+
search: z.string().optional().describe('Search term to filter composables by name or description')
14+
},
15+
inputExamples: [
16+
{},
17+
{ search: 'toast' },
18+
{ search: 'overlay' }
19+
],
20+
cache: '1h',
21+
async handler({ search }) {
22+
const event = useEvent()
23+
24+
const composables = await queryCollection(event, 'docs')
25+
.where('path', 'LIKE', '/docs/composables/%')
26+
.where('extension', '=', 'md')
27+
.select('path', 'title', 'description')
28+
.all()
29+
30+
let results = composables.map(composable => ({
31+
name: composable.path.split('/').pop(),
32+
title: composable.title,
33+
description: composable.description,
34+
path: composable.path,
35+
url: `https://ui.nuxt.com${composable.path}`
36+
}))
37+
38+
if (search) {
39+
const searchLower = search.toLowerCase()
40+
results = results.filter(composable =>
41+
composable.name?.toLowerCase().includes(searchLower)
42+
|| composable.title?.toLowerCase().includes(searchLower)
43+
|| composable.description?.toLowerCase().includes(searchLower)
44+
)
45+
}
46+
47+
return {
48+
composables: results.sort((a, b) => (a.name || '').localeCompare(b.name || '')),
49+
total: results.length
50+
}
51+
}
52+
})
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { z } from 'zod'
2+
import { queryCollection } from '@nuxt/content/server'
3+
4+
export default defineMcpTool({
5+
description: 'Search documentation pages by title, description, or section. With no params, lists all pages.',
6+
annotations: {
7+
readOnlyHint: true,
8+
destructiveHint: false,
9+
idempotentHint: true,
10+
openWorldHint: false
11+
},
12+
inputSchema: {
13+
search: z.string().optional().describe('Search term to filter pages by title or description'),
14+
section: z.string().optional().describe('Filter by documentation section (e.g., "getting-started", "components", "composables")')
15+
},
16+
inputExamples: [
17+
{},
18+
{ section: 'getting-started' },
19+
{ search: 'installation' },
20+
{ search: 'color', section: 'getting-started' }
21+
],
22+
cache: '30m',
23+
async handler({ search, section }) {
24+
const event = useEvent()
25+
26+
let query = queryCollection(event, 'docs')
27+
.select('title', 'description', 'path')
28+
29+
if (section) {
30+
query = query.where('path', 'LIKE', `/docs/${section}/%`)
31+
}
32+
33+
const pages = await query.all()
34+
35+
let results = pages.map(page => ({
36+
title: page.title,
37+
description: page.description,
38+
path: page.path,
39+
url: `https://ui.nuxt.com${page.path}`
40+
}))
41+
42+
if (search) {
43+
const searchLower = search.toLowerCase()
44+
results = results.filter(page =>
45+
page.title?.toLowerCase().includes(searchLower)
46+
|| page.description?.toLowerCase().includes(searchLower)
47+
)
48+
}
49+
50+
return {
51+
pages: results.sort((a, b) => a.path.localeCompare(b.path)),
52+
total: results.length
53+
}
54+
}
55+
})
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { z } from 'zod'
2+
3+
export default defineMcpTool({
4+
description: 'Search for icons across Iconify collections. Returns matching icon names in the `i-{prefix}-{name}` format used by Nuxt UI. Default collection is `lucide`.',
5+
annotations: {
6+
readOnlyHint: true,
7+
destructiveHint: false,
8+
idempotentHint: true,
9+
openWorldHint: true
10+
},
11+
inputSchema: {
12+
query: z.string().describe('Search query (e.g., "arrow", "home", "settings")'),
13+
collection: z.string().default('lucide').describe('Icon collection to search within (e.g., "lucide", "heroicons", "mdi"). Defaults to "lucide".'),
14+
limit: z.number().min(1).max(999).optional().describe('Maximum number of results (default: 64)')
15+
},
16+
inputExamples: [
17+
{ query: 'home' },
18+
{ query: 'arrow', collection: 'heroicons' },
19+
{ query: 'chart', collection: 'lucide', limit: 10 }
20+
],
21+
cache: '1h',
22+
async handler({ query, collection, limit }) {
23+
const params = new URLSearchParams({ query, prefix: collection })
24+
if (limit) params.set('limit', String(limit))
25+
26+
const data = await $fetch<{ icons: string[], total: number }>(`https://api.iconify.design/search?${params}`)
27+
28+
return {
29+
icons: data.icons.map((icon) => {
30+
const [iconPrefix, ...nameParts] = icon.split(':')
31+
const name = nameParts.join(':')
32+
return {
33+
name: `i-${iconPrefix}-${name}`,
34+
preview: `https://api.iconify.design/${iconPrefix}/${name}.svg`
35+
}
36+
}),
37+
total: data.total,
38+
query,
39+
collection
40+
}
41+
}
42+
})

0 commit comments

Comments
 (0)