nuxt-ai-ready
Tested against nuxt-ai-ready 2.4.1 plus its unreleased fixes on main, on Nuxt 4.5 and Node 24.
The module converts rendered pages to Markdown with mdream and publishes llms.txt, llms-full.txt, and .md twins.
Optional parts add MCP tools, WebMCP tools, and a runtime page index. Config key: aiReady. Docs: https://nuxtseo.com/ai-ready
Setup
The package installs @nuxtjs/robots and @nuxtjs/sitemap and loads them as module dependencies. Configure them with the robots and sitemap keys.
pnpm add nuxt-ai-readySet site.url. Canonical URLs, Link headers, and /.well-known/ai-catalog.json use it.
Prerender the pages you want in llms-full.txt and in the page index (nuxi generate, or nitro.prerender.routes).
A page visit in dev or production does not index anything.
Automatic behaviour
With no aiReady config, the module adds:
/llms.txt: site name, description, resource links, and a## Pageslist. In dev it lists sitemap routes without titles./llms-full.txt: the full Markdown of each prerendered page. Only prerendered pages go in the static file.- A
.mdtwin per page./aboutbecomes/about.md, and/becomes/index.md. Paths under/apiand/_get none. - Accept negotiation: a request that prefers
text/markdown, or a known AI bot user agent, gets a307to the.mdURL. <link rel="alternate" type="text/markdown">and<link rel="describedby" href="/llms.txt">in HTML, plus matchingLinkheaders./sitemap.md, and a## Sitemapfooter on every generated.mdpage. SetsitemapMd: falseto remove both.- Nuxt Content v3
pagecollections: the.mdroute serves the source Markdown, not converted HTML. SetcontentSource: falseto convert HTML. - Agent skills: every
skills/<name>/SKILL.mdin the project root or a local layer is published at/.well-known/agent-skills/, at/skills/<name>/SKILL.md, and inllms.txt. With one skill it is also served at/SKILL.md. SetagentSkills: falseto publish nothing.
Off by default: Content Signals, MCP, WebMCP, runtime sync, cron, and the database.
Common tasks
Add llms.txt sections. notes renders before the first heading:
export default defineNuxtConfig({
aiReady: {
llmsTxt: {
sections: [{ title: 'API Reference', links: [{ title: 'REST API', href: '/docs/api', description: 'API docs' }] }],
notes: 'Built with Nuxt AI Ready',
},
},
})Remove an element from the Markdown on every path, build and runtime. Put it in mdreamOptions; the defaults minimal and clean stay on:
export default defineNuxtConfig({
aiReady: { mdreamOptions: { filter: { exclude: ['.author-bio'] } } },
})Change the Markdown text. The Nitro hook covers runtime .md responses, prerendered .md files, llms-full.txt, and indexed pages. ctx.isPrerender is true only during prerendering:
// server/plugins/markdown.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('ai-ready:page:markdown', (ctx) => {
ctx.markdown += '\n\nSee /support.'
})
})Allow Content Signals. An omitted permission renders as no:
export default defineNuxtConfig({ aiReady: { contentSignal: { search: true } } })
// robots.txt: Content-Signal: ai-train=no, search=yes, ai-input=noMCP: install @nuxtjs/mcp-toolkit and add it to modules. The module then registers list_pages, search_pages, and get_page_markdown at /mcp. MCP needs a running server; nuxi generate output cannot host it.
WebMCP: set webmcp: true. This registers the same three tools in the browser and auto-imports useWebMcpTool() and useWebMcpSupported(). Without webmcp, those composables are not defined.
Runtime indexing, database drivers, Cloudflare D1, and the server query helpers: see references/runtime-indexing.md.
Traps
- The same edit in both hooks applies twice. During prerendering the Nitro
ai-ready:page:markdownhook runs, then the Nuxt hook of the same name. Put an edit in one of them, not both. - Content source pages skip conversion hooks. A Nuxt Content page ignores
mdreamOptionsand both Nitro hooks. - Dev has no page data. Query helpers, MCP tools, and search return empty results in
nuxi dev. Test withnuxi buildandnode .output/server/index.mjs. - Response caching turns negotiation off. An ISR,
swr, orcacheroute rule withoutvaries: ['accept', 'sec-fetch-dest', 'user-agent']serves HTML to Markdown clients. The.mdURL still works. For a CDN that caches by URL only, setcontentNegotiation: false. - Emptying
ctx.markdowndoes not hide a page. It drops the body fromllms-full.txt. The URL stays inllms.txtand in the index. Usesitemap.excludefor discovery, and access control for private pages. - A project
skills/folder is public. Agent skills discovery publishes it with no opt in. Rename the folder withagentSkills.dir, or setagentSkills: false. - The same hook name exists twice.
ai-ready:page:markdownis a Nuxt hook (nuxt.confighooks, prerender only) and a Nitro hook (nitroApp.hooks, every HTML conversion). They receive different context. The Nitroctx.eventis undefined when indexing runs outside a request. database: falseconflicts withruntimeSyncandcron. The build fails and names the option.
Version limits
- v2 removed IndexNow. The
indexNowoption and/__ai-ready/indexnowno longer exist. Submit URLs from theai-ready:page:indexedNitro hook: https://nuxtseo.com/docs/ai-ready/advanced/indexnow - v1 renamed these. Do not write the old form:
| Old | New |
|---|---|
mdreamOptions: { preset: 'minimal' } |
mdreamOptions: { minimal: true } |
cacheMaxAgeSeconds |
llmsTxtCacheSeconds |
Nitro hook ai-ready:markdown |
ai-ready:page:markdown |
BulkDocument type |
PageDocument |
JSON.parse(page.headings) |
page.headings (already an array) |
?secret=TOKEN on /__ai-ready/* |
Authorization: Bearer TOKEN header |
Config
llmsTxt.markdownLinks(false): link page entries inllms.txtto their.mdtwins.describedby(true): thedescribedbylink tag and header.tools.<listPages|searchPages|getPageMarkdown>.<mcp|webmcp>.enabled: attach a built in tool to one transport only.autoI18n(true): with@nuxtjs/i18n, adds hreflangLinkheaders and a languages section inllms.txt.- Other options: https://nuxtseo.com/docs/ai-ready/api/config
Debug
curl -H 'Accept: text/markdown' -D - -o /dev/null <url>must return307withLocation: <path>.md. A200means a cache rule turned negotiation off./__ai-ready__/debug.jsonexists in dev, or withdebug: true.- Nuxt DevTools has an AI Ready tab.