Implementing Prompts
Prompts are reusable interaction templates that help structure conversations between users and LLMs. They provide context, instructions, and can include dynamic content from resources.
Prompt Fundamentals
Prompts in MCP serve as templates that can be invoked by LLMs to generate structured interactions. They're particularly useful for complex workflows, analysis tasks, or any scenario where you want to provide consistent context and instructions.
Basic Prompt Structure
// Create a simple prompt
prompt := mcp.NewPrompt("code_review",
mcp.WithPromptDescription("Review code for best practices and issues"),
mcp.WithPromptArgument("code",
mcp.Required(),
mcp.Description("The code to review"),
),
mcp.WithPromptArgument("language",
mcp.Description("Programming language"),
mcp.Default("auto-detect"),
),
)
Prompt Templates
Basic Code Review Prompt
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
s := server.NewMCPServer("Code Assistant", "1.0.0",
server.WithPromptCapabilities(true),
)
// Code review prompt
codeReviewPrompt := mcp.NewPrompt("code_review",
mcp.WithPromptDescription("Review code for best practices, bugs, and improvements"),
mcp.WithPromptArgument("code",
mcp.Required(),
mcp.Description("The code to review"),
),
mcp.WithPromptArgument("language",
mcp.Description("Programming language (auto-detected if not specified)"),
),
mcp.WithPromptArgument("focus",
mcp.Description("Specific areas to focus on"),
mcp.Enum("security", "performance", "readability", "best-practices", "all"),
mcp.Default("all"),
),
)
s.AddPrompt(codeReviewPrompt, handleCodeReview)
server.ServeStdio(s)
}
func handleCodeReview(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
// Extract arguments safely
args := req.Params.Arguments
if args == nil {
return nil, fmt.Errorf("missing required arguments")
}
code, ok := args["code"].(string)
if !ok {
return nil, fmt.Errorf("code argument is required and must be a string")
}
language := getStringArg(args, "language", "auto-detect")
focus := getStringArg(args, "focus", "all")
// Build the prompt based on focus area
var instructions string
switch focus {
case "security":
instructions = "Focus specifically on security vulnerabilities, input validation, and potential attack vectors."
case "performance":
instructions = "Focus on performance optimizations, algorithmic efficiency, and resource usage."
case "readability":
instructions = "Focus on code clarity, naming conventions, and maintainability."
case "best-practices":
instructions = "Focus on language-specific best practices and design patterns."
default:
instructions = "Provide a comprehensive review covering security, performance, readability, and best practices."
}
return &mcp.GetPromptResult{
Description: fmt.Sprintf("Code review for %s code", language),
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(fmt.Sprintf(
"Please review the following %s code:\n\n%s\n\nInstructions: %s\n\nPlease provide:\n1. Overall assessment\n2. Specific issues found\n3. Suggested improvements\n4. Best practice recommendations\n\nCode:\n
Data Analysis Prompt
func handleDataAnalysis(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
datasetURI := req.Params.Arguments["dataset_uri"].(string)
analysisType := getStringArg(req.Params.Arguments, "analysis_type", "exploratory")
focusAreas := getStringSliceArg(req.Params.Arguments, "focus_areas", []string{})
// Fetch the dataset (this would typically read from a resource)
dataset, err := fetchDataset(ctx, datasetURI)
if err != nil {
return nil, fmt.Errorf("failed to fetch dataset: %w", err)
}
// Build analysis instructions
var instructions strings.Builder
instructions.WriteString("Please analyze the provided dataset. ")
switch analysisType {
case "exploratory":
instructions.WriteString("Perform exploratory data analysis including summary statistics, distributions, and patterns.")
case "predictive":
instructions.WriteString("Focus on predictive modeling opportunities and feature relationships.")
case "diagnostic":
instructions.WriteString("Identify data quality issues, outliers, and potential problems.")
}
if len(focusAreas) > 0 {
instructions.WriteString(fmt.Sprintf(" Pay special attention to: %s.", strings.Join(focusAreas, ", ")))
}
return &mcp.GetPromptResult{
Description: fmt.Sprintf("%s analysis of dataset", strings.Title(analysisType)),
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(fmt.Sprintf(`%s
Dataset Information:
- Source: %s
- Records: %d
- Columns: %s
Dataset Preview:
%s
Please provide a comprehensive analysis including:
1. Data overview and quality assessment
2. Key insights and patterns
3. Recommendations for further analysis
4. Potential issues or concerns`,
instructions.String(),
datasetURI,
dataset.RecordCount,
strings.Join(dataset.Columns, ", "),
dataset.Preview,
)),
},
},
}, nil
}
Prompt Arguments
Flexible Parameter Handling
func handleFlexiblePrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
// Required arguments
task := req.Params.Arguments["task"].(string)
// Optional arguments with defaults
tone := getStringArg(req.Params.Arguments, "tone", "professional")
length := getStringArg(req.Params.Arguments, "length", "medium")
audience := getStringArg(req.Params.Arguments, "audience", "general")
// Array arguments
keywords := getStringSliceArg(req.Params.Arguments, "keywords", []string{})
// Object arguments
var constraints map[string]interface{}
if c, exists := req.Params.Arguments["constraints"]; exists {
constraints = c.(map[string]interface{})
}
// Build prompt based on parameters
prompt := buildDynamicPrompt(task, tone, length, audience, keywords, constraints)
return &mcp.GetPromptResult{
Description: fmt.Sprintf("Generate %s content", task),
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(prompt),
},
},
}, nil
}
func getStringArg(args map[string]interface{}, key, defaultValue string) string {
if val, exists := args[key]; exists {
if str, ok := val.(string); ok {
return str
}
}
return defaultValue
}
func getStringSliceArg(args map[string]interface{}, key string, defaultValue []string) []string {
if val, exists := args[key]; exists {
if slice, ok := val.([]interface{}); ok {
result := make([]string, len(slice))
for i, v := range slice {
if str, ok := v.(string); ok {
result[i] = str
}
}
return result
}
}
return defaultValue
}
Message Types
Multi-Message Conversations
func handleConversationPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
scenario := req.Params.Arguments["scenario"].(string)
userRole := getStringArg(req.Params.Arguments, "user_role", "customer")
var messages []mcp.PromptMessage
switch scenario {
case "customer_support":
messages = []mcp.PromptMessage{
{
Role: "system",
Content: mcp.NewTextContent("You are a helpful customer support representative. Be polite, professional, and solution-oriented."),
},
{
Role: "user",
Content: mcp.NewTextContent(fmt.Sprintf("I'm a %s with a question about your service.", userRole)),
},
{
Role: "assistant",
Content: mcp.NewTextContent("Hello! I'm here to help. What can I assist you with today?"),
},
{
Role: "user",
Content: mcp.NewTextContent("Please continue the conversation based on the customer's needs."),
},
}
case "technical_interview":
messages = []mcp.PromptMessage{
{
Role: "system",
Content: mcp.NewTextContent("You are conducting a technical interview. Ask thoughtful questions and provide constructive feedback."),
},
{
Role: "user",
Content: mcp.NewTextContent("Let's begin the technical interview. Please start with an appropriate question."),
},
}
}
return &mcp.GetPromptResult{
Description: fmt.Sprintf("%s conversation scenario", strings.Title(scenario)),
Messages: messages,
}, nil
}
System and User Roles
func handleRoleBasedPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
expertise := req.Params.Arguments["expertise"].(string)
task := req.Params.Arguments["task"].(string)
context := getStringArg(req.Params.Arguments, "context", "")
// Define system message based on expertise
var systemMessage string
switch expertise {
case "software_engineer":
systemMessage = "You are an experienced software engineer with expertise in system design, code quality, and best practices."
case "data_scientist":
systemMessage = "You are a data scientist with expertise in statistical analysis, machine learning, and data visualization."
case "product_manager":
systemMessage = "You are a product manager with expertise in user experience, market analysis, and feature prioritization."
default:
systemMessage = fmt.Sprintf("You are an expert in %s.", expertise)
}
messages := []mcp.PromptMessage{
{
Role: "system",
Content: mcp.NewTextContent(systemMessage),
},
}
// Add context if provided
if context != "" {
messages = append(messages, mcp.PromptMessage{
Role: "user",
Content: mcp.NewTextContent(fmt.Sprintf("Context: %s", context)),
})
}
// Add the main task
messages = append(messages, mcp.PromptMessage{
Role: "user",
Content: mcp.NewTextContent(task),
})
return &mcp.GetPromptResult{
Description: fmt.Sprintf("%s task", strings.Title(expertise)),
Messages: messages,
}, nil
}
Embedded Resources
Including Resource Data
func handleResourceEmbeddedPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
documentURI := req.Params.Arguments["document_uri"].(string)
analysisType := getStringArg(req.Params.Arguments, "analysis_type", "summary")
// Fetch the document content
document, err := fetchResource(ctx, documentURI)
if err != nil {
return nil, fmt.Errorf("failed to fetch document: %w", err)
}
// Build analysis prompt with embedded content
var instructions string
switch analysisType {
case "summary":
instructions = "Please provide a concise summary of the key points in this document."
case "critique":
instructions = "Please provide a critical analysis of the arguments and evidence presented."
case "questions":
instructions = "Please generate thoughtful questions that this document raises or could be used to explore."
case "action_items":
instructions = "Please extract actionable items and recommendations from this document."
}
return &mcp.GetPromptResult{
Description: fmt.Sprintf("Document %s", analysisType),
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(fmt.Sprintf(`%s
Document: %s
Content:
---
%s
---
Please provide your analysis following the instructions above.`,
instructions,
documentURI,
document.Content,
)),
},
},
}, nil
}
Dynamic Resource Integration
func handleDynamicResourcePrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
resourceURIs := req.Params.Arguments["resource_uris"].([]interface{})
promptType := getStringArg(req.Params.Arguments, "prompt_type", "compare")
// Fetch all resources
var resources []ResourceData
for _, uri := range resourceURIs {
if uriStr, ok := uri.(string); ok {
resource, err := fetchResource(ctx, uriStr)
if err != nil {
return nil, fmt.Errorf("failed to fetch resource %s: %w", uriStr, err)
}
resources = append(resources, resource)
}
}
// Build prompt based on type and resources
var content strings.Builder
switch promptType {
case "compare":
content.WriteString("Please compare and contrast the following documents:\n\n")
for i, resource := range resources {
content.WriteString(fmt.Sprintf("Document %d (%s):\n%s\n\n", i+1, resource.URI, resource.Content))
}
content.WriteString("Please provide:\n1. Key similarities\n2. Important differences\n3. Overall assessment")
case "synthesize":
content.WriteString("Please synthesize information from the following sources:\n\n")
for i, resource := range resources {
content.WriteString(fmt.Sprintf("Source %d (%s):\n%s\n\n", i+1, resource.URI, resource.Content))
}
content.WriteString("Please create a unified analysis that incorporates insights from all sources.")
}
return &mcp.GetPromptResult{
Description: fmt.Sprintf("%s multiple resources", strings.Title(promptType)),
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(content.String()),
},
},
}, nil
}
Advanced Prompt Patterns
Conditional Prompts
func handleConditionalPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
userLevel := getStringArg(req.Params.Arguments, "user_level", "beginner")
topic := req.Params.Arguments["topic"].(string)
includeExamples := getBoolArg(req.Params.Arguments, "include_examples", true)
var prompt strings.Builder
// Adjust complexity based on user level
switch userLevel {
case "beginner":
prompt.WriteString(fmt.Sprintf("Please explain %s in simple terms suitable for someone new to the topic. ", topic))
prompt.WriteString("Use clear language and avoid jargon. ")
case "intermediate":
prompt.WriteString(fmt.Sprintf("Please provide a detailed explanation of %s. ", topic))
prompt.WriteString("Include technical details but ensure clarity. ")
case "advanced":
prompt.WriteString(fmt.Sprintf("Please provide an in-depth analysis of %s. ", topic))
prompt.WriteString("Include advanced concepts, edge cases, and technical nuances. ")
}
if includeExamples {
prompt.WriteString("Please include relevant examples and practical applications.")
}
return &mcp.GetPromptResult{
Description: fmt.Sprintf("%s explanation for %s level", topic, userLevel),
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(prompt.String()),
},
},
}, nil
}
func getBoolArg(args map[string]interface{}, key string, defaultValue bool) bool {
if val, exists := args[key]; exists {
if b, ok := val.(bool); ok {
return b
}
}
return defaultValue
}
Template-Based Prompts
type PromptTemplate struct {
Name string
Description string
Template string
Variables []string
}
var promptTemplates = map[string]PromptTemplate{
"bug_report": {
Name: "Bug Report Analysis",
Description: "Analyze a bug report and suggest solutions",
Template: `Please analyze this bug report:
**Bug Description:** {{.description}}
**Steps to Reproduce:** {{.steps}}
**Expected Behavior:** {{.expected}}
**Actual Behavior:** {{.actual}}
**Environment:** {{.environment}}
Please provide:
1. Root cause analysis
2. Potential solutions
3. Prevention strategies
4. Priority assessment`,
Variables: []string{"description", "steps", "expected", "actual", "environment"},
},
"feature_request": {
Name: "Feature Request Evaluation",
Description: "Evaluate a feature request",
Template: `Please evaluate this feature request:
**Feature:** {{.feature}}
**Use Case:** {{.use_case}}
**User Story:** {{.user_story}}
**Acceptance Criteria:** {{.criteria}}
Please assess:
1. Business value and impact
2. Technical feasibility
3. Implementation complexity
4. Potential risks and considerations`,
Variables: []string{"feature", "use_case", "user_story", "criteria"},
},
}
func handleTemplatePrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
templateName := req.Params.Arguments["template"].(string)
variables := req.Params.Arguments["variables"].(map[string]interface{})
template, exists := promptTemplates[templateName]
if !exists {
return nil, fmt.Errorf("unknown template: %s", templateName)
}
// Replace template variables
content := template.Template
for _, variable := range template.Variables {
if value, exists := variables[variable]; exists {
placeholder := fmt.Sprintf("{{.%s}}", variable)
content = strings.ReplaceAll(content, placeholder, fmt.Sprintf("%v", value))
}
}
return &mcp.GetPromptResult{
Description: template.Description,
Messages: []mcp.PromptMessage{
{
Role: "user",
Content: mcp.NewTextContent(content),
},
},
}, nil
}
Next Steps
- Advanced Features - Explore typed tools, middleware, and hooks
- Client Integration - Learn how to build MCP clients
- Tools - Learn about implementing server tools