Core Concepts

Prompts

Create reusable prompts for AI assistants with optional arguments.

What are Prompts?

Prompts are reusable message templates that can be used by AI assistants. They can include dynamic arguments and return pre-formatted messages.

Prompt
Create a new MCP prompt in my Nuxt app using @nuxtjs/mcp-toolkit.

- Create a file in server/mcp/prompts/ (e.g. server/mcp/prompts/review-code.ts)
- Use defineMcpPrompt (auto-imported) with a description and handler
- The handler can return a string (auto-wrapped as a user message) or a full GetPromptResult with messages array
- Define arguments with `import { z } from 'zod'` in inputSchema (prompt arguments must be strings)
- Use the role option ('user' or 'assistant') to control the default role for string returns
- Use completable() to provide autocompletion suggestions for arguments
- Return multiple messages to create a conversation flow
- Name and title are auto-generated from the filename
- Prompts appear in Cursor and VS Code when typing / in the chat

Docs: https://mcp-toolkit.nuxt.dev/core-concepts/prompts

Why Use Prompts?

MCP prompts offer several advantages over ad-hoc instructions:

Reusability

Define once, use everywhere. Share prompts across your team for consistent AI interactions.

Standardization

Ensure consistent formatting and context for specific tasks like code reviews or documentation.

Customization

Use arguments to adapt prompts to different contexts while maintaining structure.

IDE Integration

Prompts appear in Cursor, VS Code, and Visual Studio for easy access during development.

IDE Integration

MCP prompts integrate seamlessly with modern development environments. When your MCP server is connected, prompts become available directly in your IDE.

Using Prompts in Cursor / VS Code

  1. Type /: In the chat, type / to see all available MCP prompts
  2. Select a prompt: Choose from the list (e.g., local-mcp/setup-mcp-server)
  3. Fill Arguments: For prompt templates, a dialog will appear to fill in the required arguments

Auto-Generated Name and Title

You can omit name and title - they will be automatically generated from the filename:

server/mcp/prompts/greeting.ts
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  // name and title are auto-generated from filename:
  // name: 'greeting'
  // title: 'Greeting'
  description: 'Generate a personalized greeting message',
  handler: async () => {
    // ...
  },
})

The filename greeting.ts automatically becomes:

  • name: greeting (kebab-case)
  • title: Greeting (title case)

You can still provide name or title explicitly to override the auto-generated values.

Simple Prompt (No Arguments)

Create a prompt without arguments. Handlers can return a simple string — it will be automatically wrapped into a single user message:

server/mcp/prompts/greeting.ts
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  name: 'greeting',
  title: 'Greeting',
  description: 'Generate a personalized greeting message',
  handler: async () => {
    const hour = new Date().getHours()
    const timeOfDay = hour < 12 ? 'morning' : hour < 18 ? 'afternoon' : 'evening'

    return `Good ${timeOfDay}! How can I help you today?`
  },
})

Default Role

When a handler returns a string, it is wrapped with the user role by default. Use the role option to change this:

server/mcp/prompts/code-reviewer.ts
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  role: 'assistant',
  description: 'Code review assistant persona',
  handler: async () => 'I am a code review assistant. Share your code and I will review it for best practices.',
})
The role option only affects string returns. When returning a full GetPromptResult, define roles directly in the messages array.

Prompt with Arguments

Create a prompt that accepts arguments:

server/mcp/prompts/summarize.ts
import { z } from 'zod'
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  name: 'summarize',
  title: 'Text Summarizer',
  description: 'Summarize any text content',
  inputSchema: {
    text: z.string().describe('The text to summarize'),
    maxLength: z.string().optional().describe('Maximum length of summary in words'),
  },
  handler: async ({ text, maxLength }) => {
    const words = text.split(/\s+/)
    const maxWords = maxLength ? Number.parseInt(maxLength) : Math.ceil(words.length * 0.3)
    const summary = words.slice(0, maxWords).join(' ')

    return `Summary (${maxWords} words): ${summary}${words.length > maxWords ? '...' : ''}`
  },
})

Prompt Structure

A prompt definition consists of:

import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  name: 'prompt-name',  // Unique identifier
  handler: async () => 'Your prompt text here',
})

Input Schema

Use Zod to define and validate prompt arguments:

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

Zod TypeExampleDescription
z.string()z.string().min(1)String with validation
z.enum()z.enum(['a', 'b'])Enumeration
z.optional()z.string().optional()Optional field
z.default()z.string().default('value')Field with default
Note: Prompt arguments must be strings. Use z.string() and convert to other types in your handler if needed.

Argument Autocompletion

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

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:

// 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}.`
When returning a string, it is automatically wrapped into { messages: [{ role, content: { type: 'text', text: '...' } }] } using the role option (defaults to 'user').

Handler Arguments

// 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:

return {
  messages: [{
    role: 'user',
    content: {
      type: 'text',
      text: 'User message with instructions',
    },
  }],
}
Note: The MCP specification only supports user and assistant roles. To provide context or instructions, include them in the user message text.

Multiple Messages

Return multiple messages to create a conversation flow:

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.`,
          },
        },
      ],
    }
  },
})

Use Cases

Prompts are particularly useful for:

1. Setup and Onboarding

Help new developers or AI assistants understand how to work with your codebase:

server/mcp/prompts/setup-guide.ts
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  description: 'Provide complete setup instructions for this project',
  handler: async () => `You are setting up this Nuxt project. Here's what you need to know:

1. Install dependencies: \`pnpm install\`
2. Start dev server: \`pnpm dev\`
3. Project structure follows Nuxt conventions
4. MCP tools are available in server/mcp/

Ask me what you'd like to build!`,
})

2. Code Review Standards

Ensure consistent code review criteria:

server/mcp/prompts/review-standards.ts
import { z } from 'zod'
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  description: 'Apply team code review standards',
  inputSchema: {
    focus: z.enum(['security', 'performance', 'maintainability', 'all']).default('all'),
  },
  handler: async ({ focus }) => `You are a code reviewer following our team standards. Focus on: ${focus}.

Review the code I provide, checking for best practices and potential issues.`,
})

3. Documentation Generation

Standardize documentation format:

server/mcp/prompts/generate-docs.ts
import { z } from 'zod'
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  description: 'Generate documentation in team format',
  inputSchema: {
    type: z.enum(['api', 'component', 'function']).describe('What to document'),
  },
  handler: async ({ type }) => {
    const templates = {
      api: 'Document this API endpoint with: endpoint, method, parameters, response format, and examples.',
      component: 'Document this Vue component with: props, emits, slots, and usage examples.',
      function: 'Document this function with: parameters, return value, and usage examples.',
    }

    return templates[type]
  },
})

4. Troubleshooting Workflows

Guide debugging for common issues:

server/mcp/prompts/debug-helper.ts
import { z } from 'zod'
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  description: 'Help debug common issues',
  inputSchema: {
    area: z.enum(['api', 'auth', 'database', 'frontend']).describe('Area of the issue'),
  },
  handler: async ({ area }) => `You are debugging a ${area} issue. Ask clarifying questions and suggest diagnostic steps.`,
})

Groups and Tags

Organize your prompts with group and tags for categorization. These fields work the same way as for tools.

server/mcp/prompts/onboarding/setup-guide.ts
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'

export default defineMcpPrompt({
  tags: ['getting-started'],
  description: 'Help new developers set up the project',
  handler: async () => 'You are setting up this project...',
})

Placing the file in prompts/onboarding/ auto-infers group: 'onboarding'.

Prompt group and tags are stored on the definition objects but are not yet included in prompts/list protocol responses. This will be supported when SEP-1300 is adopted by the MCP SDK.

File Organization

Organize your prompts in the server/mcp/prompts/ directory. Both flat and nested layouts are supported:

server/
└── mcp/
    └── prompts/
        ├── greeting.ts
        ├── summarize.ts
        ├── onboarding/
        │   └── setup-guide.ts
        └── debugging/
            └── troubleshoot.ts

Each file should export a default prompt definition. Subdirectories automatically set the group.

Type Safety

The module provides full TypeScript type inference:

// Argument types are inferred from inputSchema
handler: async ({ text, maxLength }) => {
  // text is typed as string
  // maxLength is typed as string | undefined
}

Best Practices

1. Design for AI Understanding

Write prompts that give the AI clear context and expectations:

// Good: Clear context and instructions
handler: async ({ code }) =>
  `You are a senior developer reviewing code for a Nuxt application.

Review this code for Vue 3 best practices:\n\n${code}`

// Less effective: Vague instructions
handler: async ({ code }) => code

2. Use Descriptive Arguments

Always use .describe() on Zod fields to help both users and AI understand what's expected:

inputSchema: {
  // Good: Clear descriptions
  language: z.enum(['typescript', 'javascript']).describe('Programming language of the code'),
  strict: z.boolean().default(true).describe('Whether to enforce strict TypeScript rules'),

  // Less helpful: No descriptions
  lang: z.string(),
  s: z.boolean(),
}

3. Use Conversation Flow

Use user and assistant messages to guide the AI:

// Effective: User provides context, assistant acknowledges
messages: [
  { role: 'user', content: { type: 'text', text: 'You are an expert in accessibility. Review this HTML for a11y issues.' } },
  { role: 'assistant', content: { type: 'text', text: 'I\'ll analyze the HTML for accessibility issues.' } },
]

4. Keep Prompts Focused

Each prompt should have a single, clear purpose. Create multiple prompts instead of one complex one:

// Good: Separate focused prompts
// server/mcp/prompts/review-security.ts
// server/mcp/prompts/review-performance.ts
// server/mcp/prompts/review-style.ts

// Less maintainable: One complex prompt trying to do everything

5. Provide Default Values

Use .default() for optional arguments to improve usability:

inputSchema: {
  format: z.enum(['brief', 'detailed']).default('detailed').describe('Output format'),
  language: z.string().default('en').describe('Response language'),
}

6. Include Examples in Complex Prompts

For prompts that need specific output formats, include examples:

handler: async () => `Generate a commit message following this format:

type(scope): description

Example:
feat(auth): add OAuth2 login support

Types: feat, fix, docs, style, refactor, test, chore`

Conditional Registration

You can control whether a prompt is visible to clients using the enabled guard:

server/mcp/prompts/admin-prompt.ts
export default defineMcpPrompt({
  name: 'admin-prompt',
  description: 'Admin-only prompt',
  enabled: event => event.context.user?.role === 'admin',
  handler: async () => 'Admin instructions...',
})
See the Dynamic Definitions guide for detailed documentation on auth-based filtering.

Next Steps

Copyright © 2026