Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/mcp/server/mcpserver/utilities/func_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,9 @@ def _convert_to_content(result: Any) -> list[ContentBlock]:
return [result.to_audio_content()]

if isinstance(result, list | tuple):
if not result:
return [TextContent(type="text", text="[]" if isinstance(result, list) else "()")]

return list(
chain.from_iterable(
_convert_to_content(item)
Expand Down
21 changes: 21 additions & 0 deletions tests/interaction/mcpserver/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,24 @@ async def collect(message: IncomingMessage) -> None:
assert received == snapshot(
[LoggingMessageNotification(params=LoggingMessageNotificationParams(level="info", data="tool set changed"))]
)


async def test_tool_returning_empty_list_and_tuple_produces_text_content(connect: Connect, unstamped: Unstamp) -> None:
"""A tool returning an empty list or tuple produces a TextContent block rather than zero content blocks."""
mcp = MCPServer("empty-tools")

@mcp.tool()
def get_empty_list() -> list[str]:
return []

@mcp.tool()
def get_empty_tuple() -> tuple[str, ...]:
return ()

async with connect(mcp) as client:
list_result = await client.call_tool("get_empty_list", {})
tuple_result = await client.call_tool("get_empty_tuple", {})

assert list_result.content == [TextContent(text="[]")]
assert tuple_result.content == [TextContent(text="()")]

20 changes: 20 additions & 0 deletions tests/server/mcpserver/test_func_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -1376,3 +1376,23 @@ def fn() -> StepA | StepB: ... # pragma: no branch

meta = func_metadata(fn)
assert meta.output_schema is None


def test_convert_to_content_empty_list_and_tuple():
from mcp.server.mcpserver.utilities.func_metadata import _convert_to_content

empty_list_res = _convert_to_content([])
assert len(empty_list_res) == 1
assert isinstance(empty_list_res[0], TextContent)
assert empty_list_res[0].text == "[]"

empty_tuple_res = _convert_to_content(())
assert len(empty_tuple_res) == 1
assert isinstance(empty_tuple_res[0], TextContent)
assert empty_tuple_res[0].text == "()"

non_empty_res = _convert_to_content(["hello", "world"])
assert len(non_empty_res) == 2
assert non_empty_res[0].text == "hello"
assert non_empty_res[1].text == "world"

Loading