Prompts are reusable message templates that can be used by AI assistants. They can include dynamic arguments and return pre-formatted messages.
You can omit name and title - they will be automatically generated from the filename:
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.
Create a prompt without arguments:
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 {
messages: [{
role: 'user',
content: {
type: 'text',
text: `Good ${timeOfDay}! How can I help you today?`,
},
}],
}
},
})
Create a prompt that accepts arguments:
import { z } from 'zod'
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 {
messages: [{
role: 'user',
content: {
type: 'text',
text: `Summary (${maxWords} words): ${summary}${words.length > maxWords ? '...' : ''}`,
},
}],
}
},
})
A prompt definition consists of:
export default defineMcpPrompt({
name: 'prompt-name', // Unique identifier
handler: async () => { // Handler function
return { messages: [...] }
},
})
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 { messages: [...] }
},
})
Use Zod to define and validate prompt arguments:
import { z } from 'zod'
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
},
})
| 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.The handler receives validated arguments (if inputSchema is provided) and returns messages:
// Prompt without arguments
handler: async () => {
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: 'Message text',
},
}],
}
}
// Prompt with arguments
handler: async (args, extra) => {
// args: Validated arguments matching inputSchema
// extra: Request handler extra information
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: 'Message text',
},
}],
}
}
Prompts can return messages with different roles:
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: 'User message',
},
}],
}
return {
messages: [{
role: 'assistant',
content: {
type: 'text',
text: 'Assistant message',
},
}],
}
return {
messages: [{
role: 'system',
content: {
type: 'text',
text: 'System message',
},
}],
}
Return multiple messages in sequence:
export default defineMcpPrompt({
name: 'conversation-starter',
inputSchema: {
topic: z.string().describe('Conversation topic'),
},
handler: async ({ topic }) => {
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: 'You are a helpful assistant.',
},
},
{
role: 'user',
content: {
type: 'text',
text: `Let's discuss ${topic}.`,
},
},
],
}
},
})
import { z } from 'zod'
export default defineMcpPrompt({
name: 'code-review',
title: 'Code Review',
description: 'Generate a code review prompt',
inputSchema: {
code: z.string().describe('Code to review'),
language: z.string().describe('Programming language'),
focus: z.enum(['performance', 'security', 'style', 'all']).default('all'),
},
handler: async ({ code, language, focus }) => {
const focusText = focus === 'all'
? 'performance, security, and style'
: focus
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: `Please review this ${language} code focusing on ${focusText}:\n\n\`\`\`${language}\n${code}\n\`\`\``,
},
}],
}
},
})
import { z } from 'zod'
export default defineMcpPrompt({
name: 'documentation',
title: 'Generate Documentation',
description: 'Create documentation for code',
inputSchema: {
code: z.string().describe('Code to document'),
style: z.enum(['jsdoc', 'tsdoc', 'markdown']).default('jsdoc'),
},
handler: async ({ code, style }) => {
const prompt = style === 'markdown'
? `Generate markdown documentation for this code:\n\n\`\`\`\n${code}\n\`\`\``
: `Generate ${style.toUpperCase()} documentation for this code:\n\n\`\`\`\n${code}\n\`\`\``
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: prompt,
},
}],
}
},
})
import { z } from 'zod'
export default defineMcpPrompt({
name: 'email-template',
title: 'Email Template',
description: 'Generate email from template',
inputSchema: {
recipient: z.string().describe('Recipient name'),
subject: z.string().describe('Email subject'),
tone: z.enum(['formal', 'casual', 'friendly']).default('friendly'),
},
handler: async ({ recipient, subject, tone }) => {
const greeting = tone === 'formal'
? 'Dear'
: tone === 'casual'
? 'Hi'
: 'Hello'
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: `Write an email:\n\nTo: ${recipient}\nSubject: ${subject}\nTone: ${tone}\n\nGreeting: ${greeting}`,
},
}],
}
},
})
Organize your prompts in the server/mcp/prompts/ directory:
server/
└── mcp/
└── prompts/
├── greeting.ts
├── summarize.ts
├── translate.ts
├── code-review.ts
└── documentation.ts
Each file should export a default prompt definition.
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
}