{"record":{"id":"b1c92fdfc768c93f","repo":"microsoft/semantic-kernel","slug":"internal-error","errorCode":"INTERNAL_ERROR","errorMessage":"Function {function_name} returned no result","messagePattern":"Function (.+?) returned no result","errorType":"error_code","errorClass":"McpError","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/mcp.py","lineNumber":1158,"sourceCode":"                        match item:\n                            case (\n                                TextContent() | ImageContent() | BinaryContent() | AudioContent() | ChatMessageContent()\n                            ):\n                                messages.extend(_kernel_content_to_mcp_content_types(item))\n                            case _:\n                                messages.append(\n                                    types.TextContent(type=\"text\", text=str(item)),\n                                )\n                else:\n                    match value:\n                        case TextContent() | ImageContent() | BinaryContent() | AudioContent() | ChatMessageContent():\n                            messages.extend(_kernel_content_to_mcp_content_types(value))\n                        case _:\n                            messages.append(\n                                types.TextContent(type=\"text\", text=str(value)),\n                            )\n                return messages\n            raise McpError(\n                error=types.ErrorData(\n                    code=types.INTERNAL_ERROR,\n                    message=f\"Function {function_name} returned no result\",\n                ),\n            )\n\n    if prompts:\n\n        @server.list_prompts()\n        async def _list_prompts() -> list[types.Prompt]:\n            \"\"\"List all prompts in the kernel.\"\"\"\n            mcp_prompts = []\n            for prompt in prompts:\n                mcp_prompts.append(\n                    types.Prompt(\n                        name=prompt.prompt_template_config.name,\n                        description=prompt.prompt_template_config.description,\n                        arguments=[","sourceCodeStart":1140,"sourceCodeEnd":1176,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/mcp.py#L1140-L1176","documentation":"Raised inside the MCP server's `@server.call_tool()` handler (`_call_tool`) after a Semantic Kernel function is invoked through the MCP bridge. The kernel function call returned a falsy result (`if result:` at mcp.py:1133 was False), so there is nothing to serialize into MCP content types, and the server responds with an MCP error carrying code INTERNAL_ERROR. It signals that the wrapped tool executed but produced no usable return value (None, empty FunctionResult, or a value that evaluates to False).","triggerScenarios":"An MCP client sends a `tools/call` request for a registered kernel function; the underlying kernel function returns `None`, an empty result, or raises-and-is-swallowed such that `_call_kernel_function` yields a falsy `FunctionResult`. The handler skips the `if result:` branch at line 1133 and falls through to the `raise McpError(...)` at line 1158.","commonSituations":"A kernel function registered via the MCP server has no explicit `return` statement, returns `None` on some code path, returns an empty list/dict, or the function's plugin logic intentionally yields no output for certain inputs. Also occurs when a function throws an exception that the bridge converts into a None result, or when the function is misconfigured and returns a void coroutine result.","solutions":["Ensure the registered kernel function always returns a non-empty, truthy value (a string, a KernelContent item, or a non-empty list) on every code path.","Inspect the function's implementation for branches that implicitly return None and add an explicit return with meaningful content.","If a no-op result is legitimate, wrap the return so the MCP client receives at least one TextContent instead of triggering the error.","Add logging/tests asserting the function returns a truthy FunctionResult for representative inputs before registering it as an MCP tool."],"exampleFix":"// before\n@kernel_function\nasync def summarize(text: str):\n    if not text:\n        return  # falsy -> MCP INTERNAL_ERROR\n    return llm.summarize(text)\n\n// after\n@kernel_function\nasync def summarize(text: str) -> str:\n    if not text:\n        return \"(nothing to summarize)\"\n    return llm.summarize(text)","handlingStrategy":"validation","validationCode":"async def safe_call(kernel, function_name, arguments):\n    result = await kernel.invoke(function_name, **arguments)\n    if not result or result.value is None or result.value == []:\n        # guarantee a non-empty payload before the MCP bridge sees it\n        return [\"(no result)\"]\n    return result\n\n# register only functions known to return truthy values","typeGuard":"def has_result(result) -> bool:\n    \"\"\"True when a FunctionResult is safe to expose over MCP.\"\"\"\n    return bool(result) and not (getattr(result, \"value\", None) in (None, [], \"\"))","tryCatchPattern":"from mcp.shared.exceptions import McpError\ntry:\n    out = await mcp_client.call_tool(\"my_tool\", {\"x\": 1})\nexcept McpError as e:\n    if \"returned no result\" in str(e):\n        # tool produced no output; degrade gracefully\n        out = []\n    else:\n        raise","preventionTips":["Annotate every kernel function exposed over MCP with a return type and a guaranteed non-empty return on all paths.","Unit-test each registered function for a truthy result across edge inputs (empty, None, boundary).","Before registering a plugin as MCP tools, run a smoke call per function and assert a non-empty response."],"tags":["mcp","kernel-function","tool-result","semantic-kernel"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}