Skip to content

Prompts

A prompt is a reusable message template the server offers and the user chooses to run. The typical UI is a slash command: the user types /code_review, the host asks for the arguments, calls prompts/get, and injects the returned messages into the conversation.

“User-controlled” describes who decides when the prompt is used — not who wrote it. The server authors the content; the person triggers it. That distinction is why prompts are safe to make powerful: they can encode your team’s review checklist, a debugging playbook, or a few-shot example set, and they only run when someone asks.

sequenceDiagram
  participant U as User
  participant C as Host
  participant S as Server
  C->>S: prompts/list
  S-->>C: prompts[] shown as slash commands
  U->>C: /code_review code=...
  C->>S: prompts/get name=code_review arguments
  S-->>C: messages[]
  C->>U: messages injected into the conversation
Slash command to messages
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"prompts": [
{
"name": "code_review",
"title": "Request Code Review",
"description": "Asks the LLM to analyze code quality and suggest improvements",
"arguments": [
{ "name": "code", "description": "The code to review", "required": true },
{ "name": "language", "description": "Programming language", "required": false }
]
}
],
"nextCursor": "next-page-cursor",
"ttlMs": 600000,
"cacheScope": "public"
}
}

A prompt has a name, optional title and description, optional icons, and an optional list of arguments, each with a name, description, and required flag. Arguments are always strings on the wire — the host collects them from the user as text.

{
"jsonrpc": "2.0",
"id": 2,
"method": "prompts/get",
"params": { "name": "code_review", "arguments": { "code": "def hello():\n print('world')" } }
}
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"description": "Code review prompt",
"messages": [
{
"role": "user",
"content": { "type": "text", "text": "Please review this Python code:\ndef hello():\n print('world')" }
}
]
}
}

messages is an ordered list of PromptMessage objects, each with a role of user or assistant and a single content block. Because you control the whole sequence, you can return a conversation, not just one instruction — a system-style framing as the first user message, an assistant message showing the expected format, then the user’s actual input.

Like the other act methods, prompts/get MAY return an InputRequiredResult when the server needs to elicit something before it can build the messages.

typeFieldsUse for
texttextInstructions, few-shot examples
imagedata (base64), mimeTypeA screenshot to critique, a design mock
audiodata (base64), mimeTypeAudio to transcribe or discuss
resource_linkuri, name, description, mimeTypePoint at a resource the host can fetch
resourceresource: { uri, mimeType, text or blob }Embed a document, schema, or code sample inline

Embedded resources are the strongest feature here: a db_query_help prompt can embed the live database schema so the model does not have to guess table names. All content blocks support the usual annotations (audience, priority, lastModified).

import { McpServer, completable } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
const server = new McpServer({ name: 'review', version: '1.0.0' });
server.registerPrompt(
'code_review',
{
title: 'Request Code Review',
description: 'Asks the LLM to analyze code quality and suggest improvements',
argsSchema: z.object({
code: z.string().describe('The code to review'),
language: completable(z.string().describe('Programming language'), (value) =>
['typescript', 'javascript', 'python', 'rust', 'go'].filter((l) => l.startsWith(value)),
),
}),
},
({ code, language }) => ({
messages: [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: `Review this ${language} code. Check correctness first, then readability.\n\n${code}`,
},
},
],
}),
);

argsSchema drives the arguments list in prompts/list; wrapping a field in completable(...) makes the server answer completion/complete for it.

Hosts call completion/complete as the user types an argument value, so the picker can suggest valid entries:

{
"jsonrpc": "2.0",
"id": 3,
"method": "completion/complete",
"params": {
"ref": { "type": "ref/prompt", "name": "code_review" },
"argument": { "name": "language", "value": "py" }
}
}
{
"jsonrpc": "2.0",
"id": 3,
"result": { "resultType": "complete", "completion": { "values": ["python"], "hasMore": false } }
}

The same request with "type": "ref/resource" and a uri template completes resource template variables. Completion is a completions server capability; declare it if you implement it.

Prompts shine when a task is repeated and has a known good shape. Some patterns:

  • Checklists. “Release readiness review” that walks through tests, changelog, migration notes — as a numbered list the model must address in order.
  • Few-shot sets. Two or three worked examples of the output format you want, as alternating user/assistant messages, followed by the real input.
  • Grounded prompts. Embed a resource (schema, style guide, glossary) so the model works from the source of truth instead of memory.
  • Parameterized playbooks. incident_triage(service, severity) that pulls the right runbook section for that service.

When is a prompt the wrong choice?

SituationUse instead
The model should decide when to do itA tool
It is just data with no instructionsA resource
It needs to do something (write, call an API)A tool — prompts only produce messages

A prompt never executes anything. If your “prompt” needs to fetch live data, have it embed a resource or tell the model which tool to call next.

  • Unknown prompt name → -32602 (Invalid params).
  • Missing required argument → -32602.
  • Internal failure → -32603.

Servers SHOULD validate arguments before building messages, and — since arguments are user-supplied text that ends up in the model’s context — treat them as untrusted input. Do not let an argument break out of the framing you intended (for example, by interpolating it into a place where it can masquerade as an assistant turn).

In the prompts interaction model, who decides WHEN a prompt is used?
Which method lets a host suggest valid values for a prompt argument as the user types?
A team wants a "/deploy" command that actually triggers a deployment. What is the right primitive?