Install
Cursor reads MCP servers from .cursor/mcp.json in the project, or from the global
file in your home directory. Add the entry:
{
"mcpServers": {
"opentree": {
"type": "http",
"url": "https://read.botook.ai/mcp",
"headers": { "Authorization": "Bearer otr_live_YOUR_KEY" }
}
}
}Then restart the editor — Cursor loads servers at startup, and you will be prompted to trust the new one the first time it is called. Confirm it registered under Settings → MCP; the server should list twelve tools.
A local process instead of an HTTP header works too:
npx -y opentree-mcpGet the key first
Keys live in the dashboard, carry the otr_live_ prefix and
are displayed once. Revoke one without disturbing the others:
curl -X POST https://read.botook.ai/api-keys \
-H "Authorization: Bearer otr_live_EXISTING_KEY" \
-H "content-type: application/json" -d '{"name":"cursor"}'Publish what the editor just wrote
publish_html({
content: "<!doctype html><title>Q3 review</title>…",
expires_in_hours: 168,
password: "optional",
agentation: true
})Ask in the chat: publish this as a private link that expires in two days. The agent calls the tool, the reply carries the URL, and the file never leaves the editor as an attachment.
The link survives the rewrite
Cursor rarely gets a page right the first time. update_site replaces the content
behind the existing entry, so the address stays stable across every revision:
update_site({ site_id: "…", content: "<!doctype html>…" })Publish the whole build
cd dist && zip -r ../site.zip . && cd ..
curl -X POST https://read.botook.ai/sites \
-H "Authorization: Bearer otr_live_YOUR_KEY" -F file=@site.zipThe archive is unpacked on the way in and served as a tree, with index.html as
the entry point.
Put a rule in the project
So the model reaches for the right tool without being told twice, drop this in
.cursor/rules/publish.mdc:
---
description: How to share a page with someone outside the repo
alwaysApply: false
---
When asked to share a page, call publish_html on the opentree server.
Never paste HTML into the chat as a fallback. Set expires_in_hours to 168
unless told otherwise, and report only the returned URL.Access before it leaves your machine
set_password({ site_id: "…", password: "hunter2" })
set_email_gate({ site_id: "…", allowed_email_domain: "client.com" })An email gate sends a one-time link to a work address and refuses everything else — the right default when the audience is a client rather than a teammate.
Feedback comes back into the editor
Enable the on-page toolbar and the comments a reviewer leaves are readable as structured input on the next turn:
list_feedback({ site_id: "…", unresolved_only: true })Without the server
curl -X POST https://read.botook.ai/sites \
-H "Authorization: Bearer otr_live_YOUR_KEY" \
-F file=@index.htmlMore than HTML comes out of an editor
A repository is full of things worth sending to someone who will never clone it — a
README, an architecture diagram, a coverage report. Each has a direct route in:
| In the repo | Sent as | Served as |
|---|---|---|
NOTES.md | content-type: text/markdown | A rendered, self-contained document |
docs/arch.svg | -F file=@docs/arch.svg | The image, byte-for-byte |
coverage/ | -F file=@coverage.zip | The tree, entry at index.html |
dist/index.html | -F file=@dist/index.html | The page, as built |
curl -X POST https://read.botook.ai/sites \
-H "Authorization: Bearer otr_live_YOUR_KEY" \
-H "content-type: text/markdown" \
--data-binary @README.mdWhat the recipient actually gets
One URL, one click, no account, no download, no file:// that renders differently
on their machine than on yours. With agentation enabled there is a toolbar for notes;
with reactions there is an emoji row. Paste the link into a chat app and the unfurl
shows a screenshot of the page — except on a gated page, where it is a placeholder card on purpose.
Reading engagement back into the editor
The same key that published can ask how the page was read, without leaving the terminal pane:
curl -s https://read.botook.ai/sites/SITE_ID/engagement \
-H "Authorization: Bearer otr_live_YOUR_KEY" | jq '{opens,unique_viewers,read_to_end}'Aggregate counters only — opens, unique_viewers, dwell, ten scroll
buckets, read_to_end. Nothing per-visitor, nothing replayable.
Housekeeping
Editor sessions generate drafts fast. List what this key owns and delete the ones that are done; the rest expire by themselves after seven days:
curl -s https://read.botook.ai/sites -H "Authorization: Bearer otr_live_YOUR_KEY" | jq '.sites[] | {id,title}'
curl -X DELETE https://read.botook.ai/sites/SITE_ID -H "Authorization: Bearer otr_live_YOUR_KEY"Questions
The tools do not show up.
Cursor reads the config at startup. Restart, then check
Settings → MCP. A 401 in the tool output means the key is wrong or revoked.
Can I use one key across machines?
You can, but a key per client is easier to revoke. Mint one for the laptop and one for CI.
Does this replace my host?
No. It hosts documents and single-file tools. Applications with a server side still deploy normally — see the use cases.