{"record":{"id":"2f6131e0ef44c5da","repo":"microsoft/semantic-kernel","slug":"method-not-found","errorCode":"METHOD_NOT_FOUND","errorMessage":"Unknown tool: {function_name}","messagePattern":"Unknown tool: (.+?)","errorType":"error_code","errorClass":"McpError","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/mcp.py","lineNumber":1125,"sourceCode":"                            for param in func.parameters\n                            if param.name and param.is_required and param.include_in_function_choices\n                        ],\n                    },\n                )\n                for func in functions_to_expose\n            ]\n            await _log(level=\"debug\", data=f\"List of tools: {tools}\")\n            await asyncio.sleep(0.0)\n            return tools\n\n        @server.call_tool()\n        async def _call_tool(\n            *args: Any,\n        ) -> Sequence[types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource]:\n            \"\"\"Call a tool in the kernel.\"\"\"\n            function_name, arguments = args[0], args[1]\n            if function_name not in exposed_names:\n                raise McpError(\n                    error=types.ErrorData(\n                        code=types.METHOD_NOT_FOUND,\n                        message=f\"Unknown tool: {function_name}\",\n                    )\n                )\n            await _log(level=\"debug\", data=f\"Calling tool: {function_name}\")\n            result = await _call_kernel_function(function_name, arguments)\n            if result:\n                value = result.value\n                messages: list[\n                    types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource\n                ] = []\n                if isinstance(value, list):\n                    for item in value:\n                        match item:\n                            case (\n                                TextContent() | ImageContent() | BinaryContent() | AudioContent() | ChatMessageContent()\n                            ):","sourceCodeStart":1107,"sourceCodeEnd":1143,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/mcp.py#L1107-L1143","documentation":"Raised inside the SK-as-MCP-server handler _call_tool (mcp.py:1125) as an McpError with code METHOD_NOT_FOUND when the incoming tool name is not in exposed_names (the set of kernel function names registered for exposure). This is server-side: Semantic Kernel is acting as an MCP server and a client requested a tool it never registered. The error is returned to the MCP client as a structured error response.","triggerScenarios":"An MCP client calls a tool name that was not exposed via the server's functions_to_expose list; a typo in the tool name; the tool was filtered out during exposure; the client cached a stale tool list. Guard at mcp.py:1124-1130.","commonSituations":"Client using an outdated tool list after the server removed/renamed a function; case-sensitivity mismatch (note _normalize_mcp_name rewrites names); plugin was added to the kernel after the server enumerated tools; client guessed a name.","solutions":["Have the client call tools/list first and use only the returned names.","Verify the requested name matches an exposed kernel function name exactly (after normalization).","Ensure the kernel function is registered before the MCP server exposes its tool list.","On the server side, confirm functions_to_expose includes the desired function and its name passes _normalize_mcp_name."],"exampleFix":"# client side - before\nawait session.call_tool(\"Summarise\", {...})  # typo / not exposed\n\n# after\nawait session.call_tool(\"summarize\", {...})  # exact exposed name","handlingStrategy":"validation","validationCode":"# client side: fetch the tool list and validate the requested name before calling\nasync def tool_is_exposed(session, name: str) -> bool:\n    tools = await session.list_tools()\n    exposed = {t.name for t in tools.tools}\n    return name in exposed","typeGuard":"import re\n\ndef name_matches_normalized(requested: str, exposed: set[str]) -> bool:\n    normalize = lambda n: re.sub(r\"[^A-Za-z0-9_.-]\", \"-\", n)\n    return normalize(requested) in {normalize(n) for n in exposed}","tryCatchPattern":"# client side\ntry:\n    await session.call_tool(\"Summarise\", {})\nexcept Exception as ex:\n    # McpError with METHOD_NOT_FOUND is returned as an error result;\n    # re-fetch tools/list and only call known names\n    tools = await session.list_tools()\n    names = {t.name for t in tools.tools}\n    if \"Summarise\" not in names:\n        # pick the correct (normalized) name","preventionTips":["Always call tools/list first and use only the returned names.","Remember _normalize_mcp_name rewrites non-alphanumeric chars to '-', so match post-normalization.","Register kernel functions before the MCP server enumerates tools.","Treat a METHOD_NOT_FOUND as a stale/incorrect tool name, not a server crash."],"tags":["mcp-server","tool-routing","method-not-found","name-normalization"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}