Skip to main content

Sampling

Handle LLM completion requests from servers
MCP servers can request LLM completions from clients during tool execution. This enables servers to delegate AI reasoning to the client, which controls which model is used.

Handler

To support sampling, register a sampling handler when you connect. The handler receives the server’s request (CreateMessageRequestParams) and should return either:
  • CreateMessageResult (success), or
  • ErrorData (failure)
Here’s a complete example using Anthropic:
from anthropic import AsyncAnthropic
from dedalus_mcp import types

anthropic = AsyncAnthropic()

async def sampling_handler(
    _ctx: object,
    params: types.CreateMessageRequestParams,
) -> types.CreateMessageResult | types.ErrorData:
    try:
        messages = [{"role": m.role, "content": m.content.text} for m in params.messages]

        resp = await anthropic.messages.create(
            model="claude-sonnet-4-20250514",
            messages=messages,
            max_tokens=params.maxTokens,
        )

        return types.CreateMessageResult(
            model=resp.model,
            role="assistant",
            content=types.TextContent(type="text", text=resp.content[0].text),
            stopReason="end_turn",
        )
    except Exception as e:
        return types.ErrorData(code=types.INTERNAL_ERROR, message=str(e))

Usage

Enable sampling by passing the handler in ClientCapabilitiesConfig when connecting:
capabilities = ClientCapabilitiesConfig(sampling=sampling_handler)

async with open_connection(
    url="http://127.0.0.1:8000/mcp",
    capabilities=capabilities,
) as client:
    # If the server calls sampling/createMessage during this tool run,
    # your sampling_handler will be invoked.
    result = await client.call_tool("analyze", {"data": "..."})

Error handling

When something goes wrong inside your handler, return an ErrorData (don’t raise). The server will receive this as an MCP error response to its sampling request.
from dedalus_mcp import types

async def sampling_handler(context: object, params: types.CreateMessageRequestParams):
    try:
        # ... call LLM ...
        return types.CreateMessageResult(
            model="claude-3-5-sonnet-20241022",
            role="assistant",
            content=types.TextContent(type="text", text="ok"),
            stopReason="end_turn",
        )
    except Exception as e:
        return types.ErrorData(code=types.INTERNAL_ERROR, message=str(e))