11import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server' ;
2- import { queryCollection } from '@nuxt/content/server ' ;
2+ import { ofetch } from 'ofetch ' ;
33import { useEvent } from 'nitropack/runtime' ;
44import { z } from 'zod' ;
55import { docsSections } from '#shared/utils/docsSections' ;
6+ import { getMcpStaticBaseUrl } from '../../utils/mcpStatic' ;
67
78const BASE_PATH = '/docs' ;
89
910const allPrefixes = Array . from ( new Set ( docsSections . flatMap ( s => s . prefixes ) ) ) . sort ( ) ;
1011const prefixDescription = `Path prefix to filter by. Must start with "/". Valid prefixes: ${ allPrefixes . join ( ', ' ) } .` ;
1112
13+ interface McpDocIndexEntry {
14+ title : string ;
15+ path : string ;
16+ description : string ;
17+ }
18+
1219export default defineMcpTool ( {
1320 name : 'list-docs' ,
1421 title : 'List Directus docs' ,
@@ -27,22 +34,40 @@ export default defineMcpTool({
2734 const event = useEvent ( ) ;
2835 const config = useRuntimeConfig ( ) ;
2936 const siteOrigin = config . public . siteUrl . replace ( / \/ $ / , '' ) ;
30- let query = queryCollection ( event , 'content' )
31- . where ( 'path' , 'NOT LIKE' , '%/.%' )
32- . where ( 'path' , 'NOT LIKE' , '%/_partials/%' )
33- . order ( 'path' , 'ASC' ) ;
37+ const rows = await loadDocIndex ( event ) ;
38+ const filtered = pathPrefix
39+ ? rows . filter ( row => row . path . startsWith ( pathPrefix ) )
40+ : rows ;
41+
42+ return filtered . slice ( 0 , limit ?? 200 ) . map ( row => ( {
43+ title : row . title ,
44+ path : row . path ,
45+ description : row . description ?? '' ,
46+ url : `${ siteOrigin } ${ BASE_PATH } ${ row . path } ` ,
47+ } ) ) ;
48+ } ,
49+ } ) ;
3450
35- if ( pathPrefix ) {
36- query = query . where ( 'path' , 'LIKE' , `${ pathPrefix } %` ) ;
51+ async function loadDocIndex ( event : ReturnType < typeof useEvent > ) : Promise < McpDocIndexEntry [ ] > {
52+ try {
53+ return await ofetch < McpDocIndexEntry [ ] > ( `${ getMcpStaticBaseUrl ( ) } /mcp-docs-index.json` ) ;
54+ }
55+ catch {
56+ if ( ! import . meta. dev ) {
57+ throw createError ( { statusCode : 503 , message : 'Docs index unavailable' } ) ;
3758 }
3859
39- const rows = await query . limit ( limit ?? 200 ) . all ( ) ;
60+ const { queryCollection } = await import ( '@nuxt/content/server' ) ;
61+ const rows = await queryCollection ( event , 'content' )
62+ . where ( 'path' , 'NOT LIKE' , '%/.%' )
63+ . where ( 'path' , 'NOT LIKE' , '%/_partials/%' )
64+ . order ( 'path' , 'ASC' )
65+ . all ( ) ;
4066
4167 return rows . map ( row => ( {
4268 title : row . title ,
4369 path : row . path ,
4470 description : row . description ?? '' ,
45- url : `${ siteOrigin } ${ BASE_PATH } ${ row . path } ` ,
4671 } ) ) ;
47- } ,
48- } ) ;
72+ }
73+ }
0 commit comments