rohitg00/ai-engineering-from-scratch · error · ValueError
_meta.{PROTOCOL_VERSION_KEY} is required
Error message
_meta.{PROTOCOL_VERSION_KEY} is required What it means
After confirming `_meta` is an object, the server looks up the namespaced key `io.modelcontextprotocol/protocolVersion` and requires it to be a string. Missing key, null, or a non-string value (e.g. a number) raises this error. Version negotiation is mandatory per request in this stateless design, so there is no session-cached version to fall back on.
Source
Thrown at certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py:211
reason = params.get("reason")
if reason is not None and not isinstance(reason, str):
raise ValueError("notifications/cancelled reason must be a string")
metadata = params.get("_meta")
if metadata is not None and not isinstance(metadata, dict):
raise ValueError("notifications/cancelled _meta must be an object")
if set(params) - {"requestId", "reason", "_meta"}:
raise ValueError("notifications/cancelled contains unexpected fields")
def _validate_request_metadata(self, params: Any) -> dict[str, Any]:
if not isinstance(params, dict):
raise ValueError("params must be an object")
metadata = params.get("_meta")
if not isinstance(metadata, dict):
raise ValueError("_meta must be an object")
version = metadata.get(PROTOCOL_VERSION_KEY)
capabilities = metadata.get(CLIENT_CAPABILITIES_KEY)
if not isinstance(version, str):
raise ValueError(f"_meta.{PROTOCOL_VERSION_KEY} is required")
if not isinstance(capabilities, dict):
raise ValueError(f"_meta.{CLIENT_CAPABILITIES_KEY} is required")
client_info = metadata.get(CLIENT_INFO_KEY)
if client_info is not None and (
not isinstance(client_info, dict)
or not isinstance(client_info.get("name"), str)
or not isinstance(client_info.get("version"), str)
):
raise ValueError(f"_meta.{CLIENT_INFO_KEY} must include name and version")
if version != CURRENT_PROTOCOL_VERSION:
raise ProtocolError(
-32022,
"Unsupported protocol version",
{"supported": [CURRENT_PROTOCOL_VERSION], "requested": version},
)
return metadata
def _dispatch(View on GitHub (pinned to 39ea8a1c6d)
Solutions
- Set _meta["io.modelcontextprotocol/protocolVersion"] = "2026-07-28" (CURRENT_PROTOCOL_VERSION, a string) in every request
- Check for the exact namespaced key — a bare "protocolVersion" key is silently ignored
- If the value comes from config, assert isinstance(value, str) before sending
Example fix
# before
"_meta": {"io.modelcontextprotocol/clientCapabilities": {}}
# after
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
} Defensive patterns
Strategy: validation
Validate before calling
VERSION_KEY = "io.modelcontextprotocol/protocolVersion"
def with_version(meta: dict) -> dict:
meta[VERSION_KEY] = str(meta.get(VERSION_KEY, "2026-07-28"))
return meta Type guard
def has_protocol_version(meta: dict) -> bool:
return isinstance(meta.get("io.modelcontextprotocol/protocolVersion"), str) Try / catch
try:
server.exchange(method, params)
except ValueError as e:
if "protocolVersion" in str(e):
params["_meta"][VERSION_KEY] = "2026-07-28"
server.exchange(method, params) Prevention
- Use the namespaced key verbatim — define it as a module constant, never retype it
- Stringify any version value coming from config or packaging metadata
- Fail fast client-side with an assert instead of a server round trip
When it happens
Trigger: _meta that includes clientCapabilities but omits protocolVersion; protocolVersion set to null, 2026 (int), or a list; typo'd key like "protocolVersion" without the io.modelcontextprotocol/ namespace prefix.
Common situations: Copy-paste from older MCP examples that used a bare "protocolVersion" key inside InitializeParams rather than the namespaced _meta key; schema drift between client and server after a spec version bump; YAML/JSON config where the date string got coerced.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/e3125eb01522bde7.
Report an issue: GitHub.