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:

typescript
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})`);
    }
  }
}

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:

typescript
const 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:

typescript
const { 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

  1. Assuming prompts are always available: Servers may not expose any prompts. Always check the length of the prompts array before iterating.
  2. Ignoring required arguments: Calling getPrompt without a required argument causes a server error. Always inspect the argument definitions from listPrompts() first.
  3. 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

  1. Discover prompts at startup and present them to users as available actions, similar to slash commands.
  2. Validate that all required arguments have values before calling getPrompt() to provide better error messages.
  3. 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

typescript
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})`);
    }
  }
}
typescript
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)'}`);
}
✓ Completed