---
title: "Publish from an AI agent"
description: "How an AI agent (Claude, an MCP tool, or any LLM app) can publish to social media through Dravo."
section: "Guides"
url: https://dravo.dev/docs/guides/publish-from-ai-agent
---
# Publish from an AI agent

## Why Dravo suits agents

An agent does best with one predictable contract and machine readable failures.
Dravo gives both: a single publish call for every network, and
[errors](/docs/concepts/errors) that name what to fix. There is also a raw
Markdown mirror of every docs page (the View .md button at the top of each page),
which is easy for an LLM to ingest.

## The minimal loop

Give the agent exactly one capability: publish text (and optional media) to a set
of accounts.

```js
async function publish({ accountIds, text, mediaUrls = [] }) {
  const res = await fetch("https://api.dravo.dev/v1/publish", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.DRAVO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ account_ids: accountIds, text, media_urls: mediaUrls }),
  });
  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.detail); // actionable message the agent can act on
  }
  return res.json(); // { job_id, status }
}
```

## Reading errors and retrying

When a request is rejected, the body contains a `detail` string describing the
problem (for example a missing field or text over the limit). An agent should
parse it, adjust the input, and retry. When a job is accepted but a single
account fails, the per account result carries a stable `error_code` plus a human
message, so the agent can decide whether to retry that account or skip it. See
[handling partial failures](/docs/guides/handling-partial-failures).

## As an MCP tool

Wrap the publish call as a single MCP tool named something like `publish_post`
with inputs `account_ids`, `text` and `media_urls`. Keep the surface tiny: one
tool, clear inputs, and let Dravo's response drive the agent's next step. Point
the model at the raw docs (`/docs/quickstart.md`) so it knows the contract.
