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.

Auto-Generated Name and Title

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

server/mcp/prompts/greeting.ts
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:

server/mcp/prompts/greeting.ts
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?`,
        },
      }],
    }
  },
})

Prompt with Arguments

Create a prompt that accepts arguments:

server/mcp/prompts/summarize.ts
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 ? '...' : ''}`,
        },
      }],
    }
  },
})

Prompt Structure

A prompt definition consists of:

export default defineMcpPrompt({
  name: 'prompt-name',  // Unique identifier
  handler: async () => { // Handler function
    return { messages: [...] }
  },
})

Input Schema

Use Zod to define and validate prompt arguments:

server/mcp/prompts/translate.ts
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
  },
})

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.

Handler Function

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',
      },
    }],
  }
}

Message Roles

Prompts can return messages with different roles:

return {
  messages: [{
    role: 'user',
    content: {
      type: 'text',
      text: 'User message',
    },
  }],
}

Multiple Messages

Return multiple messages in sequence:

server/mcp/prompts/conversation.ts
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}.`,
          },
        },
      ],
    }
  },
})

Advanced Examples

Code Review Prompt

server/mcp/prompts/code-review.ts
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\`\`\``,
        },
      }],
    }
  },
})

Documentation Prompt

server/mcp/prompts/documentation.ts
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,
        },
      }],
    }
  },
})

Template-Based Prompt

server/mcp/prompts/email.ts
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}`,
        },
      }],
    }
  },
})

File Organization

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.

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. Use descriptive names: Make prompt names clear and specific
  2. Provide descriptions: Help users understand what the prompt does
  3. Validate arguments: Use Zod schemas to ensure valid input
  4. Handle errors: Return appropriate error messages when needed
  5. Keep prompts focused: Each prompt should have a single, clear purpose

Next Steps

  • Tools - Create tools to perform actions
  • Resources - Create resources to expose data
  • Handlers - Create custom MCP endpoints
  • Examples - See more prompt examples