---
title: "Input, handler & messages"
description: "Zod arguments, handler return types, roles, and multi-message prompts."
canonical_url: "https://mcp-toolkit.nuxt.dev/prompts/input-handler-messages"
---
# Input, handler & messages

> Zod arguments, handler return types, roles, and multi-message prompts.

## Input Schema

Use Zod to define and validate prompt arguments:

```typescript [server/mcp/prompts/translate.ts]
import { z } from 'zod'
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  name: 'translate',
  inputSchema: {
    // Required string argument
    text: z.string().describe('Text to translate'),

    // Required enum argument
    targetLanguage: z.enum(['en', 'fr', 'es', 'de']).describe('Target language'),

    // Optional argument
    sourceLanguage: z.string().optional().describe('Source language (auto-detect if not provided)'),

    // Optional with default
    formality: z.enum(['formal', 'informal']).default('formal'),
  },
  handler: async ({ text, targetLanguage, sourceLanguage, formality }) => {
    // Implementation
  },
})
```

### Common Argument Types

<table>
<thead>
  <tr>
    <th>
      Zod Type
    </th>
    
    <th>
      Example
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        z.string()
      </code>
    </td>
    
    <td>
      <code>
        z.string().min(1)
      </code>
    </td>
    
    <td>
      String with validation
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        z.enum()
      </code>
    </td>
    
    <td>
      <code>
        z.enum(['a', 'b'])
      </code>
    </td>
    
    <td>
      Enumeration
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        z.optional()
      </code>
    </td>
    
    <td>
      <code>
        z.string().optional()
      </code>
    </td>
    
    <td>
      Optional field
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        z.default()
      </code>
    </td>
    
    <td>
      <code>
        z.string().default('value')
      </code>
    </td>
    
    <td>
      Field with default
    </td>
  </tr>
</tbody>
</table>

<callout color="info" icon="i-lucide-info">

**Note**: Prompt arguments must be strings. Use `z.string()` and convert to other types in your handler if needed.

</callout>

### Argument Autocompletion

Wrap a schema field with `completable()` to provide autocompletion suggestions when clients fill in prompt arguments:

```typescript [server/mcp/prompts/review-code.ts]
export default defineMcpPrompt({
  description: 'Review code for best practices',
  inputSchema: {
    language: completable(
      z.string().describe('Programming language'),
      value => ['typescript', 'javascript', 'python', 'rust', 'go']
        .filter(lang => lang.startsWith(value)),
    ),
  },
  handler: async ({ language }) => {
    return `Review the following ${language} code for best practices and potential issues.`
  },
})
```

The `completable` helper is auto-imported and re-exported from the MCP SDK. The callback receives the current input value and returns matching suggestions.

## Handler Function

The handler receives validated arguments (if `inputSchema` is provided) and returns a prompt result.

### Return Types

Handlers support two return types:

<code-group>

```typescript [String (recommended)]
// Return a string — auto-wrapped into a single user message
handler: async () => 'You are a helpful assistant.'

// With arguments
handler: async ({ topic }) => `Help me understand ${topic}.`
```

```typescript [Full GetPromptResult]
// Return the full MCP result for multi-message or assistant-role prompts
handler: async () => ({
  messages: [
    { role: 'user', content: { type: 'text', text: 'Review this code.' } },
    { role: 'assistant', content: { type: 'text', text: 'I will review it.' } },
  ],
})
```

</code-group>

<callout color="info" icon="i-lucide-info">

When returning a string, it is automatically wrapped into `{ messages: [{ role, content: { type: 'text', text: '...' } }] }` using the `role` option (defaults to `'user'`).

</callout>

### Handler Arguments

```typescript
// Without inputSchema — no arguments
handler: async () => 'Message text'

// With inputSchema — receives validated arguments
handler: async (args, extra) => {
  // args: Validated arguments matching inputSchema
  // extra: Request handler extra information
  return `Message with ${args.param}`
}
```

## Message Roles

Prompts can return messages with different roles:

<code-group>

```typescript [User Message]
return {
  messages: [{
    role: 'user',
    content: {
      type: 'text',
      text: 'User message with instructions',
    },
  }],
}
```

```typescript [Assistant Message]
return {
  messages: [{
    role: 'assistant',
    content: {
      type: 'text',
      text: 'Pre-filled assistant response',
    },
  }],
}
```

</code-group>

<callout color="info" icon="i-lucide-info">

**Note**: The MCP specification only supports `user` and `assistant` roles. To provide context or instructions, include them in the `user` message text.

</callout>

## Multiple Messages

Return multiple messages to create a conversation flow:

```typescript [server/mcp/prompts/conversation.ts]
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  name: 'conversation-starter',
  inputSchema: {
    topic: z.string().describe('Conversation topic'),
  },
  handler: async ({ topic }) => {
    return {
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `You are a helpful assistant. Let's discuss ${topic}.`,
          },
        },
        {
          role: 'assistant',
          content: {
            type: 'text',
            text: `I'd be happy to discuss ${topic} with you.`,
          },
        },
      ],
    }
  },
})
```


## Sitemap

See the full [sitemap](https://mcp-toolkit.nuxt.dev/sitemap.md) for all pages.
