microsoft/semantic-kernel · error · McpError
INTERNAL_ERROR
INTERNAL_ERROR
Error message
Function {function_name} returned no result What it means
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).
Source
Thrown at python/semantic_kernel/connectors/mcp.py:1158
match item:
case (
TextContent() | ImageContent() | BinaryContent() | AudioContent() | ChatMessageContent()
):
messages.extend(_kernel_content_to_mcp_content_types(item))
case _:
messages.append(
types.TextContent(type="text", text=str(item)),
)
else:
match value:
case TextContent() | ImageContent() | BinaryContent() | AudioContent() | ChatMessageContent():
messages.extend(_kernel_content_to_mcp_content_types(value))
case _:
messages.append(
types.TextContent(type="text", text=str(value)),
)
return messages
raise McpError(
error=types.ErrorData(
code=types.INTERNAL_ERROR,
message=f"Function {function_name} returned no result",
),
)
if prompts:
@server.list_prompts()
async def _list_prompts() -> list[types.Prompt]:
"""List all prompts in the kernel."""
mcp_prompts = []
for prompt in prompts:
mcp_prompts.append(
types.Prompt(
name=prompt.prompt_template_config.name,
description=prompt.prompt_template_config.description,
arguments=[View on GitHub (pinned to c028a0c7dc)
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.
Example fix
// before
@kernel_function
async def summarize(text: str):
if not text:
return # falsy -> MCP INTERNAL_ERROR
return llm.summarize(text)
// after
@kernel_function
async def summarize(text: str) -> str:
if not text:
return "(nothing to summarize)"
return llm.summarize(text) Defensive patterns
Strategy: validation
Validate before calling
async def safe_call(kernel, function_name, arguments):
result = await kernel.invoke(function_name, **arguments)
if not result or result.value is None or result.value == []:
# guarantee a non-empty payload before the MCP bridge sees it
return ["(no result)"]
return result
# register only functions known to return truthy values Type guard
def has_result(result) -> bool:
"""True when a FunctionResult is safe to expose over MCP."""
return bool(result) and not (getattr(result, "value", None) in (None, [], "")) Try / catch
from mcp.shared.exceptions import McpError
try:
out = await mcp_client.call_tool("my_tool", {"x": 1})
except McpError as e:
if "returned no result" in str(e):
# tool produced no output; degrade gracefully
out = []
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Request context is required for sampling function.
- Configuration not found, please setup the notebooks first us
- AZURE_OPENAI_ENDPOINT is not set.
- AZURE_OPENAI_ENDPOINT is not set.
- AZURE_OPENAI_ENDPOINT is not set.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/b1c92fdfc768c93f.
Report an issue: GitHub.