Ship prompts your users do not have to write
A user could already type "reformat the report.pdf in markdown" and get a usable result out of Claude. That is the baseline. The question is whether that is the experience you want to ship — relying on every user to hand-craft their own prompt, every time, and hoping they get it right.
You would not ship a product that way. You would sit down, write a careful prompt, test it against a handful of tricky documents, tighten the edge cases, and bake the result into the application. Prompts in MCP are exactly that: pre-built, tested, server-defined instructions that clients can invoke by name, usually through a slash command. They let you encode domain expertise once and expose it to every user without asking them to become prompt engineers.
Why prompts are different from tools and resources
So far you have seen two primitives with distinct control patterns:
- Tools are model-controlled. Claude decides when to call them.
- Resources are app-controlled. Your application code decides when to fetch them.
Prompts are the third pattern: user-controlled. The user decides — via a button click, a menu selection, or a slash command — when to trigger a predefined workflow. That workflow is a prompt the server author crafted and the client now runs on behalf of the user.
Building a /format command
Walk through a concrete example: a format prompt that rewrites a document into clean markdown. In the chatbot, the user experience will look like this:
- User types
/in the chat input. - The CLI shows the list of available prompts from the server.
- User picks
formatand is asked for a document ID. - The server fills the ID into its pre-written prompt template.
- The resulting messages go to Claude, which uses the
edit_documenttool to reformat the document in place.
Notice how much the user did not have to do. They did not write a prompt, decide which tool to use, or work out how to phrase the reformatting instructions. They picked a command and a document. The server did the prompt engineering.
Defining the prompt
In mcp_server.py, add this alongside your tools and resources:
from mcp.server.fastmcp.prompts import base
from pydantic import Field
@mcp.prompt(
name="format",
description="Rewrites the contents of the document in Markdown format."
)
def format_document(
doc_id: str = Field(description="Id of the document to format")
) -> list[base.Message]:
prompt = f"""
Your goal is to reformat a document to be written with markdown syntax.
The id of the document you need to reformat is:
<document_id>
{doc_id}
</document_id>
Add in headers, bullet points, tables, etc as necessary. Feel free to add in structure.
Use the 'edit_document' tool to edit the document. After the document has been reformatted...
"""
return [
base.UserMessage(prompt)
]
The decorator pattern is familiar by now. @mcp.prompt takes a name and description, the function parameters use Pydantic Field for argument documentation, and the return type is a list of messages — base.UserMessage and base.AssistantMessage — that get sent directly to Claude.
A few details worth calling out. The doc_id flows in as a keyword argument and gets interpolated into the prompt template with an f-string. The returned list becomes the conversation that starts the run — you can return multiple messages to stage a more complex setup, or a single user message for simple workflows like this one. And the prompt does not just describe the task; it tells Claude which tool to use, connecting the prompt primitive back to the tool primitive you built in Module 2.
The value proposition
The point of server-defined prompts is to move prompt quality out of the user's hands and into the server author's. As the MCP server author, you can:
- Craft carefully — write the prompt once, with thought.
- Test systematically — run it against edge cases before shipping.
- Encode domain expertise — include context and constraints only someone close to the domain would know.
- Update in one place — improve the prompt once and every client that uses it benefits.
Your users get reliably better output than they would by improvising. They never have to know you spent an afternoon tuning the template.
Testing prompts in the Inspector
The Inspector has a Prompts tab for exactly this. Select your format prompt, enter a document ID, and the Inspector will show you the fully interpolated messages — exactly what Claude will receive. This lets you verify the template before anyone clicks /format in the real chatbot, and before you write the client-side code that will consume it in the next lesson.
Prompts work best when they are specialised for your server's domain. A document management server has prompts for formatting, summarising, or analysing. A data analysis server has prompts for generating reports or visualisations. The common thread is that each prompt is a packaged, tested piece of domain expertise your users can invoke by name.
Key Takeaways
- 1Prompts are server-defined, pre-tested instructions that clients can invoke by name through UI actions like slash commands.
- 2Server-authored prompts let you encode domain expertise once so users get high-quality results without writing prompts themselves.
- 3The @mcp.prompt decorator mirrors the tool and resource decorators, with the function returning a list of base.UserMessage or base.AssistantMessage objects.
- 4Prompts round out the three control patterns of MCP: tools are model-controlled, resources are app-controlled, and prompts are user-controlled.