Chapter 6: Prompts Template System

Haiyue
25min

Chapter 6: Prompts Template System

Learning Objectives

  1. Understand the role and design principles of Prompts
  2. Learn to create reusable prompt templates
  3. Master implementation of parameterized prompts
  4. Learn prompt version management and optimization
  5. Implement dynamic prompt generation system

1. Prompts Concept Overview

1.1 What are Prompts

Prompts are a mechanism in the MCP protocol for providing predefined prompt templates to AI models. Their main purposes are:

  • Provide structured prompt templates
  • Support parameterization and dynamic content generation
  • Enable prompt reuse and standardization
  • Simplify prompt construction for complex tasks

1.2 Advantages of Prompts

  1. Consistency - Ensure same tasks use same prompt format
  2. Maintainability - Centrally manage and update prompt templates
  3. Parameterization - Support dynamic parameter filling
  4. Reusability - Templates can be reused across multiple scenarios
  5. Version Control - Support prompt template versioning

2. Prompt Structure and Types

2.1 Prompt Basic Structure

interface Prompt {
  name: string;           // Prompt name
  description?: string;   // Prompt description
  arguments?: Array<{     // Parameter definitions
    name: string;
    description?: string;
    required?: boolean;
  }>;
}

interface PromptMessage {
  role: "user" | "assistant" | "system";
  content: {
    type: "text" | "image";
    text?: string;
    image?: string;  // base64 encoded
  };
}

interface GetPromptResult {
  messages: PromptMessage[];
  description?: string;
}

2.2 Prompt Type Classification

  1. System Prompts - Define AI role and behavior rules
  2. Task Prompts - Define specific task execution templates
  3. Conversation Prompts - Structured conversation flow templates
  4. Analysis Prompts - Data analysis and processing templates
  5. Creative Prompts - Content generation and creation templates

3. Basic Prompt System Implementation

3.1 Prompt Manager Basic Architecture

import { Server } from "@modelcontextprotocol/sdk/server/index.js";

interface PromptTemplate {
  name: string;
  description: string;
  arguments: PromptArgument[];
  template: string;
  version: string;
  category: string;
}

interface PromptArgument {
  name: string;
  description: string;
  type: "string" | "number" | "boolean" | "array" | "object";
  required: boolean;
  default?: any;
}

class PromptManager {
  private server: Server;
  private templates: Map<string, PromptTemplate> = new Map();

  constructor(server: Server) {
    this.server = server;
    this.setupPromptHandlers();
    this.initializeDefaultTemplates();
  }

  private setupPromptHandlers() {
    // List available prompts
    this.server.setRequestHandler("prompts/list", async () => {
      return {
        prompts: Array.from(this.templates.values()).map(template => ({
          name: template.name,
          description: template.description,
          arguments: template.arguments
        }))
      };
    });

    // Get specific prompt
    this.server.setRequestHandler("prompts/get", async (request) => {
      const { name, arguments: args } = request.params;
      return await this.getPrompt(name, args || {});
    });
  }

  async getPrompt(name: string, args: Record<string, any>): Promise<GetPromptResult> {
    const template = this.templates.get(name);
    if (!template) {
      throw new Error(`Prompt template not found: ${name}`);
    }

    // Validate arguments
    this.validateArguments(template, args);

    // Render template
    const renderedContent = this.renderTemplate(template.template, args);

    return {
      description: template.description,
      messages: [{
        role: "user",
        content: {
          type: "text",
          text: renderedContent
        }
      }]
    };
  }

  private validateArguments(template: PromptTemplate, args: Record<string, any>) {
    for (const arg of template.arguments) {
      if (arg.required && !(arg.name in args)) {
        throw new Error(`Required argument '${arg.name}' is missing`);
      }

      if (arg.name in args) {
        this.validateArgumentType(arg, args[arg.name]);
      }
    }
  }

  private validateArgumentType(arg: PromptArgument, value: any) {
    switch (arg.type) {
      case "string":
        if (typeof value !== "string") {
          throw new Error(`Argument '${arg.name}' must be a string`);
        }
        break;
      case "number":
        if (typeof value !== "number") {
          throw new Error(`Argument '${arg.name}' must be a number`);
        }
        break;
      case "boolean":
        if (typeof value !== "boolean") {
          throw new Error(`Argument '${arg.name}' must be a boolean`);
        }
        break;
      case "array":
        if (!Array.isArray(value)) {
          throw new Error(`Argument '${arg.name}' must be an array`);
        }
        break;
    }
  }

  private renderTemplate(template: string, args: Record<string, any>): string {
    let rendered = template;

    // Simple template rendering - replace {{variableName}} format variables
    for (const [key, value] of Object.entries(args)) {
      const regex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, 'g');
      rendered = rendered.replace(regex, String(value));
    }

    return rendered;
  }

  private initializeDefaultTemplates() {
    // Initialize some default templates
    this.addTemplate({
      name: "code_review",
      description: "Code review prompt template",
      version: "1.0.0",
      category: "development",
      arguments: [
        {
          name: "code",
          description: "Code to review",
          type: "string",
          required: true
        },
        {
          name: "language",
          description: "Programming language",
          type: "string",
          required: true
        }
      ],
      template: `Please review the following {{language}} code:

\`\`\`{{language}}
{{code}}
\`\`\`

Please provide feedback on:
1. Code quality and best practices
2. Potential bugs or issues
3. Performance considerations
4. Suggestions for improvement`
    });
  }

  addTemplate(template: PromptTemplate) {
    this.templates.set(template.name, template);
  }
}

3.2 Advanced Template Rendering Engine

import Handlebars from "handlebars";

class AdvancedTemplateRenderer {
  private handlebars: typeof Handlebars;

  constructor() {
    this.handlebars = Handlebars.create();
    this.registerHelpers();
  }

  private registerHelpers() {
    // Conditional helper
    this.handlebars.registerHelper("if_eq", function(a, b, options) {
      return a === b ? options.fn(this) : options.inverse(this);
    });

    // Loop index helper
    this.handlebars.registerHelper("index_plus_one", function(index) {
      return index + 1;
    });

    // Date formatting helper
    this.handlebars.registerHelper("format_date", function(date, format) {
      return new Date(date).toLocaleDateString();
    });

    // Array length helper
    this.handlebars.registerHelper("length", function(array) {
      return Array.isArray(array) ? array.length : 0;
    });

    // JSON serialization helper
    this.handlebars.registerHelper("json", function(obj) {
      return JSON.stringify(obj, null, 2);
    });
  }

  render(template: string, context: Record<string, any>): string {
    const compiledTemplate = this.handlebars.compile(template);
    return compiledTemplate(context);
  }
}

// Prompt manager using advanced renderer
class EnhancedPromptManager extends PromptManager {
  private renderer: AdvancedTemplateRenderer;

  constructor(server: Server) {
    super(server);
    this.renderer = new AdvancedTemplateRenderer();
  }

  protected renderTemplate(template: string, args: Record<string, any>): string {
    return this.renderer.render(template, args);
  }
}

4. Complex Prompt Template Examples

4.1 Code Generation Template

const codeGenerationTemplate: PromptTemplate = {
  name: "code_generation",
  description: "Generate code based on specifications",
  version: "1.0.0",
  category: "development",
  arguments: [
    {
      name: "language",
      description: "Programming language",
      type: "string",
      required: true
    },
    {
      name: "functionality",
      description: "Description of required functionality",
      type: "string",
      required: true
    },
    {
      name: "framework",
      description: "Framework or library to use",
      type: "string",
      required: false
    },
    {
      name: "constraints",
      description: "Specific constraints or requirements",
      type: "array",
      required: false,
      default: []
    }
  ],
  template: `Generate {{language}} code for the following functionality:

**Functionality**: {{functionality}}

{{#if framework}}
**Framework**: {{framework}}
{{/if}}

{{#if constraints}}
**Constraints**:
{{#each constraints}}
- {{this}}
{{/each}}
{{/if}}

Please provide:
1. Clean, well-commented code
2. Error handling where appropriate
3. Brief explanation of the approach
4. Usage examples

Code:
`
};

4.2 Data Analysis Template

const dataAnalysisTemplate: PromptTemplate = {
  name: "data_analysis",
  description: "Analyze data and provide insights",
  version: "1.0.0",
  category: "analysis",
  arguments: [
    {
      name: "data",
      description: "Data to analyze (JSON format)",
      type: "string",
      required: true
    },
    {
      name: "analysis_type",
      description: "Type of analysis to perform",
      type: "string",
      required: true
    },
    {
      name: "metrics",
      description: "Specific metrics to calculate",
      type: "array",
      required: false,
      default: []
    }
  ],
  template: `Please analyze the following data:

\`\`\`json
{{data}}
\`\`\`

**Analysis Type**: {{analysis_type}}

{{#if metrics}}
**Focus on these metrics**:
{{#each metrics}}
- {{this}}
{{/each}}
{{/if}}

Please provide:
1. Key findings and patterns
2. Statistical summary
3. Visualizations suggestions
4. Actionable insights
5. Recommendations

Analysis:
`
};

4.3 Multi-turn Conversation Template

const conversationTemplate: PromptTemplate = {
  name: "conversation_flow",
  description: "Structure multi-turn conversation",
  version: "1.0.0",
  category: "conversation",
  arguments: [
    {
      name: "role",
      description: "AI assistant role",
      type: "string",
      required: true
    },
    {
      name: "context",
      description: "Conversation context",
      type: "string",
      required: true
    },
    {
      name: "previous_messages",
      description: "Previous conversation messages",
      type: "array",
      required: false,
      default: []
    }
  ],
  template: `You are a {{role}}.

**Context**: {{context}}

{{#if previous_messages}}
**Previous conversation**:
{{#each previous_messages}}
{{#if_eq role "user"}}
User: {{content}}
{{else}}
Assistant: {{content}}
{{/if_eq}}
{{/each}}
{{/if}}

Please continue the conversation naturally, maintaining consistency with your role and the established context.
`
};

5. Dynamic Prompt System

5.1 Conditional Prompt Generation

interface ConditionalPrompt {
  name: string;
  conditions: PromptCondition[];
  templates: Record<string, string>;
  default_template: string;
}

interface PromptCondition {
  field: string;
  operator: "eq" | "neq" | "gt" | "lt" | "contains" | "in";
  value: any;
  template_key: string;
}

class ConditionalPromptManager {
  private conditionalPrompts: Map<string, ConditionalPrompt> = new Map();

  addConditionalPrompt(prompt: ConditionalPrompt) {
    this.conditionalPrompts.set(prompt.name, prompt);
  }

  generatePrompt(name: string, args: Record<string, any>): string {
    const conditionalPrompt = this.conditionalPrompts.get(name);
    if (!conditionalPrompt) {
      throw new Error(`Conditional prompt not found: ${name}`);
    }

    // Evaluate conditions
    for (const condition of conditionalPrompt.conditions) {
      if (this.evaluateCondition(condition, args)) {
        return conditionalPrompt.templates[condition.template_key];
      }
    }

    return conditionalPrompt.default_template;
  }

  private evaluateCondition(condition: PromptCondition, args: Record<string, any>): boolean {
    const fieldValue = args[condition.field];

    switch (condition.operator) {
      case "eq":
        return fieldValue === condition.value;
      case "neq":
        return fieldValue !== condition.value;
      case "gt":
        return fieldValue > condition.value;
      case "lt":
        return fieldValue < condition.value;
      case "contains":
        return String(fieldValue).includes(String(condition.value));
      case "in":
        return Array.isArray(condition.value) && condition.value.includes(fieldValue);
      default:
        return false;
    }
  }
}

5.2 Context-Aware Prompt System

interface ContextAwarePrompt {
  name: string;
  base_template: string;
  context_modifiers: ContextModifier[];
}

interface ContextModifier {
  context_type: string;
  context_value: any;
  modification: PromptModification;
}

interface PromptModification {
  type: "prepend" | "append" | "replace" | "insert";
  position?: string;
  content: string;
}

class ContextAwarePromptManager {
  private contextPrompts: Map<string, ContextAwarePrompt> = new Map();
  private currentContext: Map<string, any> = new Map();

  setContext(key: string, value: any) {
    this.currentContext.set(key, value);
  }

  generateContextualPrompt(name: string, args: Record<string, any>): string {
    const contextPrompt = this.contextPrompts.get(name);
    if (!contextPrompt) {
      throw new Error(`Context-aware prompt not found: ${name}`);
    }

    let prompt = contextPrompt.base_template;

    // Apply context modifiers
    for (const modifier of contextPrompt.context_modifiers) {
      if (this.shouldApplyModifier(modifier)) {
        prompt = this.applyModification(prompt, modifier.modification);
      }
    }

    return prompt;
  }

  private shouldApplyModifier(modifier: ContextModifier): boolean {
    const contextValue = this.currentContext.get(modifier.context_type);
    return contextValue === modifier.context_value;
  }

  private applyModification(prompt: string, modification: PromptModification): string {
    switch (modification.type) {
      case "prepend":
        return modification.content + "\n\n" + prompt;
      case "append":
        return prompt + "\n\n" + modification.content;
      case "replace":
        return modification.content;
      case "insert":
        if (modification.position) {
          return prompt.replace(modification.position, modification.content);
        }
        return prompt;
      default:
        return prompt;
    }
  }
}

6. Prompt Version Management and Optimization

6.1 Version Control System

interface PromptVersion {
  version: string;
  template: string;
  changelog: string;
  deprecated: boolean;
  created_at: Date;
}

class PromptVersionManager {
  private versions: Map<string, Map<string, PromptVersion>> = new Map();

  addVersion(promptName: string, version: PromptVersion) {
    if (!this.versions.has(promptName)) {
      this.versions.set(promptName, new Map());
    }

    const promptVersions = this.versions.get(promptName)!;
    promptVersions.set(version.version, version);
  }

  getVersion(promptName: string, version: string): PromptVersion | undefined {
    return this.versions.get(promptName)?.get(version);
  }

  getLatestVersion(promptName: string): PromptVersion | undefined {
    const promptVersions = this.versions.get(promptName);
    if (!promptVersions) return undefined;

    const versions = Array.from(promptVersions.values())
      .filter(v => !v.deprecated)
      .sort((a, b) => b.created_at.getTime() - a.created_at.getTime());

    return versions[0];
  }

  deprecateVersion(promptName: string, version: string) {
    const promptVersion = this.getVersion(promptName, version);
    if (promptVersion) {
      promptVersion.deprecated = true;
    }
  }

  listVersions(promptName: string): PromptVersion[] {
    const promptVersions = this.versions.get(promptName);
    return promptVersions ? Array.from(promptVersions.values()) : [];
  }
}

6.2 A/B Testing System

interface PromptVariant {
  name: string;
  template: string;
  weight: number;  // 0-100
  metrics: PromptMetrics;
}

interface PromptMetrics {
  usage_count: number;
  success_rate: number;
  average_response_time: number;
  user_satisfaction: number;
}

class PromptABTester {
  private variants: Map<string, PromptVariant[]> = new Map();
  private random = Math.random;

  addVariant(promptName: string, variant: PromptVariant) {
    if (!this.variants.has(promptName)) {
      this.variants.set(promptName, []);
    }

    this.variants.get(promptName)!.push(variant);
  }

  selectVariant(promptName: string): PromptVariant | undefined {
    const variants = this.variants.get(promptName);
    if (!variants || variants.length === 0) return undefined;

    const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);
    const randomValue = this.random() * totalWeight;

    let currentWeight = 0;
    for (const variant of variants) {
      currentWeight += variant.weight;
      if (randomValue <= currentWeight) {
        variant.metrics.usage_count++;
        return variant;
      }
    }

    return variants[0];
  }

  recordSuccess(promptName: string, variantName: string) {
    const variants = this.variants.get(promptName);
    const variant = variants?.find(v => v.name === variantName);
    if (variant) {
      variant.metrics.success_rate = this.calculateSuccessRate(variant);
    }
  }

  private calculateSuccessRate(variant: PromptVariant): number {
    // Implement success rate calculation logic
    return variant.metrics.success_rate; // Simplified implementation
  }

  getBestPerformingVariant(promptName: string): PromptVariant | undefined {
    const variants = this.variants.get(promptName);
    if (!variants) return undefined;

    return variants.reduce((best, current) => {
      const bestScore = this.calculateVariantScore(best);
      const currentScore = this.calculateVariantScore(current);
      return currentScore > bestScore ? current : best;
    });
  }

  private calculateVariantScore(variant: PromptVariant): number {
    const { success_rate, user_satisfaction, usage_count } = variant.metrics;

    // Weighted scoring algorithm
    return (success_rate * 0.4) +
           (user_satisfaction * 0.4) +
           (Math.log(usage_count + 1) * 0.2);
  }
}

7. Complete Prompt Server Implementation

7.1 Enterprise Prompt Server

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

class EnterprisePromptServer {
  private server: Server;
  private promptManager: EnhancedPromptManager;
  private versionManager: PromptVersionManager;
  private abTester: PromptABTester;
  private conditionalManager: ConditionalPromptManager;

  constructor() {
    this.server = new Server(
      {
        name: "enterprise-prompt-server",
        version: "1.0.0"
      },
      {
        capabilities: {
          prompts: {}
        }
      }
    );

    this.promptManager = new EnhancedPromptManager(this.server);
    this.versionManager = new PromptVersionManager();
    this.abTester = new PromptABTester();
    this.conditionalManager = new ConditionalPromptManager();

    this.setupAdvancedHandlers();
    this.loadPromptLibrary();
  }

  private setupAdvancedHandlers() {
    // Get specific version of prompt
    this.server.setRequestHandler("prompts/get_version", async (request) => {
      const { name, version, arguments: args } = request.params;

      const promptVersion = this.versionManager.getVersion(name, version);
      if (!promptVersion) {
        throw new Error(`Prompt version not found: ${name}@${version}`);
      }

      return {
        description: `${name} (version ${version})`,
        messages: [{
          role: "user",
          content: {
            type: "text",
            text: this.renderTemplate(promptVersion.template, args || {})
          }
        }]
      };
    });

    // A/B testing variant selection
    this.server.setRequestHandler("prompts/get_variant", async (request) => {
      const { name, arguments: args } = request.params;

      const variant = this.abTester.selectVariant(name);
      if (!variant) {
        throw new Error(`No variants available for prompt: ${name}`);
      }

      return {
        description: `${name} (variant: ${variant.name})`,
        messages: [{
          role: "user",
          content: {
            type: "text",
            text: this.renderTemplate(variant.template, args || {})
          }
        }],
        metadata: {
          variant: variant.name,
          usage_count: variant.metrics.usage_count
        }
      };
    });

    // Conditional prompt generation
    this.server.setRequestHandler("prompts/get_conditional", async (request) => {
      const { name, arguments: args } = request.params;

      const template = this.conditionalManager.generatePrompt(name, args || {});

      return {
        description: `${name} (conditional)`,
        messages: [{
          role: "user",
          content: {
            type: "text",
            text: this.renderTemplate(template, args || {})
          }
        }]
      };
    });
  }

  private loadPromptLibrary() {
    // Load prompt template library
    const templates = [
      codeGenerationTemplate,
      dataAnalysisTemplate,
      conversationTemplate,
      // Add more templates...
    ];

    templates.forEach(template => {
      this.promptManager.addTemplate(template);

      // Add version information
      this.versionManager.addVersion(template.name, {
        version: template.version,
        template: template.template,
        changelog: `Initial version of ${template.name}`,
        deprecated: false,
        created_at: new Date()
      });
    });
  }

  private renderTemplate(template: string, args: Record<string, any>): string {
    return this.promptManager.renderTemplate(template, args);
  }

  async start() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error("Enterprise Prompt Server running on stdio");
  }
}

// Start server
const server = new EnterprisePromptServer();
server.start().catch(console.error);

8. Best Practices

8.1 Prompt Design Principles

  1. Clarity - Clear and explicit instructions, avoid ambiguity
  2. Structure - Use clear formatting and sections
  3. Context - Provide sufficient background information
  4. Examples - Include input/output examples
  5. Constraints - Clearly specify output format and limitations

8.2 Template Organization Strategy

  1. Categorization - Organize by functional domain
  2. Naming Convention - Use consistent naming conventions
  3. Parameter Standardization - Unify parameter naming and types
  4. Complete Documentation - Detailed template documentation
  5. Test Coverage - Comprehensive template test cases

8.3 Performance Optimization

  1. Template Caching - Cache compiled templates
  2. Lazy Loading - Load template content on demand
  3. Compression - Compress large template content
  4. Batch Operations - Support batch template processing
  5. Async Rendering - Asynchronous template rendering

Summary

Through this chapter, we have mastered:

  • Basic concepts and architectural design of Prompts
  • How to implement flexible template systems
  • Dynamic and conditional prompt generation
  • Version management and A/B testing mechanisms
  • Complete enterprise Prompt Server implementation

The Prompt system provides powerful prompt template capabilities for MCP Server, enabling AI models to receive structured, consistent instructions, serving as an important component for building high-quality AI applications.