Skip to main content

Module 5: Implementing Prompts

Duration: ~25 minutes | Level: Intermediate | Prerequisites: Module 4: Implementing Resources


What Prompts Are For

Prompts are the least intuitive MCP primitive, but they're powerful for team workflows.

A Prompt is a parameterised instruction template that:

  1. Appears in the host application's UI as a selectable workflow (a slash command, dropdown item, etc.)
  2. Accepts arguments from the user
  3. Returns a pre-assembled conversation structure that produces high-quality, consistent AI output

Think of them as expert-crafted prompt recipes that anyone on your team can invoke. Instead of every developer writing their own "review this code" instruction with varying levels of specificity, one person writes the ideal prompt once, and it's available to the whole team through their AI tool.


A Minimal Prompt

var codeReviewPrompt = new McpServerFeatures.SyncPromptSpecification(
new McpSchema.Prompt(
"code_review",
"Perform a thorough code review focusing on security, correctness, and maintainability",
List.of(
new McpSchema.PromptArgument(
"language",
"Programming language (java, python, typescript, etc.)",
false // not required
),
new McpSchema.PromptArgument(
"focus",
"Optional focus area: security | performance | style | correctness",
false
)
)
),
(exchange, request) -> {
String language = (String) request.arguments().getOrDefault("language", "unspecified");
String focus = (String) request.arguments().getOrDefault("focus", "general");

String instruction = buildCodeReviewInstruction(language, focus);

return new McpSchema.GetPromptResult(
"Code review assistant", // optional description
List.of(
new McpSchema.PromptMessage(
McpSchema.Role.USER,
new McpSchema.TextContent(instruction)
)
)
);
}
);

The handler returns a GetPromptResult containing an array of PromptMessage objects, the pre-assembled conversation starter. The host injects this into a new conversation with the AI, along with any user-provided code.


Building the Instruction

The buildCodeReviewInstruction helper assembles the actual prompt text:

private static String buildCodeReviewInstruction(String language, String focus) {
var sb = new StringBuilder();
sb.append("Please review the following ");
if (!"unspecified".equals(language)) {
sb.append(language).append(" ");
}
sb.append("code.\n\n");

sb.append("Focus: ").append(switch (focus) {
case "security" -> "Identify security vulnerabilities, injection risks, authentication gaps, and data exposure.";
case "performance" -> "Identify bottlenecks, inefficient algorithms, excessive allocations, and blocking operations.";
case "style" -> "Check naming conventions, code organisation, documentation, and adherence to idiomatic patterns.";
default -> "Provide a balanced review covering correctness, security, performance, and maintainability.";
}).append("\n\n");

sb.append("""
Structure your review as:
1. **Summary**, overall assessment in 2-3 sentences
2. **Critical Issues**, bugs or security problems that must be fixed
3. **Recommendations**, improvements worth making
4. **Positives**, what the code does well (be specific)

Reference specific line numbers where relevant. Be direct and constructive.
""");

return sb.toString();
}

Prompts with Resource Context

Prompts can embed resource references that the host can fetch and inject:

var sprintReviewPrompt = new McpServerFeatures.SyncPromptSpecification(
new McpSchema.Prompt(
"sprint_review",
"Generate a sprint retrospective based on completed tasks",
List.of(
new McpSchema.PromptArgument("sprint_id", "Sprint identifier", true)
)
),
(exchange, request) -> {
String sprintId = (String) request.arguments().get("sprint_id");
String resourceUri = "sprints://" + sprintId + "/summary";

// EmbeddedResource carries a ResourceContents (the actual bytes/text), not
// a reference to a URI. To attach a *reference* that the host should resolve,
// use ResourceLink content instead (added in spec 2025-06-18). Alternatively
// read the resource server-side and inline its contents here.
return new McpSchema.GetPromptResult(
"Sprint retrospective generator",
List.of(
new McpSchema.PromptMessage(
McpSchema.Role.USER,
new McpSchema.TextContent(
"Generate a comprehensive sprint retrospective for the sprint data below. " +
"Cover: what went well, what to improve, and action items for next sprint."
)
),
new McpSchema.PromptMessage(
McpSchema.Role.USER,
McpSchema.ResourceLink.builder()
.uri(resourceUri)
.name("sprint-" + sprintId + "-summary")
.title("Sprint " + sprintId + " summary")
.description("Sprint summary data fetched on each prompt invocation")
.mimeType("application/json")
.build()
)
)
);
}
);

The ResourceLink content type gives the host the URI of a resource it can fetch and include. Hosts that resolve resource links get fresh sprint data on every invocation; since fetching is at the client's discretion (and older clients may not understand ResourceLink at all), fetch the resource server-side and inline it as an EmbeddedResource carrying its ResourceContents when you need a guarantee.


Registering Prompts

McpServer.sync(transport)
.serverInfo("acme-prompts", "1.0.0")
.capabilities(McpSchema.ServerCapabilities.builder()
.prompts(true) // listChanged notifications enabled
.build())
.prompts(codeReviewPrompt, sprintReviewPrompt)
.build();

The client will call prompts/list to discover them and prompts/get to retrieve a specific prompt's messages.


When to Build a Prompt (vs. Just a Good Tool Description)

Prompts are worth building when:

  • The workflow is complex enough that most users would write a suboptimal prompt for it
  • Different roles (developer vs. manager) need different phrasings of the same task
  • The output needs to follow a specific structure (reports, reviews, summaries)
  • You want consistent AI behaviour across a team, not just one developer's session

If it's a one-liner that any developer would write correctly, you probably don't need a Prompt; a good tool description is enough.


Key Takeaways

  • Prompts are user-invoked workflow templates, not AI-invoked like Tools
  • They return pre-assembled PromptMessage arrays, the conversation starter
  • Prompts can embed resource references for dynamic context
  • Best for complex, high-quality workflows that teams use repeatedly

Companion code

A runnable server exposing both prompts (the parameterised code_review and the sprint_review that embeds a ResourceLink) is in the companion repository at projects/mcp-java-sdk/prompts-server/.

In the next module, we cover error handling, what to do when things go wrong.

→ Module 6: Error Handling