Skip to content
Merged
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
16 changes: 11 additions & 5 deletions layer/server/mcp/tools/get-page.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { z } from 'zod'
import { joinURL } from 'ufo'
import { queryCollection } from '@nuxt/content/server'
import type { Collections } from '@nuxt/content'
import { getAvailableLocales, getCollectionFromPath } from '../../utils/content'
import { queryCollection } from '@nuxt/content/server'
import { joinURL } from 'ufo'
import { z } from 'zod'
import { inferSiteURL } from '../../../utils/meta'
import { getAvailableLocales, getCollectionFromPath, isNavigationPath } from '../../utils/content'

export default defineMcpTool({
description: `Retrieves the full content and details of a specific documentation page.
Expand All @@ -25,14 +25,20 @@ WORKFLOW: This tool returns the complete page content including title, descripti
openWorldHint: false,
},
inputSchema: {
path: z.string().describe('The page path from list-pages or provided by the user (e.g., /en/getting-started/installation)'),
path: z.string().describe(
'The page path from list-pages or provided by the user (e.g., /en/getting-started/installation)',
),
},
inputExamples: [
{ path: '/en/getting-started/installation' },
{ path: '/getting-started/introduction' },
],
cache: '1h',
handler: async ({ path }) => {
if (isNavigationPath(path)) {
throw createError({ statusCode: 404, message: 'Page not found' })
}

const event = useEvent()
const config = useRuntimeConfig(event)
const publicConfig = config.public
Expand Down
9 changes: 5 additions & 4 deletions layer/server/mcp/tools/list-pages.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { z } from 'zod'
import { joinURL } from 'ufo'
import { queryCollection } from '@nuxt/content/server'
import type { Collections } from '@nuxt/content'
import { getCollectionsToQuery, getAvailableLocales } from '../../utils/content'
import { queryCollection } from '@nuxt/content/server'
import { joinURL } from 'ufo'
import { z } from 'zod'
import { inferSiteURL } from '../../../utils/meta'
import { getAvailableLocales, getCollectionsToQuery } from '../../utils/content'

export default defineMcpTool({
description: `Lists all available documentation pages with their categories and basic information.
Expand Down Expand Up @@ -52,6 +52,7 @@ OUTPUT: Returns a structured list with:
const allPages = await Promise.all(
collections.map(async (collectionName) => {
const pages = await queryCollection(event, collectionName as keyof Collections)
.where('path', 'NOT LIKE', '%.navigation')
.select('title', 'path', 'description')
.all()

Expand Down
9 changes: 6 additions & 3 deletions layer/server/routes/sitemap.xml.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { queryCollection } from '@nuxt/content/server'
import { getAvailableLocales, getCollectionsToQuery } from '../utils/content'
import { inferSiteURL } from '../../utils/meta'
import { getAvailableLocales, getCollectionsToQuery, isNavigationPath } from '../utils/content'

interface SitemapUrl {
loc: string
Expand All @@ -27,7 +27,10 @@ export default defineEventHandler(async (event) => {

for (const collection of collections) {
try {
const pages = await (queryCollection as unknown as (event: unknown, collection: string) => { all: () => Promise<Array<Record<string, unknown> & { path?: string }>> })(event, collection).all()
const pages = await (queryCollection as unknown as (
event: unknown,
collection: string,
) => { all: () => Promise<Array<Record<string, unknown> & { path?: string }>> })(event, collection).all()

for (const page of pages) {
const meta = page as Record<string, unknown>
Expand All @@ -37,7 +40,7 @@ export default defineEventHandler(async (event) => {
if (meta.sitemap === false) continue

// Skip .navigation files (used for navigation configuration)
if (pagePath.endsWith('.navigation') || pagePath.includes('/.navigation')) continue
if (isNavigationPath(pagePath)) continue

const urlEntry: SitemapUrl = {
loc: pagePath,
Expand Down
4 changes: 4 additions & 0 deletions layer/server/utils/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export function getCollectionsToQuery(locale: string | undefined, availableLocal
: ['docs']
}

export function isNavigationPath(path: string): boolean {
return path.endsWith('.navigation') || path.includes('/.navigation/')
}

export function getCollectionFromPath(path: string, availableLocales: string[]): string {
const pathSegments = path.split('/').filter(Boolean)
const firstSegment = pathSegments[0]
Expand Down
Loading