OpenTree DashboardSign in

$ mcp list

Every agent that can write HTML can publish it here

One MCP server, one API key, twelve tools. Claude Code, OpenAI Codex, Cursor, the Claude.ai connector, a Slack workflow or a shell script — they all land on the same account and the same private links.

The one-line version

The integration is a model context protocol server spoken over Streamable HTTP. Point a client at https://read.botook.ai/mcp with a bearer key and the twelve tools appear. For clients that prefer a local process, the same server ships as a stdio package you run with npx:

npx -y opentree-mcp

No package at all is also fine — every tool is an ordinary HTTP endpoint underneath, so curl is a complete integration.

Pick your client

What the agent gets

ToolWhat it does
publish_htmlPublish a document and get back an unlisted URL.
update_siteReplace the content behind an existing URL, in place.
get_siteRead one site's settings, counters and share URL.
list_sitesList everything the calling key owns.
delete_siteHard-delete the record and the stored bytes.
set_passwordPut a passphrase in front of the page, or clear it.
set_expiryMove the expiry, or pin the link open forever.
set_email_gateRestrict opens to one work-email domain.
set_agentationTurn the on-page toolbar (notes, reactions, feedback) on or off.
list_feedbackRead what viewers left, newest first.
resolve_feedbackMark one piece of feedback handled.
link_walletAttach a wallet identity to the account that owns a page.

Register the server

For a terminal client:

claude mcp add --transport http opentree https://read.botook.ai/mcp \
  --header "Authorization: Bearer otr_live_YOUR_KEY"

For a client that reads a JSON config file:

{
  "mcpServers": {
    "opentree": {
      "type": "http",
      "url": "https://read.botook.ai/mcp",
      "headers": { "Authorization": "Bearer otr_live_YOUR_KEY" }
    }
  }
}

Create the key first — the dashboard mints keys with the otr_live_ prefix and shows each one exactly once.

Two ways to authenticate

A bearer API key is right for anything you configure yourself. A hosted client that registers itself gets the full OAuth 2.1 authorization-code flow with PKCE, including dynamic client registration — that is what the Claude.ai connector uses, and it means you never paste a secret into someone else's server.

curl -s https://read.botook.ai/.well-known/oauth-authorization-server | jq .

The publish call, in every client

Whatever the client, the tool call is the same shape:

publish_html({
  content: "<!doctype html><title>Q3 review</title>…",
  expires_in_hours: 168,
  password: "optional",
  agentation: true
})

The response carries the site id, the unlisted URL and the preview image URL. Re-run update_site on the same id and the link keeps pointing at the newest bytes.

No client, no install

curl -X POST https://read.botook.ai/v1/publish -F file=@index.html

Anonymous publishes need no account at all. With a key it is the same call plus a header:

curl -X POST https://read.botook.ai/sites \
  -H "Authorization: Bearer otr_live_YOUR_KEY" \
  -F file=@index.html

What comes back to you

Agent identity and wallets

link_wallet attaches a wallet identity to the account that owns a page, so an autonomous agent has something durable to be recognised by. This deployment does not charge per call, so nothing is settled on-chain — see agent payments for why that machinery is deliberately absent here.

Human in the loop, where it belongs

Agents publish; people decide. The dashboard is where a human claims an anonymous link, sets a password, moves a page onto a custom domain, or deletes it outright. Nothing about the agent path requires you to be watching it.

Formats an agent can hand over

An agent should not have to convert anything before it publishes. Four shapes go in, and the conversion — where there is one — happens once, at publish time, not on every read:

What the agent sendsWhat gets storedWhat the reader opens
A complete HTML documentThe bytes, untouchedThe page exactly as written
MarkdownA self-contained HTML document, rendered on the way inA readable document, not a screenful of asterisks
An SVG diagramThe bytes, untouchedThe image, served as image/svg+xml
A zip of a build directoryThe tree, unpackedindex.html plus every relative asset

Because the rendering is done before storage, every downstream reader agrees with every other one: /raw/:token, the preview card and the extracted title all read the same stored document. Nothing renders differently depending on who asked.

Troubleshooting

SymptomCauseFix
Tools do not appearClient never completed the handshakeRestart the client; check the URL ends in /mcp
401 on every callMissing or revoked keyMint a new key in the dashboard; keys are shown once
403 pii_detectedThe scan found sensitive dataRe-publish with pii_check set to warn
429Anonymous rate limit per addressUse a key — keyed publishes are not rate-limited here

Keep reading