rohitg00/ai-engineering-from-scratch · error · ValueError
_meta.{CLIENT_INFO_KEY} must include name and version
Error message
_meta.{CLIENT_INFO_KEY} must include name and version What it means
Unlike version and capabilities, `_meta["io.modelcontextprotocol/clientInfo"]` is optional — but if present it must be an object with string `name` and string `version` fields, matching the MCP ImplementationInfo shape. This error fires only when the key exists and is malformed: not a dict, missing name/version, or either field is not a string.
Source
Thrown at certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py:220
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(
self, method: str, params: dict[str, Any], metadata: dict[str, Any]
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
if method == "server/discover":
extra = set(params) - {"_meta"}
if extra:
raise ValueError("server/discover accepts no params beyond _meta")
return self._complete(
supportedVersions=[CURRENT_PROTOCOL_VERSION],
capabilities={"prompts": {}, "resources": {}, "tools": {}},View on GitHub (pinned to 39ea8a1c6d)
Solutions
- Either omit the clientInfo key entirely (it is optional) or send {"name": "<string>", "version": "<string>"}
- Stringify version numbers: str(__version__) or version from importlib.metadata as str
- When clientInfo is unknown, delete the key from the payload rather than setting it to None
Example fix
# before
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": None,
}
# after
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": {"name": "my-client", "version": "1.0.0"},
} Defensive patterns
Strategy: type-guard
Validate before calling
INFO_KEY = "io.modelcontextprotocol/clientInfo"
def clean_client_info(meta: dict) -> dict:
info = meta.get(INFO_KEY)
if info is None:
meta.pop(INFO_KEY, None)
else:
meta[INFO_KEY] = {
"name": str(info["name"]),
"version": str(info["version"]),
}
return meta Type guard
def valid_client_info(meta: dict) -> bool:
info = meta.get("io.modelcontextprotocol/clientInfo")
return info is None or (
isinstance(info, dict)
and isinstance(info.get("name"), str)
and isinstance(info.get("version"), str)
) Prevention
- Omit clientInfo when unknown rather than sending None or partial dicts
- Coerce name/version with str() at the boundary
- Centralize clientInfo in one config so partial copies cannot leak into requests
When it happens
Trigger: clientInfo set to "my-client" (bare string), {"name": "x"} (no version), {"name": "x", "version": 1.2} (numeric version), or null under the key.
Common situations: Injecting a version parsed from pyproject/package.json that arrives as a tuple or float; optional-field handling where None is sent instead of omitting the key entirely; clientInfo confused with serverInfo in the payload.
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
- _meta must be an object
- _meta.{PROTOCOL_VERSION_KEY} is required
- _meta.{CLIENT_CAPABILITIES_KEY} is required
- -32600
- -32022
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/38428b7cc4d3df38.
Report an issue: GitHub.