What it does
sampling/createMessage is a JSON-RPC request sent from a server to a client, instructing the client to perform an LLM completion on the server's behalf. The server constructs a CreateMessageRequest containing a messages array (SamplingMessage[]), a required maxTokens budget, an optional systemPrompt, optional modelPreferences (cost/speed/intelligence priority axes plus model name hints), optional stopSequences, and an optional includeContext flag ('none' | 'thisServer' | 'allServers') that controls whether the client should inject current MCP context into the prompt. The server sends this request and then blocks — awaiting a CreateMessageResult or a JSON-RPC error response.
Before sending, the server must verify that the client advertised the sampling capability (ClientCapabilities.sampling present) during the initialize handshake. If it was not declared, sending sampling/createMessage is a protocol violation. On receipt, the client is responsible for showing the user the pending request (human-in-the-loop approval), selecting a concrete model consistent with the server's modelPreferences hints, calling its LLM provider, and returning CreateMessageResult with role:'assistant', the generated content (TextContent | ImageContent | AudioContent), the actual model string used, and a stopReason. If the user declines or the LLM call fails, the client returns a JSON-RPC error, not a result.
The round-trip can span several seconds or longer for large maxTokens values. Servers must treat this as an async operation and never assume an immediate response. stopReason values 'endTurn', 'maxTokens', and 'stopSequence' are conventional; clients may return custom strings for provider-specific stop conditions. Servers should inspect stopReason to decide whether to retry, truncate, or continue a multi-turn loop using the returned content as the next assistant turn.
When to use
When the server needs LLM-driven reasoning, analysis, or generation.
When NOT to use
When the answer is computable without an LLM.
Notes
Capability gate is mandatory
The server must check ClientCapabilities.sampling before issuing this request. If the client did not include 'sampling':{} in its initialize response, the server must not call sampling/createMessage at all — doing so is a spec violation and the client is entitled to return -32601 (method not found) or simply close the connection.
Error codes to handle on the server
Expect -32603 (internal error) when the client's LLM call fails, and a custom error (commonly -32000 or -32001) when the user explicitly declines the sampling request. Servers should distinguish a declined request (user said no — do not retry automatically) from a transient LLM error (may retry with back-off). Never treat a JSON-RPC error response as a CreateMessageResult.
maxTokens is a hard requirement
The params.maxTokens field is required, not optional. Clients use it to bound cost and enforce provider limits. Omitting it should cause the client to return -32602 (invalid params). Set a realistic ceiling: too low truncates useful output (stopReason will be 'maxTokens'), too high wastes budget on simple tasks.
modelPreferences are hints, not commands
The client owns final model selection. The server's ModelPreferences (hints[], costPriority, speedPriority, intelligencePriority) are advisory. A client may ignore hint names it cannot resolve and fall back to its configured default. Servers must not hard-code assumptions about which concrete model will execute the request — read the returned model field in CreateMessageResult to know what actually ran.
Multi-turn agentic loops and ordering
When building agentic loops, append the CreateMessageResult content as an assistant message in your next sampling/createMessage call, then add the next user-turn message. Do not mutate in-flight message history across concurrent sampling calls — MCP makes no guarantee about request ordering between parallel sampling/createMessage calls. Serialize loop turns explicitly in your server logic.
Request parameters
| Name | Type | Purpose |
|---|---|---|
| messages | SamplingMessage[] | Conversation to complete. |
| modelPreferences | ModelPreferences? | Bias model selection. |
| systemPrompt | string? | System prompt. |
| maxTokens | number | Token budget. |
| includeContext | 'none' | 'thisServer' | 'allServers'? | MCP context inclusion. |
Response fields
| Name | Type | Purpose |
|---|---|---|
| role | 'assistant' | Always assistant. |
| content | TextContent | ImageContent | AudioContent | Generated content. |
| model | string | Actual model used. |
| stopReason | string? | Why generation stopped. |
Examples
Ask for analysis
{ "method": "sampling/createMessage", "params": { "messages": [...], "maxTokens": 200 } }
Common mistakes
❌ Treating it as synchronous
✅ Sampling can take seconds — show progress.