rohitg00/ai-engineering-from-scratch · error · ProtocolError

-32021

-32021

Error message

Server requires roots, sampling, and elicitation capabilities for this request

What it means

The prepare_review tool needs the client to gather workspace roots (roots/list), a model sample (sampling/createMessage), and a form elicitation (elicitation/create) on its behalf. Before starting that flow the server checks the client capabilities in metadata; if roots, sampling, or elicitation.form is missing it raises ProtocolError -32021 with a requiredCapabilities payload naming exactly what is absent.

Source

Thrown at certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py:381

                        "properties": {"goal": {"type": "string"}},
                        "required": ["goal"],
                    },
                },
            },
        }
        capabilities = metadata[CLIENT_CAPABILITIES_KEY]
        missing: dict[str, Any] = {}
        if not isinstance(capabilities.get("roots"), dict):
            missing["roots"] = {}
        if not isinstance(capabilities.get("sampling"), dict):
            missing["sampling"] = {}
        elicitation = capabilities.get("elicitation")
        if not isinstance(elicitation, dict) or (
            elicitation and not isinstance(elicitation.get("form"), dict)
        ):
            missing["elicitation"] = {"form": {}}
        if missing:
            raise ProtocolError(
                -32021,
                "Server requires roots, sampling, and elicitation capabilities for this request",
                {"requiredCapabilities": missing},
            )

        state = params.get("requestState")
        responses = params.get("inputResponses")
        if state is None:
            return self._input_required(
                inputRequests=input_requests,
                requestState=self.state_signer.issue("tools/call", "prepare_review", arguments),
            )
        self.state_signer.verify(state, "tools/call", "prepare_review", arguments)
        if not isinstance(responses, dict):
            return self._input_required(inputRequests=input_requests, requestState=state)
        missing_responses = {
            key: request for key, request in input_requests.items() if key not in responses
        }

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Read the error's data.requiredCapabilities — it lists the exact capability objects to add
  2. Declare roots {}, sampling {}, and elicitation {"form": {}} in the client capabilities metadata before calling prepare_review
  3. Gate the prepare_review call on negotiated capabilities exactly as the server does

Example fix

# before
meta = {"clientCapabilities": {"roots": {}}}

# after
meta = {"clientCapabilities": {"roots": {}, "sampling": {}, "elicitation": {"form": {}}}}
Defensive patterns

Strategy: validation

Validate before calling

caps = meta["clientCapabilities"]
required = {"roots": {}, "sampling": {}, "elicitation": {"form": {}}}
missing = {k: v for k, v in required.items() if not isinstance(caps.get(k), dict)}
if missing:
    raise ValueError(f"client missing capabilities: {sorted(missing)}")
server.exchange("tools/call", {"name": "prepare_review", ...}, metadata=meta)

Type guard

def has_required_capabilities(caps: object) -> bool:
    if not isinstance(caps, dict):
        return False
    if not all(isinstance(caps.get(k), dict) for k in ("roots", "sampling")):
        return False
    el = caps.get("elicitation")
    return isinstance(el, dict) and isinstance(el.get("form"), dict)

Try / catch

try:
    result = server.exchange("tools/call", params, metadata=meta)
except ProtocolError as exc:
    if exc.code == -32021:
        upgrade_client_capabilities(exc.data["requiredCapabilities"])
    raise

Prevention

When it happens

Trigger: Calling tools/call prepare_review without declaring roots/sampling/elicitation capabilities under the client-capabilities metadata key the server reads (CLIENT_CAPABILITIES_KEY from initialize).

Common situations: A minimal MCP client that skips capability negotiation; a client that supports roots but not elicitation forms; test harnesses reusing metadata from a different lesson or an older server revision.

Related errors


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/1799e5d9762285ca. Report an issue: GitHub.