Skip to content

Response limiter drops structuredContent for large successful tool results #70

Description

@tony

Problem

Large successful tool results with output schemas can become protocol-invalid after response limiting.

FastMCP stores structured output in both content and structuredContent, then the response limiter measures the serialized whole result. libtmux-mcp uses a 50 KB backstop on large-output tools. When the limiter fires, the returned result can lose structuredContent, and FastMCP clients raise:

RuntimeError: Tool capture_pane has an output schema but did not return structured content

Minimal local reproduction

$ uv run python - <<'PY'
import asyncio
import uuid
from fastmcp import Client
from libtmux_mcp.server import build_mcp_server
from libtmux_mcp._utils import _get_server

async def main():
    socket_name = f"limit_{uuid.uuid4().hex[:8]}"
    server = _get_server(socket_name=socket_name)
    session = server.new_session(session_name="limit", kill_session=True, attach=False)
    pane = session.active_pane
    try:
        pane.send_keys("for i in $(seq 1 1400); do printf 'line%04d xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\\n' $i; done", enter=True)
        await asyncio.sleep(1.5)
        async with Client(build_mcp_server()) as client:
            await client.call_tool("capture_pane", {
                "pane_id": pane.pane_id,
                "socket_name": socket_name,
                "start": -1400,
                "max_lines": None,
            })
    finally:
        server.kill()

asyncio.run(main())
PY

Expected today: the client raises because the truncated response has no structured content.

Upstream mechanism

Minimal fix

Do not truncate schema-bearing success results into text-only results.

Preferred minimal path:

  • Raise the middleware backstop above every tool-level cap.
  • Keep truncation inside each tool's structured model fields (truncated, content, lines, etc.).
  • Preserve structuredContent for all successful output-schema tools.

Acceptance criteria

  • Large capture_pane, capture_since, snapshot_pane, and search_panes calls return valid structured content.
  • FastMCP Client.call_tool() does not raise for large successful captures.
  • Tests cover a large successful schema-bearing result through the client path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions