Introduction
MCP prompts are reusable templates that servers expose to clients. They allow server authors to encode domain-specific expertise into structured message templates that LLMs can use. In this lesson, you will learn how to discover and retrieve prompts from MCP servers using the client SDK.
Key Concepts
- MCP Prompt: A reusable message template exposed by an MCP server. Prompts define a name, description, and optional arguments that customize the generated messages.
- listPrompts(): A client method that discovers all prompts available on a connected server. Returns an array of prompt metadata including names, descriptions, and argument definitions.
- getPrompt(): A client method that retrieves a specific prompt by name, optionally passing arguments. Returns a messages array ready to send to an LLM.
- Prompt Arguments: Named parameters that customize prompt output. Each argument has a name, description, and a required flag.
Real World Context
Consider a code review tool. Instead of hardcoding review instructions in your application, the MCP server exposes a code-review prompt that encapsulates best practices. Your client discovers this prompt, passes the code and language as arguments, and receives a structured set of messages optimized for the LLM to perform a thorough review. If the review criteria change, the server author updates the prompt without any client-side changes.
Deep Dive
Prompt discovery starts with client.listPrompts(). This returns metadata about every prompt the server exposes, including argument definitions.
The following code demonstrates listing all available prompts from a connected server:
typescriptconst { prompts } = await client.listPrompts(); for (const prompt of prompts) { console.log(`Prompt: ${prompt.name}`); console.log(`Description: ${prompt.description}`); if (prompt.arguments) { for (const arg of prompt.arguments) { console.log(` Arg: ${arg.name} (required: ${arg.required})`); } } }
Each prompt in the array has a name string, an optional description, and an optional arguments array. The arguments array describes what inputs the prompt accepts.
Once you know a prompt's name and arguments, you retrieve it with client.getPrompt(). This call resolves the template with your provided arguments and returns the resulting messages.
Here is how to retrieve a prompt with arguments:
typescriptconst result = await client.getPrompt({ name: "code-review", arguments: { language: "typescript", code: "function add(a: number, b: number) { return a + b; }" } }); // result.messages contains the rendered prompt for (const msg of result.messages) { console.log(`[${msg.role}]: ${msg.content.type === 'text' ? msg.content.text : '(non-text)'}`); }
The getPrompt call takes an object with name (the prompt identifier) and arguments (a key-value map matching the prompt's argument definitions). The server resolves the template and returns the messages array.
Arguments can be required or optional. If a required argument is missing, the server will return an error. Optional arguments allow the prompt to provide sensible defaults.
The following example shows how to handle prompts with mixed required and optional arguments:
typescriptconst { prompts } = await client.listPrompts(); const reviewPrompt = prompts.find(p => p.name === 'code-review'); if (reviewPrompt) { const requiredArgs = reviewPrompt.arguments?.filter(a => a.required) ?? []; const optionalArgs = reviewPrompt.arguments?.filter(a => !a.required) ?? []; console.log('Required:', requiredArgs.map(a => a.name)); console.log('Optional:', optionalArgs.map(a => a.name)); // Build arguments object with all required args const args: Record<string, string> = {}; for (const arg of requiredArgs) { args[arg.name] = getUserInput(arg.name); // your input function } const result = await client.getPrompt({ name: 'code-review', arguments: args }); }
This pattern ensures your client validates that all required arguments are provided before making the request.
Common Pitfalls
- Assuming prompts are always available: Servers may not expose any prompts. Always check the length of the prompts array before iterating.
- Ignoring required arguments: Calling
getPromptwithout a required argument causes a server error. Always inspect the argument definitions fromlistPrompts()first. - Caching prompt lists indefinitely: Servers can add or remove prompts dynamically. Re-fetch the prompt list periodically or when the server signals a change.
Best Practices
- Discover prompts at startup and present them to users as available actions, similar to slash commands.
- Validate that all required arguments have values before calling
getPrompt()to provide better error messages. - Store prompt metadata (names, descriptions, arguments) locally for UI rendering, but always fetch fresh prompt content when executing.
Summary
- MCP prompts are reusable templates exposed by servers, discoverable via
client.listPrompts(). - Each prompt has a name, optional description, and optional arguments with required/optional flags.
- Retrieve prompt content with
client.getPrompt({ name, arguments }), which returns a messages array. - Always check argument requirements before calling
getPrompt()to avoid server errors. - Prompts decouple domain expertise from your client application, allowing server authors to update templates independently.
Code Examples
const { prompts } = await client.listPrompts();
for (const prompt of prompts) {
console.log(`Prompt: ${prompt.name}`);
console.log(`Description: ${prompt.description}`);
if (prompt.arguments) {
for (const arg of prompt.arguments) {
console.log(` Arg: ${arg.name} (required: ${arg.required})`);
}
}
}const result = await client.getPrompt({
name: "code-review",
arguments: {
language: "typescript",
code: "function add(a: number, b: number) { return a + b; }"
}
});
for (const msg of result.messages) {
console.log(`[${msg.role}]: ${msg.content.type === 'text' ? msg.content.text : '(non-text)'}`);
}