---
title: "Assistant"
description: "Add AI-powered chat to your docs that answers questions, cites sources, and generates code examples."
canonical_url: "https://docus.dev/en/ai/assistant"
---
# Assistant

> Add AI-powered chat to your docs that answers questions, cites sources, and generates code examples.

## About the Assistant

The assistant answers questions about your documentation through natural language queries. It is embedded directly in your documentation site, so users can find answers quickly and succeed with your product.

When users ask questions, the assistant:

- **Searches and retrieves** relevant content from your documentation using an [MCP server](https://docus.dev/en/ai/mcp).
- **Cites sources** with navigable links to take users directly to referenced pages.
- **Generates copyable code examples** to help users implement solutions from your documentation.

## How It Works

The assistant uses a multi-agent architecture:

1. **Main Agent** - Receives user questions and decides when to search documentation
2. **Search Agent** - Uses [MCP server](https://docus.dev/en/ai/mcp) tools to find relevant content
3. **Response Generation** - Synthesizes information into helpful, conversational answers

By default, the assistant connects to your documentation's built-in MCP server at `/mcp`, giving it access to all your pages without additional configuration. You can also connect to an external MCP server if needed.

## Quick Start

<note to="#custom-ai-provider">

This quick start uses Vercel AI Gateway. To use another provider (Mistral, OpenAI, Cloudflare AI Gateway, or anything else supported by the AI SDK), see **Custom AI provider**.

</note>

### 1. Set up AI Gateway authentication

Pick **one** of these methods:

**API key**: create a key in [Vercel AI Gateway](https://vercel.com/~/ai/api-keys) and add it to your environment:

```bash [.env]
AI_GATEWAY_API_KEY=your-api-key
```

**OIDC (only on Vercel)**: `VERCEL_OIDC_TOKEN` is injected automatically, so there is nothing to add in production. For local dev, run `vercel env pull` on a [linked project](https://vercel.com/docs/cli/link).

### 2. Deploy

Deploy your site, the assistant is available as soon as authentication is configured.

## Configuration

Configure the assistant through `app.config.ts`:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    // Show the floating input on documentation pages
    floatingInput: true,

    // Show the "Explain with AI" button in the sidebar
    explainWithAi: true,

    // FAQ questions to display when chat is empty
    faqQuestions: [],

    // Keyboard shortcuts
    shortcuts: {
      focusInput: 'meta_i'
    },

    // Custom icons
    icons: {
      trigger: 'i-lucide-sparkles',
      explain: 'i-lucide-brain'
    }
  }
})
```

### Questions

Display suggested questions when the chat is empty. This helps users discover what they can ask.

#### Simple Format

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    faqQuestions: [
      'How do I install Docus?',
      'How do I customize the theme?',
      'How do I add components to my pages?'
    ]
  }
})
```

#### Category Format

Organize questions into categories:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    faqQuestions: [
      {
        category: 'Getting Started',
        items: [
          'How do I install Docus?',
          'What is the project structure?'
        ]
      },
      {
        category: 'Customization',
        items: [
          'How do I change the theme colors?',
          'How do I add a custom logo?'
        ]
      }
    ]
  }
})
```

#### Localized Format

For multi-language documentation, provide FAQ questions per locale:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    faqQuestions: {
      en: [
        { category: 'Getting Started', items: ['How do I install?'] }
      ],
      fr: [
        { category: 'Démarrage', items: ['Comment installer ?'] }
      ]
    }
  }
})
```

### Keyboard Shortcuts

Configure the keyboard shortcut for focusing the floating input:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    shortcuts: {
      // Default: 'meta_i' (Cmd+I on Mac, Ctrl+I on Windows)
      focusInput: 'meta_k' // Change to Cmd/Ctrl+K
    }
  }
})
```

The shortcut format uses underscores to separate keys. Common examples:

- `meta_i` - Cmd+I (Mac) / Ctrl+I (Windows)
- `meta_k` - Cmd+K (Mac) / Ctrl+K (Windows)
- `ctrl_shift_p` - Ctrl+Shift+P

### Icons

Customize the icons used by the assistant:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    icons: {
      // Icon for the trigger button and slideover header
      trigger: 'i-lucide-bot',

      // Icon for the "Explain with AI" button
      explain: 'i-lucide-lightbulb'
    }
  }
})
```

Icons use the [Iconify](https://iconify.design/) format (e.g., `i-lucide-sparkles`, `i-heroicons-sparkles`).

### Features

#### Disable the Floating Input

Hide the floating input at the bottom of documentation pages:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    floatingInput: false
  }
})
```

#### Disable "Explain with AI"

Hide the "Explain with AI" button in the documentation sidebar:

```ts [app.config.ts]
export default defineAppConfig({
  assistant: {
    explainWithAi: false
  }
})
```

#### Disable the Assistant Entirely

Set `enabled` to `false` to disable the assistant, even when AI Gateway credentials are available:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  docus: {
    assistant: {
      enabled: false
    }
  }
})
```

### MCP Server Configuration

The assistant uses an MCP server to access your documentation. You have two options:

#### Use the Built-in MCP Server (Default)

By default, the assistant uses Docus's built-in MCP server at `/mcp`:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  docus: {
    assistant: {
      mcpServer: '/mcp'
    }
  }
})
```

<warning>

Make sure the MCP server is enabled in your configuration. If you've customized the MCP path, update `mcpServer` accordingly.

</warning>

#### Use an External MCP Server

Connect to any external MCP server by providing a full URL:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  docus: {
    assistant: {
      mcpServer: 'https://other-docs.example.com/mcp'
    }
  }
})
```

This is useful when you want the assistant to answer questions from a different documentation source, or when connecting to a centralized knowledge base.

### Model

The assistant uses `google/gemini-3-flash` by default. You can change this to any model supported by the AI SDK Gateway:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  docus: {
    assistant: {
      model: 'anthropic/claude-opus-4.5'
    }
  }
})
```

### Site Name

The assistant automatically uses your site name in its responses. Configure the site name in `nuxt.config.ts`:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  site: {
    name: 'My Documentation'
  }
})
```

This makes the assistant respond as "the My Documentation assistant" and speak with authority about your specific product.

## Custom provider

The `model` option above resolves models through Vercel AI Gateway, so it requires `AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN`. To use another provider (Mistral, OpenAI, Cloudflare AI Gateway, or anything else supported by the [AI SDK](https://ai-sdk.dev/)), enable the assistant explicitly and provide your own endpoint.

<steps>

### Enable the assistant and pick a path

Set `enabled: true` so the assistant no longer depends on AI Gateway credentials, and point `apiPath` at the route you're about to create:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  docus: {
    assistant: {
      enabled: true,
      apiPath: '/api/assistant'
    }
  }
})
```

Your own server route always takes precedence: when you define a route at `apiPath`, Docus steps aside and doesn't register its built-in endpoint there.

### Install a provider

Install the AI SDK provider package you need, for example Mistral:

<code-group>

```bash [npm]
npm install @ai-sdk/mistral
```

```bash [pnpm]
pnpm add @ai-sdk/mistral
```

```bash [yarn]
yarn add @ai-sdk/mistral
```

</code-group>

### Implement the endpoint

```ts [server/api/assistant.ts]
import { streamText, convertToModelMessages } from 'ai'
import { createMistral } from '@ai-sdk/mistral'

const mistral = createMistral()

export default defineEventHandler(async (event) => {
  const { messages } = await readBody(event)

  return createAssistantResponse(streamText({
    ...await getAssistantDefaultOptions(event),
    model: mistral('mistral-large-latest'),
    messages: await convertToModelMessages(messages)
  }))
})
```

<tip>

Because you own the `streamText` call, provider specific constraints are solved where they belong.

</tip>

<warning>

Spread the defaults **first**. Options you set after the spread win (before are overwritten).

</warning>

<table>
<thead>
  <tr>
    <th>
      Util
    </th>
    
    <th>
      Role
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <a href="#getassistantdefaultoptions">
        <code>
          getAssistantDefaultOptions(event)
        </code>
      </a>
    </td>
    
    <td>
      Every <code>
        streamText
      </code>
      
       option the built-in endpoint uses: MCP tools, abort on disconnect, client cleanup, the documentation prompt, and the step and token limits.
    </td>
  </tr>
  
  <tr>
    <td>
      <a href="#getassistantsystemprompt">
        <code>
          getAssistantSystemPrompt(event)
        </code>
      </a>
    </td>
    
    <td>
      The default documentation-tuned prompt on its own, for when you want to extend it.
    </td>
  </tr>
  
  <tr>
    <td>
      <a href="#createassistantresponse">
        <code>
          createAssistantResponse(result)
        </code>
      </a>
    </td>
    
    <td>
      Wraps the result in the response format the assistant UI expects.
    </td>
  </tr>
</tbody>
</table>

#### `getAssistantDefaultOptions`

Returns real `streamText` options, so you can see and override every one of them:

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Default
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        tools
      </code>
    </td>
    
    <td>
      The MCP tools from <code>
        docus.assistant.mcpServer
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        abortSignal
      </code>
    </td>
    
    <td>
      Aborts generation when the client disconnects
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onEnd
      </code>
      
       / <code>
        onAbort
      </code>
    </td>
    
    <td>
      Closes the MCP client
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onError
      </code>
    </td>
    
    <td>
      Logs the provider error server-side, then closes the MCP client
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        instructions
      </code>
    </td>
    
    <td>
      <code>
        getAssistantSystemPrompt(event)
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        maxOutputTokens
      </code>
    </td>
    
    <td>
      <code>
        8000
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        maxRetries
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stopWhen
      </code>
    </td>
    
    <td>
      <code>
        isStepCount(10)
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prepareStep
      </code>
    </td>
    
    <td>
      Disables tools on the last step so the model answers instead of stopping mid tool-calling
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        experimental_transform
      </code>
    </td>
    
    <td>
      <code>
        smoothStream()
      </code>
    </td>
  </tr>
</tbody>
</table>

`model` and `messages` are not included, and neither are provider specific options like `providerOptions` or `temperature`, since they don't port across providers.

Override by setting the option after the spread:

```ts [server/api/assistant.ts]
return createAssistantResponse(streamText({
  ...await getAssistantDefaultOptions(event),
  model: mistral('mistral-large-latest'),
  // Wins over the default 8000
  maxOutputTokens: 4000,
  messages: await convertToModelMessages(messages)
}))
```

To add behaviour to a callback rather than replace it, keep a reference and call through to it, so MCP cleanup still runs:

```ts [server/api/assistant.ts]
const defaults = await getAssistantDefaultOptions(event)

return createAssistantResponse(streamText({
  ...defaults,
  model: mistral('mistral-large-latest'),
  messages: await convertToModelMessages(messages),
  onError: (payload) => {
    myErrorReporter(payload.error)
    // Still closes the MCP client
    defaults.onError(payload)
  }
}))
```

<warning>

`onEnd`, `onAbort` and `onError` close the MCP client. Replacing one without calling through to the original leaks a connection per request.

</warning>

#### `getAssistantSystemPrompt`

`getAssistantDefaultOptions` already sets this prompt as `instructions`, so you only need this util to extend it. It returns a plain string, so concatenate:

```ts [server/api/assistant.ts]
const defaults = await getAssistantDefaultOptions(event)

return createAssistantResponse(streamText({
  ...defaults,
  model: mistral('mistral-large-latest'),
  messages: await convertToModelMessages(messages),
  instructions: `${defaults.instructions}

**Extra instructions:**
- Always mention the minimum supported version
- Never speculate about the roadmap`
}))
```

Set `instructions` to your own string to replace the default entirely.

#### `createAssistantResponse`

Wraps a `streamText` result in the response format the assistant UI expects, so your route follows future stream format changes without being edited.

</steps>

## Programmatic Access

Use the `useAssistant` composable to control the assistant programmatically:

```vue
<script setup>
const { isEnabled, isOpen, open, close, toggle } = useAssistant()

function askQuestion() {
  // Open the assistant with a pre-filled question
  open('How do I configure the theme?', true)
}
</script>

<template>
  <UButton v-if="isEnabled" @click="askQuestion">
    Ask about themes
  </UButton>
</template>
```

## Composable API

<table>
<thead>
  <tr>
    <th>
      Property
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        isEnabled
      </code>
    </td>
    
    <td>
      <code>
        ComputedRef<boolean>
      </code>
    </td>
    
    <td>
      Whether the assistant is enabled (<code>
        docus.assistant.enabled
      </code>
      
      , or <code>
        AI_GATEWAY_API_KEY
      </code>
      
       / <code>
        VERCEL_OIDC_TOKEN
      </code>
      
       at build)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        isOpen
      </code>
    </td>
    
    <td>
      <code>
        Ref<boolean>
      </code>
    </td>
    
    <td>
      Whether the slideover is open
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        open(message?, clearPrevious?)
      </code>
    </td>
    
    <td>
      <code>
        Function
      </code>
    </td>
    
    <td>
      Open the assistant, optionally with a message
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        close()
      </code>
    </td>
    
    <td>
      <code>
        Function
      </code>
    </td>
    
    <td>
      Close the assistant slideover
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        toggle()
      </code>
    </td>
    
    <td>
      <code>
        Function
      </code>
    </td>
    
    <td>
      Toggle the assistant open/closed
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        clearMessages()
      </code>
    </td>
    
    <td>
      <code>
        Function
      </code>
    </td>
    
    <td>
      Clear the conversation history
    </td>
  </tr>
</tbody>
</table>


## Sitemap

See the full [sitemap](https://docus.dev/sitemap.md) for all pages.
