AI と LLM
Fumadocs に AI 機能を組み込みます。
LLM向けドキュメント
LLMやAIエージェント向けに、ドキュメントをMarkdown形式で提供します。
npx @fumadocs/cli feature llmsこれにより、docs コレクションで処理済みの Markdown が有効になり、lib/source.ts に docsLlms が追加されて、以下のファイルが配信されます。手動でセットアップする場合に備えて、生成されるファイルを以下に記載しています。
docsLlms
llms() は、ドキュメントを LLM 向けにレンダリングします。renderPage は、生のファイル内容ではなく処理済みのドキュメントをもとに、1 つのページを Markdown に変換します。
import { llms } from 'fumadocs-core/source';
export const docsLlms = llms(source, {
renderPage: async (page) => `# ${page.data.title} (${page.url})
${await page.data.getText('processed')}`,
});
| メソッド | 出力 |
|---|---|
index(lang?) | ページツリーから構築される llms.txt インデックス |
page(page) | renderPage でレンダリングした 1 つのページ |
full(lang?) | renderPage でレンダリングした全ページを結合したもの |
files() | エージェント向けファイルのパス |
serve(path) | 指定したパスにあるファイルのレスポンス |
renderPage は必須です
コンテンツソースが Markdown をどのように公開しているかを Fumadocs 側では判断できないため、page()、full()、files()、serve() は
renderPage を渡した場合にのみ利用できます。
renderPage はページの処理済み Markdown を読み取るため、includeProcessedMarkdown を有効にしてください。
import { defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
dir: 'content/docs',
docs: {
postprocess: {
includeProcessedMarkdown: true,
},
},
});
MDX コンポーネントは JSX 構文のまま出力されます。これらを Markdown 形式にレンダリングするには、MDX コンポーネントをページの props として渡してください。
@fumadocs/local-md のようなランタイムのコンテンツソースは、リクエスト時に解決されます。その getSource を渡すと、CLI が同じファイルを生成します。
export const docsLlms = llms(getSource, {
renderPage: (page) => `# ${page.data.title} (${page.url})
${page.data.content}`,
});getSource を使用する場合、index() と indexNode() は文字列ではなく Promise を返します。
ファイル
CLIは、AIエージェント向けに次のファイルを配信します。
/llms.txt: ドキュメントのインデックスです。各ページのMarkdownへのリンクが含まれます。/llms-full.txt: 全ページのコンテンツです。<page>.md: 各ページのMarkdownです (例:/docs/ui.md) 。/のページは/index.mdになります。<section>/llms-full.txt: セクションのコンテンツです (例:/docs/ui/llms-full.txt) 。
下書きなどのページをこれらのファイルから除外するには、filter を指定します。除外したページも llms.txt には引き続き掲載され、HTMLページへのリンクになります。
export const docsLlms = llms(source, {
filter: (page) => page.slugs[0] !== 'drafts',
renderPage: async (page) => `# ${page.data.title}\n\n${await page.data.getText('processed')}`,
});これらのファイルでは、renderUrl はリンク先のファイルのパス (ページの .md ファイルなど) を受け取ります。
ページの HTML を読み取るエージェントは、<head> 内のリンクからそのページの Markdown を見つけます:
<link rel="alternate" type="text/markdown" href="/docs/ui.md" />セクション
セクションとは、独自の llms-full.txt を持つページツリー内のフォルダーです。これにより、エージェントは大規模なドキュメントを部分ごとに読み込めます。デフォルトでは、すべてのルートフォルダーがセクションになります。llms.txt では、各フォルダーの行がそのセクションの llms-full.txt へのリンクになります。
セクションとするフォルダーを指定するには、section を渡します。この関数はフォルダーを受け取り、そのフォルダーをセクションとするかどうかを返します。
export const docsLlms = llms(source, {
// index ページを持つすべてのフォルダー
section: (folder) => folder.index !== undefined,
renderPage: async (page) => `# ${page.data.title}\n\n${await page.data.getText('processed')}`,
});大規模なサイトでは、セクションを折りたたむと llms.txt を短く保てます。折りたたんだセクションは、llms.txt ではそのセクション専用の <section>/llms.txt への1つのリンクとして記載され、セクション内のページはそのファイルに一覧表示されます。
export const docsLlms = llms(source, {
section: (folder) => (folder.root ? { collapse: true } : false),
renderPage: async (page) => `# ${page.data.title}\n\n${await page.data.getText('processed')}`,
});セクションのファイルは、そのフォルダーのインデックスページの URL 配下で配信されます。インデックスページがないフォルダーでは、代わりに配下のページの URL ディレクトリが使われます。フォルダーグループのように 2 つのフォルダーが同じ URL を共有する場合は、asPath を渡すと、一方を別のパスで配信できます (例:{ asPath: '/docs/guides' }) 。
ルート
files() はファイルのパスを列挙し、serve(path) は指定したパスのファイルをレスポンスとして返します。そのため、各ルートはリクエストパスを serve() に渡すだけで済みます。
API ルートが /llms.mdx 配下でファイルを配信し、renderUrl で llms.txt 内のリンク先をそちらに向けます。サーバー上では、src/middleware 内の Hono ミドルウェア が /docs/ui.md などのファイルも本来のパスで配信します。型定義を利用するため、hono を開発依存関係としてインストールしてください:
import { docsLlms } from '@/lib/source';
export async function GET() {
return (await docsLlms.serve('/llms.txt'))!;
}
export async function getConfig() {
return {
render: 'static' as const,
} as const;
}
serve() はファイルが存在しないパスに対して undefined を返すため、ミドルウェアはリクエストを後続の処理に渡せます。hideLocale: 'always' を指定した場合は URL にロケールが含まれないため、言語を serve() の第2引数、および files() の第1引数として渡してください。
静的出力
API ルートはプリレンダリングされるため、静的ファイルとしてデプロイした Waku サイトでも /llms.mdx 配下でファイルが配信されます。ただし、ミドルウェアを使うにはサーバーが必要です。
Accept
AIエージェントは、Accept ヘッダーを使って Markdown を要求できます。
上記のミドルウェアは、リクエストが Markdown を優先する場合に、ドキュメントページの Markdown を返します。
プリレンダリングされたページはミドルウェアの実行前に静的ファイルとして配信されるため、常に HTML が返されます。
同じ URL に2つの表現が存在することになるため、キャッシュの衝突を防ぐには、レスポンスに Vary: Accept を含める必要があります。
ページアクション
ページアクションを使うと、読者はページの Markdown をコピーしたり、AI アプリでページを開いたりできます。ページアクションは、ページの .md ファイルを読み込みます。

docs ページ内でレンダリングしてください。
import { MarkdownCopyButton, ViewOptionsPopover } from 'fumadocs-ui/layouts/docs/page';
const markdownUrl = `${page.url}.md`;
<div className="flex flex-row gap-2 items-center border-b pt-2 pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<ViewOptionsPopover
markdownUrl={markdownUrl}
githubUrl={`https://github.com/${owner}/${repo}/blob/main/content/docs/${encodeURI(page.path)}`}
/>
</div>;静的デプロイでも配信されるよう、URL には `/llms.mdx${page.url}.md` を使用してください。
MCP サーバー
MCP サーバーを通じてドキュメントをAIエージェントに公開できます。ページの一覧表示・検索・読み取りを行うツールも提供されます。
npx @fumadocs/cli feature mcp上記の LLM ルート に加えて、Streamable HTTP トランスポートを使用する /api/mcp ルートを作成します。
ツールは fumadocs-core/mcp によって提供されます。
import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import { registerSearchTool, registerSourceTools } from 'fumadocs-core/mcp';
import { createFromSource } from 'fumadocs-core/search/server';
import { docsLlms, source } from '@/lib/source';
const handler = createMcpHandler(() => {
const mcp = new McpServer(
{
name: 'docs',
version: '1.0.0',
},
// the tools never change, a stream to watch them would hold a serverless function open
{ capabilities: { tools: { listChanged: false } } },
);
registerSourceTools(mcp, source, docsLlms);
registerSearchTool(mcp, createFromSource(source));
return mcp;
});
export async function GET(request: Request) {
return handler.fetch(request);
}
export async function POST(request: Request) {
return handler.fetch(request);
}
export async function DELETE(request: Request) {
return handler.fetch(request);
}
エージェントを接続するには、次のようにします。
{
"mcpServers": {
"docs": { "url": "https://your-site.com/api/mcp" }
}
}WebMCP
実験的機能
WebMCP は策定初期段階の Web 標準で、Chrome 149 以降で
#enable-webmcp-testing フラグを有効にするか、オリジントライアルを通じて利用できます。API は今後
変更される可能性があります。
前述の MCP サーバーがサイトに接続してくるエージェント向けであるのに対し、WebMCP は読者が閲覧しているページ上で、ブラウザに組み込まれた AIエージェント にツールを公開します。
npx @fumadocs/cli feature webmcpLLM ルートをベースにした WebMCP コンポーネントが作成されます。これを <RootProvider /> の内側でレンダリングしてください。
search_docsは検索 API ルートにクエリを送信します。fetchClientは他のクライアントに置き換えることもできます。read_pageは、/llms.mdx/docs/page.mdからページの Markdown を取得します。
AIに質問

Fumadocs CLI を使用して、AI チャットダイアログをインストールできます。
npx @fumadocs/cli add ai/openrouterVercel AI SDK を使用して OpenRouter 向けに自動で設定され、AI 用の /search ツールも含まれます。
/api/chat ルートを更新すれば、他のモデルも使用できます。
Fumadocs は AI モデルを提供していません。モデルはご自身で用意してください。
AI モデルには、上記で生成した llms-full.txt ファイルを利用できます。また、サードパーティのソリューションと組み合わせれば、より多様な情報ソースを活用することもできます。
Docs レイアウトは、aiChat オプションをもとにチャットをレンダリングします。このオプションはクライアントの状態を受け取るため、レイアウト用のクライアントコンポーネントを作成し、元のレイアウトの代わりに使用してください。
'use client';
// Notebook、Glass、Spacious レイアウトも使用できます
import { DocsLayout as Layout, type DocsLayoutProps } from 'fumadocs-ui/layouts/docs';
// インストールしたコンポーネント
import { AIChat, AIChatPanel, useAIChat } from './search';
export function DocsLayout(props: DocsLayoutProps) {
return (
<AIChat>
<ChatLayout {...props} />
</AIChat>
);
}
function ChatLayout(props: DocsLayoutProps) {
const { open, setOpen } = useAIChat();
return (
<Layout
{...props}
aiChat={{ open, onOpenChange: setOpen, panel: <AIChatPanel />, trigger: true }}
/>
);
}レイアウトのオプションはクライアントコンポーネントに渡されるため、シリアライズ可能な値にする必要があります。
How is this guide?
最終更新日
