Prompts
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.
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
Standardization
Customization
IDE Integration
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
- Type
/: In the chat, type/to see all available MCP prompts - Select a prompt: Choose from the list (e.g.,
local-mcp/setup-mcp-server) - 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:
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:
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:
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.',
})
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:
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',
})
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'
export default defineMcpPrompt({
name: 'prompt-name',
role: 'assistant', // Role for string returns (default: 'user')
handler: async () => 'I am an assistant persona.',
})
import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server'
export default defineMcpPrompt({
name: 'prompt-name',
title: 'Prompt Title', // Human-readable title
description: 'Description', // What the prompt does
inputSchema: { ... }, // Zod schema for arguments
handler: async (args) => { // Handler with arguments
return `Prompt text with ${args.param}`
},
})
Input Schema
Use Zod to define and validate prompt arguments:
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 Type | Example | Description |
|---|---|---|
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 |
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:
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}.`
// 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.' } },
],
})
{ 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',
},
}],
}
return {
messages: [{
role: 'assistant',
content: {
type: 'text',
text: 'Pre-filled assistant response',
},
}],
}
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:
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:
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:
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:
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:
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.
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'.
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:
export default defineMcpPrompt({
name: 'admin-prompt',
description: 'Admin-only prompt',
enabled: event => event.context.user?.role === 'admin',
handler: async () => 'Admin instructions...',
})
Next Steps
- Prompt Examples - See advanced prompt examples
- Tools - Create tools to perform actions
- Resources - Create resources to expose data
- Handlers - Create custom MCP endpoints
- Dynamic Definitions - Conditionally register definitions