{"record":{"id":"f59453ce5295fb21","repo":"shareAI-lab/learn-claude-code","slug":"missing-mcp-handlers-join-missing","errorCode":null,"errorMessage":"Missing MCP handlers: {', '.join(missing)}","messagePattern":"Missing MCP handlers: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"s14_mcp_plugin/code.py","lineNumber":176,"sourceCode":"# -- New in s14: MCP discovery and dispatch --\n\nclass MCPClient:\n    \"\"\"Small in-process stand-in for MCP tools/list and tools/call.\"\"\"\n\n    def __init__(self, name: str):\n        self.name = name\n        self.tools: list[dict] = []\n        self._handlers: dict[str, callable] = {}\n\n    def register(self, tool_defs: list[dict], handlers: dict[str, callable]):\n        names = [tool.get(\"name\") for tool in tool_defs]\n        if any(not isinstance(name, str) or not name for name in names):\n            raise ValueError(\"Every MCP tool needs a non-empty name\")\n        if len(set(names)) != len(names):\n            raise ValueError(f\"Duplicate MCP tool name on server {self.name!r}\")\n        missing = [name for name in names if name not in handlers]\n        if missing:\n            raise ValueError(f\"Missing MCP handlers: {', '.join(missing)}\")\n        self.tools = list(tool_defs)\n        self._handlers = dict(handlers)\n\n    def call_tool(self, tool_name: str, args: dict) -> str:\n        handler = self._handlers.get(tool_name)\n        if not handler:\n            return f\"MCP error: unknown tool '{tool_name}'\"\n        try:\n            return str(handler(**args))\n        except Exception as exc:\n            return f\"MCP error: {type(exc).__name__}: {exc}\"\n\n\nmcp_clients: dict[str, MCPClient] = {}\nmcp_tool_policies: dict[str, str] = {}\n_DISALLOWED_CHARS = re.compile(r\"[^a-zA-Z0-9_-]\")\n\n# Authorization comes from host configuration, never server descriptions.","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s14_mcp_plugin/code.py#L158-L194","documentation":"MCPClient.register() requires a handler for every tool name in tool_defs; any tool without an entry in the handlers dict is listed as missing in the error. This keeps the catalog and dispatch table consistent — a listed tool must be callable.","triggerScenarios":"register([{'name': 'search'}, {'name': 'get_version'}], handlers={'search': fn}) → 'Missing MCP handlers: get_version'; handler dict keys with typos or different casing than the def names.","commonSituations":"Adding a new tool def but forgetting its handler; renaming a tool in defs but not the handlers dict; building handlers via vars() or filtering that drops one entry.","solutions":["Add a handler keyed by the exact tool name string.","Derive handlers and defs from one source of truth (e.g. a registry decorator) so they cannot drift.","Copy the name string from the error message to fix casing/typo mismatches."],"exampleFix":"// before\nserver.register(\n    [{'name': 'search'}, {'name': 'get_version'}],\n    handlers={'search': do_search})  // missing get_version\n\n// after\nserver.register(\n    [{'name': 'search'}, {'name': 'get_version'}],\n    handlers={'search': do_search, 'get_version': do_get_version})","handlingStrategy":"validation","validationCode":"def handlers_cover_defs(tool_defs: list[dict], handlers: dict) -> bool:\n    return all(t['name'] in handlers for t in tool_defs)\n\nassert handlers_cover_defs(defs, handlers) before register(defs, handlers)","typeGuard":null,"tryCatchPattern":"try:\n    server.register(defs, handlers)\nexcept ValueError as exc:\n    if str(exc).startswith('Missing MCP handlers'):\n        missing = str(exc).rsplit(':', 1)[1].split(',')\n        raise RuntimeError(f'wire handlers for {missing}') from exc\n    raise","preventionTips":["Derive defs and handlers from a single registry (decorator pattern) so they cannot drift.","After adding a tool def, run a smoke register() in CI to catch missing handlers.","Use the exact name strings from the error message to fix key mismatches."],"tags":["mcp","tool-registration","validation","handler-missing"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}