Share what an Agents SDK run produced

Runner.run comes back. result.final_output holds the report. You print it, the terminal wraps four thousand lines, and the person who asked for the analysis is on Slack asking whether it is done.

Two ways in

A function tool is the shortest path:

from agents import Agent, Runner, function_tool
import httpx, os

@function_tool
def publish_report(title: str, html: str) -> str:
    """Publish an HTML report and return its shareable URL."""
    r = httpx.post(
        "https://commareports.com/api/v1/reports",
        headers={"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
        json={"title": title, "html": html},
    )
    r.raise_for_status()
    return r.json()["url"]

agent = Agent(
    name="analyst",
    instructions=(
        "Do the analysis, render it as a self-contained HTML report, "
        "publish it with publish_report, and return only the URL."
    ),
    tools=[publish_report],
)

An MCP server is the better path if you also use Comma from an editor, because it is the same endpoint and the same token:

from agents.mcp import MCPServerStreamableHttp

async with MCPServerStreamableHttp(
    params={
        "url": "https://commareports.com/api/mcp",
        "headers": {"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
    },
) as comma:
    agent = Agent(name="analyst", instructions=..., mcp_servers=[comma])

The tool list is discovered, so publishing, updating and reading comments all arrive without you writing wrappers for each. Setup shape is in MCP setup.

Make the URL part of the type

The SDK's structured outputs are the clean way to stop HTML from sloshing around your program:

class Analysis(BaseModel):
    summary: str
    report_url: str

agent = Agent(name="analyst", output_type=Analysis, tools=[publish_report])

Now final_output is a short object with an address in it. The document lives at the URL, the program handles a string, and nothing downstream has to decide what to do with four thousand lines of markup — the point of context budgeting for AI reports.

Handoffs: publish at the end, not everywhere

In a triage → research → writer chain, only the writer should hold the publish tool. Giving it to all three invites the triage agent to publish an introduction, and you end up with three reports where you wanted one.

Worth knowing

  • Guardrails run first. Anything that checks the output for policy should trip before the publish tool, not after.
  • Sessions make revisions natural. Keep the report id in session state and update it on the next turn, so one conversation produces one evolving report.
  • reports:write, plus comments:read for the review loop — see scoped tokens for AI agents.
  • 5 MB per report body.

Try it

Free — unlimited reports, commenters and revisions.

See MCP setup →

Related