MCP Sampling Through Client-Mediated LLM Calls

Protocols & Interoperability intermediate Building with AI ~30 min read

Overview

Model Context Protocol sampling lets an MCP server ask the connected client to run an LLM completion on its behalf. The server does not receive a provider API key, choose the final model unilaterally, or bypass the user’s approval surface. Instead, it sends a structured sampling/createMessage request to the client, and the client decides whether to approve, modify, route, and return the generated response.

This reverses the usual tool-calling direction. In ordinary MCP use, the model calls a server’s tools. With sampling, a server can call back into the client’s model runtime while it is fulfilling a tool request. That enables tools that summarize fetched records, classify local content, draft transformations, or perform a small reasoning step without embedding their own LLM vendor integration.

The design is especially useful when the client owns model access, user consent, and cross-server context policy. A server can request a completion with messages, model preferences, a system prompt, generation parameters, and an optional context-inclusion preference, while the client remains free to constrain what context is attached and which model is actually used.

Core Concepts

Client-Controlled Model Access

Sampling keeps model credentials and provider routing in the MCP client. The server expresses preferences, not commands. A model hint such as a preferred family can be mapped by the client to any available provider, ignored entirely, or constrained by organization policy. This matters because MCP servers may be installed from many sources and should not automatically inherit unrestricted model access.

Human Review Checkpoints

The client can expose the sampling request before it is sent to the LLM and expose the generated response before returning it to the server. That creates two review points: one for what the model will see and one for what the server will receive. The server’s workflow can use LLM assistance while the user still controls prompt disclosure and generated content.

Provider-Neutral Message Shape

Sampling messages use the MCP schema rather than a provider-specific chat-completions format. Current schemas support user and assistant roles, text and media content, model preferences, maximum token settings, stop sequences, and optional tool-use fields in newer revisions. The client adapts that shape to OpenAI, Claude, Gemini, local runtimes, or another model backend.

Key Concept: Server Requests, Client Decides

A sampling request is not a direct LLM call. It is a permissioned request from an MCP server to the client. The client may approve, edit, reject, enrich, route, or limit the request before any model receives it.

How It Works

Request Flow

A server initiates sampling while handling a normal MCP operation. The client validates that it supports sampling, presents the request if review is required, invokes a model, optionally asks for response approval, then returns a CreateMessageResult to the server.

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Classify this API error as retryable or terminal."
        }
      }
    ],
    "modelPreferences": {
      "hints": [{ "name": "fast-reasoning" }],
      "costPriority": 0.7,
      "speedPriority": 0.8,
      "intelligencePriority": 0.5
    },
    "includeContext": "thisServer",
    "maxTokens": 200,
    "temperature": 0
  }
}

Result Handling

The response returns an assistant message plus model and stop metadata. The server should treat the result as untrusted model output: validate structure, bound side effects, and preserve the same authorization checks it would use for any other model-generated artifact.

{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "role": "assistant",
    "content": {
      "type": "text",
      "text": "retryable"
    },
    "model": "client-selected-model",
    "stopReason": "endTurn"
  }
}

Practical Applications

LLM-Assisted Tools Without Server-Side Keys

A documentation MCP server can fetch several pages, ask the client to summarize conflicts, and return a compact answer without storing an API key. A database MCP server can ask for a natural language explanation of a query plan while leaving model routing and approval to the client.

Policy-Aware Cross-Server Context

The includeContext field lets a server request context from itself or from all connected servers, but the client may ignore or narrow that request. This creates a useful boundary for enterprise clients: servers can ask for richer context, while the client enforces data-sharing policy.

Interactive Transformation Workflows

Sampling fits workflows where a server prepares deterministic evidence and asks the client-side model to transform it: draft a migration summary, classify a support transcript, produce a schema mapping, or explain an error. The server remains responsible for deterministic validation before committing any output.

Implementation Patterns

Capability-Gated Sampling

Servers should only offer sampling-dependent behavior after the client advertises support. A robust server also provides a fallback path: return raw evidence, a deterministic result, or an error explaining that client-side sampling is unavailable.

async function maybeClassifyWithSampling(client, evidence) {
  if (!client.capabilities?.sampling) {
    return { mode: "deterministic", label: classifyByRules(evidence) };
  }

  const result = await client.request({
    method: "sampling/createMessage",
    params: {
      messages: [{
        role: "user",
        content: { type: "text", text: buildPrompt(evidence) }
      }],
      maxTokens: 128,
      temperature: 0
    }
  });

  return validateClassification(result.content.text);
}

Structured Post-Validation

If the server needs JSON, SQL fragments, or policy decisions, it should validate after sampling rather than trusting prose. Keep the requested output small, use explicit allowed values, and reject results that do not match the expected schema.

Performance Considerations

Common Pitfalls

Further Reading