Octopus.do
Leia e edite sitemaps visuais do octopus.do: páginas, blocos e notas de revisão, como o usuário conectado.
Documentação
Once connected, your agent can:
- See your work — list your projects and workspaces, and read the full structure of a sitemap (pages, blocks, colors, tags, symbols).
- Build and edit sitemaps — create and update pages, add content blocks with wireframes, restructure the page tree, apply several changes at once as a single atomic update.
- Read and leave review notes — read the comments on pages and blocks and the threads pinned to the canvas, add notes and replies, and resolve or reopen a thread. A note left by an agent is authored by your account and looks exactly like one you typed, and posting it notifies nobody.
- Manage projects — create, duplicate, archive, move projects; transfer ownership; update project settings like theme and layout. Projects cannot be deleted over MCP — archiving is as far as an agent goes, and archives are reversible.
Every action runs as you — the agent only ever sees and changes what your Octopus.do account has access to.
Connecting
Endpoint
https://mcp.octopus.do/mcp
The general flow is the same in every client:
- Add Octopus as a remote MCP server / connector using the endpoint above.
- Choose OAuth as the authorization type — most clients detect this automatically.
- Sign in (or register) with your Octopus.do account when the browser opens.
- Ask your agent to do something — e.g. “show my Octopus projects” or “add a pricing page to my sitemap.”
No API keys to copy or manage — authorization happens through your normal Octopus.do login. Client-specific instructions below.
Claude (web and desktop)
- Go to Settings → Connectors → Add custom connector.
- Enter
https://mcp.octopus.do/mcpas the URL and click Add. - Click Connect and sign in with your Octopus.do account.
Claude Code
Run in your terminal:
claude mcp add --transport http octopus https://mcp.octopus.do/mcp
Then run /mcp inside Claude Code to complete the sign-in.
Cursor
Add Octopus.do to Cursor — opens Cursor with the server already filled in.
Or add it by hand to ~/.cursor/mcp.json (use .cursor/mcp.json to scope it to one project):
{
"mcpServers": {
"octopus": {
"url": "https://mcp.octopus.do/mcp"
}
}
}
Cursor will prompt you to authenticate the first time the server is used.
VS Code (GitHub Copilot)
Run MCP: Add Server from the Command Palette and choose HTTP, or add to .vscode/mcp.json:
{
"servers": {
"octopus": {
"type": "http",
"url": "https://mcp.octopus.do/mcp"
}
}
}
ChatGPT
Octopus.do is published in the ChatGPT app directory: search for Octopus.do under Settings → Apps & Connectors and press Connect. Requires ChatGPT Plus or higher. Full walkthrough: Octopus.do for ChatGPT.
To add the MCP endpoint by hand instead — for a dev environment, or a workspace where the app isn't available — turn on developer mode (Settings → Apps & Connectors → Advanced settings) and:
- Go to Settings → Apps & Connectors → Create (or Add connector).
- Set the MCP server URL to
https://mcp.octopus.do/mcpand authentication to OAuth. - Complete the Octopus.do sign-in when prompted.
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"octopus": {
"serverUrl": "https://mcp.octopus.do/mcp"
}
}
}
Grok
- Open grok.com → Connectors, click New Connector, then Custom.
- Enter
https://mcp.octopus.do/mcpas the MCP server URL. - Complete the Octopus.do sign-in when prompted.
Custom connectors are a paid-plan feature in Grok. On Business and Enterprise plans a team admin has to provision the connector in the xAI cloud console before members can add it.
Gemini
- Open gemini.google.com → Settings & help → Connected Apps.
- Under Custom apps for Spark, add
https://mcp.octopus.do/mcpas the MCP server URL. - Complete the Octopus.do sign-in when prompted.
Custom apps require Gemini Spark on a personal Google Account — Workspace accounts cannot add them — and Google currently limits the feature to users in the United States, in English, from the Gemini web app. Once connected, it works in the mobile apps as well.
Other MCP clients
Any client that supports remote MCP servers (Streamable HTTP) with OAuth works: point it at https://mcp.octopus.do/mcp, pick OAuth, and sign in with your Octopus.do account.
Authentication
Octopus MCP uses OAuth 2.1, the standard MCP clients use for secure, per-user authorization. Your agent requests access on your behalf, you approve it once during sign-in, and access can be revoked from your Octopus.do account at any time. The MCP server itself never sees or stores your password.
Available tools
Your agent picks these tools on its own — you don’t call them directly. The reference below is useful when you want to know exactly what the agent can (and can’t) do, or to phrase a request precisely.
Most write tools accept an optional idempotency_key (string): a unique key that makes retries safe — a repeated request with the same key is applied only once. It’s omitted from the tables below.
Destructive actions (like deleting a page, a block or a comment) are flagged to your AI client, which will typically confirm with you before running them.
Reading
get_me
Returns your account name. No parameters.
list_projects
Lists the projects you can access, across every workspace (personal and teams), most recently updated first. Each item includes the workspace it belongs to. One page at a time: total is how many matched and has_more whether any were left out. To find one project by name use q rather than paging — it searches every project on the account, not just the current page.
| Field | Required | Type | Description |
|---|---|---|---|
q | No | string | Only projects whose title contains this, case-insensitively |
workspace_uuid | No | string | Only this workspace. Use the literal "my" for your personal workspace |
limit | No | number | How many to return, 1–200 (default 50) |
offset | No | number | How many to skip; for paging |
list_workspaces
Lists your workspaces (personal + teams) with their folders and the 10 most recently updated projects in each — project_count gives the real total, and list_projects searches and pages through the rest. No parameters.
get_workspace
Returns one workspace: info, folders, and projects.
| Field | Required | Type | Description |
|---|---|---|---|
uuid | Yes | string | Workspace uuid. Use the literal "my" for your personal workspace. |
get_project
Returns the state of one project: the entities (tabs, sections, nodes = pages, blocks, colors, tags, symbols, arrows, …) and the parent/child tree linking them. A whole sitemap is a large read, so start with view: "outline" and narrow further with scope_id when you only need one branch. A page’s notes come back in camelCase (seoTitle, pageIntent) although writes name them snake_case — see Notes field names.
On the Team plan a workspace can keep a shared symbol library, and projects reference symbols from it rather than owning them. Those references come back resolved — the symbol reads like any other, with an extra libraryId marking where its title, wireframes and default content live. Such a symbol cannot be edited through symbols.update (the call is refused): it is shared by every project of the workspace and is edited in the library itself, in the editor. Deleting it from one project is allowed and leaves the library untouched.
| Field | Required | Type | Description |
|---|---|---|---|
project_uuid | Yes | string | Project uuid. uuid is accepted as a synonym, so a call written either way works |
view | No | enum | outline (default) — the page tree with titles, urls and ids, an order of magnitude cheaper; full — page content as well |
scope_id | No | string | Read one branch instead of the project: a tab, section or page id. The response carries the chain of ancestors, so the branch keeps its context |
exclude | No | array | Content groups to drop — blocks, content, notes, styling, tags, estimates, overlays, meta |
include | No | array | Content groups to add back to the default outline view, from the same list as exclude — include: ["estimates"] returns the page tree with the estimate rate card (the lineItems ids needed to write values) without paying for view: "full". Ignored when view is full; exclude wins on a group named in both |
format | No | enum | nested (default) — the tree; plain — flat collections plus the relations graph |
list_comments
Reads the review notes on a project. There are two kinds and one call returns both: flat comments left on pages and on content blocks (thread replies are comments too), and canvas threads — the pins on the sitemap canvas, which carry a position and an open/resolved state. The result has a comments array and a threads array; whichever was not asked for comes back empty. Threads default to the open ones, so the default answer is what is still outstanding rather than everything ever written.
No access shows up differently depending on what was asked for. A default call reads both halves, and the threads half is refused outright, so the whole call fails and says so. A comments-only call (a kind of page, block or reply) gets an empty list instead — the underlying endpoint answers 200 with nothing rather than a 403, and no caller can tell that from a project that simply has no notes.
Both halves name what they point at: a comment’s target and a thread’s anchor carry a title beside the id, so a note can be read without pulling the whole project down to look the id up. For a page or a tab that is its title; for a block it is the block’s name. title is null in four ordinary cases, none of them an error: the pin is an orphan (below); the note is a reply, whose target is a thread and threads have no title of their own; the page is simply untitled; or the project tree could not be read, which costs the titles and nothing else — a comments-only call on a project you cannot read still answers with an empty list rather than an error, exactly as before.
An anchor.type of null on a thread means the page or tab it was pinned to has been deleted and the pin outlived it — orphaned pins are normal. content is markdown, whatever format the editor stored the note in, so the assistant reads a review note as text rather than as an editor document. author is { id, name, avatar } — the writer's name and photo beside a stable id, and null when the note was left by an anonymous commenter; the avatar url is public. On an anonymous comment, guest_name is the name the visitor typed for themselves — unverified, so the assistant is told to say "someone calling themselves X" rather than "X" — or null when they gave none. A thread carries it on the same terms as a comment — the visitor is asked for a name when they drop the pin — and it is null on pins dropped before the editor started asking, which reads the same as a visitor who gave none.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
kind | Não | enum | page | block | reply | thread. Omita para comentários de todos os tipos e threads juntos; thread retorna apenas threads |
target_id | Não | string | Apenas notas neste id — um id de página, um id de bloco ou um id de thread, que retorna as respostas dessa thread |
resolved | Não | boolean | Apenas threads. Omita para threads abertas, true para as resolvidas |
include_replies | Não | boolean | Incorpora as respostas de cada thread na própria thread (padrão falso) |
Edição
apply_changes
Aplica várias operações de edição a um projeto como uma única alteração atômica — a forma preferida de construir ou reestruturar um sitemap. As operações são executadas em ordem e cada uma vê o efeito das anteriores. Dê a uma entidade criada um ref e faça referência a ela em operações posteriores via parent_ref / node_ref em vez de um id.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
operations | Sim | array | Pelo menos uma operação (veja abaixo) |
dry_run | Não | boolean | Apenas validar e visualizar — nada é alterado |
idempotency_key | Não | string | Repetir uma chamada com a mesma chave aplica-a apenas uma vez |
Cada operação:
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
operation | Sim | string | Nome da operação, ex.: "nodes.create" |
ref | Não | string | Nome local para a entidade criada, referenciado por operações posteriores via campos *_ref |
data | Não | object | Payload da operação — mesmos campos da ferramenta autônoma correspondente |
Há dois limites em um lote, e apenas um deles é nosso. A API limita uma chamada a 100 operações. Separadamente, o cliente de IA que hospeda a conexão limita o tamanho dos argumentos de uma única chamada de ferramenta, e acima de aproximadamente 15–20 KB de JSON alguns clientes os truncam. Uma chamada truncada não chega como um lote menor — chega como JSON quebrado, e o erro diz que os argumentos não puderam ser analisados como JSON. Isso não é um erro de sintaxe no que você enviou, e tentar novamente sem alterações não ajudará: divida o trabalho em vários lotes menores por tamanho, não apenas por contagem de operações. Não há limite de bytes no lado do Octopus, então o teto exato depende do cliente.
Uma resposta bem-sucedida também pode conter warnings — notas consultivas, como uma página cuja url não está sob o caminho do pai. Nada foi bloqueado e nenhuma nova tentativa é necessária; elas estão lá para serem lidas, não para ação automática.
Os nomes das operações seguem group.action:
| Grupo | Ações |
|---|---|
nodes | create, update, move, delete, clone, collapse, replace_url_prefix |
sections | create, update, delete, clone, collapse, move_up, move_down |
tabs | create, update, delete, clone |
blocks | create, update, replace_text, move, delete, clone |
tags | create, update, delete, assign_node, unassign_node |
colors | create, update, delete |
symbols | create, update, delete |
sticky_notes | create, update, delete, clone |
arrows | create, update, delete |
estimates | add_line_item, update_line_item, delete_line_item, set_value, update_settings |
settings | update |
Ambas as metades do nome estão em snake_case — tags.assign_node, sections.move_up, nodes.replace_url_prefix. O endpoint REST para a mesma operação escreve seu caminho com hífens (/tags/assign-node); as duas formas não são intercambiáveis, e uma operação nomeada na forma de caminho é rejeitada.
Duas delas editam muitas entidades a partir de uma única operação, o que vale saber antes de escrever oitenta de algo. nodes.replace_url_prefix {from, to, scope_id?} reescreve o início de cada url de página correspondente; blocks.replace_text {from, to, scope_id?} substitui uma string literal dentro do conteúdo do bloco sem reenviar o conteúdo — a forma de corrigir uma palavra em todo um site. Ambas correspondem literalmente e com distinção entre maiúsculas e minúsculas, em vez de por padrão, ambas aceitam um scope_id (uma aba, seção ou página — e para blocks.replace_text, um único bloco) que padroniza para o projeto inteiro, e ambas falham se nada corresponder em vez de responder sucesso: uma reescrita que não atingiu nada é algo para saber, não para seguir em frente. Elas respondem com count e uma lista do que alteraram, limitada a 50 entradas e informando quando trunca. blocks.replace_text ignora instâncias de símbolo, cujo conteúdo pertence ao símbolo, e informa quantas ignorou.
Estimativas são editáveis via MCP: estimates.add_line_item e estimates.update_line_item constroem a tabela de preços, estimates.set_value coloca uma quantidade de unidades em uma página para uma de suas linhas (a primeira chamada para um par página/linha cria o valor, as posteriores o atualizam), estimates.delete_line_item remove uma linha com os valores por página, e estimates.update_settings define moeda, unidades, imposto e visibilidade. Todas as cinco precisam do proprietário do projeto no plano Pro ou superior, e hidden — uma estimativa privada — precisa do Team.
A API REST ainda tem algumas operações que o servidor MCP deliberadamente não oferece — reordenação de abas, vinculação de símbolos e links externos. Elas permanecem disponíveis via a API Pública.
create_node
Cria uma página (nó) no sitemap.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
parent_id | Sim | string | Id do pai — uma aba, seção ou outro nó (ids vêm de get_project) |
title | Não | string | Título da página |
color_id | Não | string | Id da cor do projeto; padroniza para o padrão do projeto |
url | Não | string | URL/slug da página mostrada no nó |
variant | Não | enum | default | frame | ghost | stack |
after_id | Não | string | Coloque-o diretamente após este irmão — nomeie um vizinho em vez de contar posições |
before_id | Não | string | Coloque-o diretamente antes deste irmão |
index | Não | number | Posição absoluta entre os filhos do pai; omita para anexar |
update_node
Atualiza campos da página.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
id | Sim | string | Id do nó |
title | Não | string | Novo título |
color_id | Não | string | Id da cor do projeto; default redefine para o padrão do projeto |
url | Não | string | null | URL/slug da página; null limpa — uma string vazia é rejeitada |
variant | Não | enum | default | frame | ghost | stack |
notes | Não | object | Campos de SEO/notas para mesclar: note, keywords, page_intent, seo_title, seo_description, seo_h1, seo_slug, seo_url. Um campo omitido mantém seu valor atual. Escrito em snake_case, lido de volta em camelCase — veja a tabela abaixo |
Os campos de notas são escritos em snake_case e lidos de volta em camelCase. Os nomes à esquerda são o que update_node e a operação em lote nodes.update aceitam; os nomes à direita são o que get_project retorna dentro do notes de uma página:
| Escrito | Lido de volta |
|---|---|
note | note |
keywords | keywords |
page_intent | pageIntent |
seo_title | seoTitle |
seo_description | seoDescription |
seo_h1 | seoH1 |
seo_slug | seoSlug |
seo_url | seoUrl |
Cada par é um campo sob duas grafias, não dois campos. Uma escrita bem-sucedida seguida de uma leitura que não mostra seo_title é este mapeamento e não dados perdidos — procure por seoTitle. Ambas as grafias permanecem como estão: normalizar qualquer lado quebraria os clientes que já leem o outro.
move_node
Move uma página com toda a sua subárvore para outro pai.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
id | Sim | string | Id do nó a mover |
parent_id | Sim | string | Novo pai (aba, seção ou nó) — não o próprio nó ou sua subárvore |
after_id | Não | string | Coloque-o diretamente após este irmão — nomeie um vizinho em vez de contar posições |
before_id | Não | string | Coloque-o diretamente antes deste irmão |
index | Não | number | Posição entre os filhos do novo pai |
delete_node
Exclui uma página com toda a sua subárvore e todos os blocos dentro.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
id | Sim | string | Id do nó |
create_block
Cria um bloco de conteúdo dentro de uma página.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
node_id | Sim | string | Id da página (nó) em que o bloco é criado |
title | Não | string | Título do bloco |
content | Não | string | Conteúdo de texto do bloco |
wireframes | Não | string[] | Nomes de wireframe para renderizar, ex.: ["header"], ["text"], ["footer"] |
color_id | Não | string | Id da cor do projeto |
index | Não | number | Posição dentro da página; omita para anexar |
update_block
Atualiza campos do bloco.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
id | Sim | string | Id do bloco |
title | Não | string | Novo título |
content | Não | string | Conteúdo de texto do bloco |
color_id | Não | string | Id da cor do projeto; default redefine para o padrão do projeto |
wireframes | Não | string[] | Nomes de wireframe para renderizar |
collapsed | Não | boolean | Recolher/expandir o bloco |
completed | Não | boolean | Marcar o bloco como concluído/não concluído |
move_block
Move um bloco para outra página.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
id | Sim | string | Id do bloco a mover |
node_id | Sim | string | Id da página (nó) de destino |
index | Não | number | Posição dentro da página de destino |
delete_block
Exclui um bloco de sua página.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | UUID do projeto |
id | Sim | string | Id do bloco |
manage_comment
Adiciona, exclui, resolve e reabre comentários e threads de canvas. Uma nota adicionada desta forma é de autoria da conta com a qual a conexão está conectada, sem nenhum marcador de qualquer tipo — no editor, é indistinguível de uma que essa pessoa digitou — e não notifica ninguém, porque nenhuma menção é enviada.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | uuid do projeto |
action | Sim | enum | add | delete | resolve | reopen |
target | Sim (add) | object | add: onde a nota se fixa — { "type": "page" | "block" | "tab" | "thread", "id": "…" } |
content | Sim (add) | string | add: o corpo da nota; não pode estar vazio. Envie texto simples — ele é envolvido em um documento de editor, um parágrafo por linha, e é renderizado da forma que uma pessoa digitando esperaria. Não construa esse documento você mesmo; um que você já tenha é armazenado intacto |
position | Não | object | add: a posição do pino, { "x": 0, "y": 0 } — fornecê-lo solicita um pino em vez de uma nota simples. Veja a tabela abaixo |
id | Sim (delete, resolve, reopen) | string | O id do comentário ou id do tópico no qual agir |
O que add cria depende do tipo de destino e se um position é fornecido:
| Tipo de destino | position | O que é criado |
|---|---|---|
page | omitido | Uma nota na página |
page | fornecido | Um pino de canvas nessa página — um tópico |
block | omitido | Uma nota no bloco de conteúdo |
block | fornecido | Recusado — um bloco nunca pode conter um pino de canvas. Remova position, ou fixe na página em vez disso |
tab | qualquer | Um pino de canvas no canvas vazio dessa aba — um tópico |
thread | omitido | Uma resposta nesse tópico |
thread | fornecido | Recusado — uma resposta não tem posição própria |
Cada id é verificado contra o projeto antes que qualquer coisa seja escrita — em add, em delete, e em resolve e reopen igualmente — então um id que o projeto não contém falha em vez de criar uma nota anexada a nada ou fechar um tópico em outro lugar. Um id do tipo errado, um id de bloco fornecido como página, por exemplo, é recusado com o tipo real do id nomeado. Nenhum dos dois vale uma nova tentativa: a correção é reler os ids.
Apenas tópicos de canvas têm um estado resolvido, então resolve e reopen aceitam um id de tópico — um comentário de página ou bloco não pode ser resolvido de forma alguma. delete aceita um id de comentário ou um id de tópico e descobre qual é, então o chamador não precisa saber; excluir um tópico remove o pino, mas deixa suas respostas para trás, já que são comentários por direito próprio.
O opcional idempotency_key torna uma nova tentativa segura — a mesma chave enviada duas vezes adiciona uma nota, não duas. Ele não torna add idempotente: duas chamadas add com chaves diferentes adicionam duas notas. Em delete a chave é aceita e ignorada: não há nada a proteger, porque excluir o mesmo id duas vezes remove uma nota e depois relata que ela se foi.
Gerenciamento de projetos
create_project
Cria um novo projeto no workspace de destino. Pode falhar quando o limite de projetos do seu plano é atingido.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
workspace_id | Sim | string | Workspace de destino — um uuid de workspace de equipe, ou o literal "my" para seu espaço pessoal. Obrigatório; um valor vazio ou omitido é rejeitado com um erro. |
folder_id | Não | string | Id da pasta dentro do workspace de equipe |
manage_project
Ações do ciclo de vida do projeto: duplicar, arquivar/desarquivar, mover, transferir.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | uuid do projeto |
action | Sim | enum | duplicate | archive | unarchive | move | transfer |
workspace_id | Sim (move) | string | move: workspace de destino — um uuid de workspace de equipe, ou o literal "my" para seu espaço pessoal. Obrigatório para move; um valor vazio é rejeitado com um erro. |
folder_id | Não | string | move: id da pasta de destino |
email | Não | string | transfer: email do destinatário — deve ser um usuário registrado, sem plano gratuito |
update_project_settings
Atualiza as configurações de nível do projeto.
| Campo | Obrigatório | Tipo | Descrição |
|---|---|---|---|
project_uuid | Sim | string | uuid do projeto |
title | Não | string | Título do projeto |
theme | Não | enum | blueprint | bold | dark | light |
tree | Não | enum | Layout da árvore: map | matrix |
frame | Não | enum | Estilo do quadro do nó: mobile | neutral | web |
mobile | Não | boolean | Modo móvel |
image_mode | Não | boolean | Mostrar imagens nos nós |
legend_position | Não | enum | bottom | none | top |
default_color_id | Não | string | Cor padrão para novas páginas |
Saiba mais
- Octopus.do: https://octopus.do/
- Model Context Protocol: https://modelcontextprotocol.io/
- Octopus.do no Smithery: https://smithery.ai/servers/octopus-do/sitemaps