# Share Claude Agent SDK Output — Add Comma's MCP Server

Canonical: https://commareports.com/agents/share-claude-agent-sdk-output
Published: 2026-09-14

> A Claude Agent SDK run writes files into a sandbox you don't ship. Attach Comma's MCP server so query() ends with a report URL your reader can actually open.

# Share what a Claude Agent SDK run produced

The SDK gives an agent real tools — file access, bash, whatever you allow — so
it produces real artifacts. A migration plan, an audit, a rendered summary of
what it changed and why.

Then `query()` returns, the process exits, and the artifact is in a directory
that existed for the length of the run.

## Attach Comma as an MCP server

The SDK speaks MCP, and Comma is a remote server, so this is configuration
rather than code:

```python
from claude_agent_sdk import query, ClaudeAgentOptions

options = ClaudeAgentOptions(
    mcp_servers={
        "comma": {
            "type": "http",
            "url": "https://commareports.com/api/mcp",
            "headers": {"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
        }
    },
    system_prompt=(
        "When you finish work that someone needs to read, render it as a "
        "self-contained HTML report, publish it to Comma, and return the URL. "
        "Do not paste the HTML into your reply."
    ),
)

async for message in query(prompt=task, options=options):
    ...
```

The standing instruction in the system prompt is the part that makes this
stick. Without it the agent will publish when asked and write a local file when
not, which is the same inconsistency the
[project-level rule for Claude Code](/agents/share-claude-code-output) exists
to remove.

## Headless is the whole reason

An interactive run has a human at a terminal who can open a local file. A
scheduled or triggered run does not. The agent that reconciles yesterday's
data at 06:00 and writes `reconciliation.html` into its container has produced
nothing — the file and the container disappear together.

A URL survives the process. It is the same argument as
[publishing from CI](/ci), and the same reason
[routines](/docs/routines) exist for the schedule itself.

## Subagents publish once

If your run fans out — a researcher, a checker, a writer — publish from the
top-level agent after the subagents report back, not from each subagent. Five
subagents with publish access produce five reports and no agreement about
which one to read.

## The revision loop

Because comments are readable over the same MCP server, the second run is
better-informed than the first:

> Read the open comment threads on report `<id>`. Address each one, update the
> same report, and reply in each thread describing the change.

Updating rather than re-creating keeps every reviewer's thread attached to the
document it was about — see
[letting an agent respond to comments](/agents/let-an-agent-respond-to-comments).

## Worth knowing

- **Give the agent `reports:write` and nothing more** until you need the
  comment loop — see
  [scoped tokens for AI agents](/agents/scoped-tokens-for-ai-agents).
- **Return the URL, not the document.** A rendered report in the final message
  is context you pay for on every subsequent turn.
- **5 MB per report body.**
- **Report HTML renders sandboxed** — `allow-scripts`, no `allow-same-origin`.

## Try it

Free — unlimited reports, commenters and revisions.

**[See MCP setup →](/mcp)**

### Related

- [Share Claude Code output](/agents/share-claude-code-output) ·
  [Where should my agent post?](/agents/where-should-my-agent-post)
- [Share OpenAI Agents SDK output](/agents/share-openai-agents-sdk-output) ·
  [Share a Mastra agent's output](/agents/share-mastra-output)
- [MCP setup](/mcp) · [Routines](/docs/routines)
