Skip to content
DFL / MCP
esc
↑↓navigate ↵open ⌘↵copy tool name

Board

Read and edit the whiteboards of DFL Board: stickies, shapes, text, frames, groups, arrows, images, PDFs and markdown cards, plus the viewport, the presence of people and agents, and the board chat.

Endpoint
https://board.mcp.devfellowship.com/mcp
Tools
52 in 10 groups
Repo
devfellowship/dfl-board
Auth
Your dfl-auth login token as Authorization: Bearer <token>. Every call runs as you, under RLS. See Auth & security.

Connect

Add to your project's .mcp.json (or the global ~/.claude/mcp.json).

.mcp.json
{
"mcpServers": {
"dfl-board": {
"type": "http",
"url": "https://board.mcp.devfellowship.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}
}
}

Then restart Claude Code (or run /mcp to reconnect). You should see the dfl-board tools appear.

Other clients (Cursor, VS Code, codex, the Anthropic SDK): see Getting started, step 3.

Endpointhttps://board.mcp.devfellowship.com/mcp. Bearer token (dfl-auth login) or OAuth (browser sign-in and consent, scopes board.read and board.write), the same as the other hosts. The old URL https://boards.devfellowship.com/mcp is retired.
Served bypackages/dfl-mcp-board (the OAuth resource) in front of the board server, devfellowship/dfl-board, which runs every tool. Each call reaches the board server with your own token.
Source of this pageA committed snapshot of the host’s live tools/list (docs/external-hosts/board.tools-list.json). Refresh it with scripts/refresh-external-host.mjs board.
Not in the one DFL MCPThe gateway router does not route to this host. Connect it as its own server.

Find a board and read what is on it: the outline page by page, a search, one item with its neighbours, the items of a frame, and the recent operations.

archive_board

Archive a board you own. It deletes nothing: the board and its items stay, get_board still reads it, and list_boards hides it unless include_archived is true.write

archive board

Archive a board you own. It deletes nothing: the board and its items stay, get_board still reads it, and list_boards hides it unless include_archived is true. Returns {id, slug, archived_at}. A second call keeps the first archived_at. Only the owner may archive; another caller gets forbidden.

ParameterTypeRequiredDescription
boardstringyes—

create_board

Create an empty board. You become its owner.write

create board

Create an empty board. You become its owner. Returns {id, slug, name, visibility, url}. Without slug the server makes one from the name, with a short suffix when it is taken. With slug, a taken slug fails with slug_conflict and writes nothing, so send your own slug when you may retry after a timeout.

ParameterTypeRequiredDescription
namestringyes—
slugstringno—
settingsobjectno—

list_boards

Read visible boards with live item counts.read

list boards

Read visible boards with live item counts. Query matches literal name or slug substrings before the limit; case folding is ASCII-only. Archived boards are hidden unless include_archived is true; an archived board carries archived_at.

ParameterTypeRequiredDescription
limitnumbernoDefault: 50.
querystringno—
include_archivedbooleannoDefault: false.

get_board

Read current board metadata, live item bounds/count, and deduplicated active authenticated subscribers or unexpired agent activity leases.read

get board

Read current board metadata, live item bounds/count, and deduplicated active authenticated subscribers or unexpired agent activity leases. Empty bounds are null.

ParameterTypeRequiredDescription
boardstringyes—

get_board_outline

Read one page of outline rows in deterministic location order: {items, next_offset}.read

get board outline

Read one page of outline rows in deterministic location order: {items, next_offset}. Each row carries text, the visible text of the item (props.text, the bound label of a shape or sticky, or a frame title, with inline marks removed; absent when the item has none), cut after 200 characters with a trailing "…" and text_truncated: true when longer (the same rule as neighbours_summary) (text_truncated is absent otherwise); get_item returns the full text. Each page is at most 30,000 bytes of JSON and can hold fewer than limit (default 200) rows: long texts make a page shorter, never larger. Call again with offset=next_offset until next_offset is null. Region uses the board spatial index. has_description: false lists only the items with no description (null or blank), true only the items with one.

ParameterTypeRequiredDescription
boardstringyes—
regionobjectno—
kindsenum[]noOne of: text, sticky, shape, frame, image, embed, report, pdf_page, diagram, document, spec_run, sheet, plan, agent_card, repo, sandpack.
has_descriptionbooleanno—
limitnumbernoDefault: 200.
offsetnumbernoDefault: 0.

search_items

Read ranked items, including parent_id, z, description and text (the visible text, cut after 200 characters with text_truncated: true, as in get_board_outline).read

search items

Read ranked items, including parent_id, z, description and text (the visible text, cut after 200 characters with text_truncated: true, as in get_board_outline). limit: default 20, max 100. Ranking: each field is scored on its own, never averaged and never divided by the total text length. A field that equals the query (case and accents ignored) scores 1, so an exact text match is always first; a partial match scores below 1, from how close the field is to the query or from how often the query occurs in it (saturating, so a long text that mentions the query many times is not pushed down). The best of text, name, frame title and image caption counts; a description match adds to that score and never lowers it, and a word found only in a description still returns the item. Without a query, items come in id order with score 0; has_description: false lists the items that still need a description.

ParameterTypeRequiredDescription
boardstringyes—
querystringno—
regionobjectno—
kindsenum[]noOne of: text, sticky, shape, frame, image, embed, report, pdf_page, diagram, document, spec_run, sheet, plan, agent_card, repo, sandpack.
has_descriptionbooleanno—
limitnumbernoDefault: 20.

get_item

Read the complete visible item, raw elements, geometry, and neighbours_summary.read

get item

Read the complete visible item, raw elements, geometry, and neighbours_summary. Neighbours (L18): the nearest item, measured edge to edge (the gap between the two boxes, 0 when they touch or overlap; never an arrow or a frame that holds the item), plus every item linked to it by an arrow or connector, with direction from (the arrow points from that item to this one), to (from this one to that item) or both, the arrow_id and the arrow label. No item is listed twice. Sorted by distance, then id. Each neighbour carries id, kind, name, side, distance and its visible text (props.text without marks, cut at 200 characters with an ellipsis and text_truncated: true). props carry backgroundColor and strokeColor when the item has them. props.text keeps its inline marks as written (bold, *italic*, __underline__, ~~strike~~; \* \_ \~ for a literal marker). A pen stroke is kind shape with props.geo freedraw, strokeWidth and point_count. An image item carries caption (the alt text that an agent or a user wrote, else the generated caption; null until the caption job is done), caption_source (user or generated), caption_status (queued, done or failed) and caption_text_in_image (the text read inside the image, when there is any); search_items matches the caption and the text in the image. Set an alt text with update_item {id, caption}.

ParameterTypeRequiredDescription
boardstringyes—
idstringyes—

get_items

Read 1 to 100 items in one call: {items}, one entry per id in the order given (a repeated id is listed once).read

get items

Read 1 to 100 items in one call: {items}, one entry per id in the order given (a repeated id is listed once). An unknown or deleted id comes back as {id, error:"not_found"} and the other entries are still returned. compact (default false): false returns each item as get_item does (raw elements, neighbours_summary and, for an image, the caption fields); true returns {id, kind, name, text, text_truncated?, description, caption?, bbox, parent_id, version} with no elements, which is the cheap way to read a whole board. text is the visible text (marks removed, cut at 200 characters). neighbours (default: true for the full form, false for compact) adds neighbours_summary with the get_item rule.

ParameterTypeRequiredDescription
boardstringyes—
idsstring[]yes—
compactbooleannoDefault: false.
neighboursbooleanno—

list_items_near

Read the items near an anchor, or actual ambiguous anchor candidates.read

list items near

Read the items near an anchor, or actual ambiguous anchor candidates. Never guess an ambiguous query. The rows start with the neighbours of get_item (the same rule: the nearest item edge to edge, plus every arrow-linked item with direction from, to or both, the arrow_id and label), so the radius never drops the nearest item; then every other item whose edge-to-edge distance is at most radius (default 800), by distance. Each row carries the visible text (cut at 200 characters, text_truncated: true). dx and dy are center to center.

ParameterTypeRequiredDescription
boardstringyes—
anchorobject | object | objectyes—
radiusnumbernoDefault: 800.
limitnumbernoDefault: 20.

list_frame_items

Read all direct frame children, not descendants.read

list frame items

Read all direct frame children, not descendants. Oversized results fail explicitly; use paged outline instead.

ParameterTypeRequiredDescription
boardstringyes—
frame_idstringyes—

list_ops

Read actual ordered board operations after a durable sequence (seq greater than since_seq).read

list ops

Read actual ordered board operations after a durable sequence (seq greater than since_seq). This read never appends an operation. Every write response carries the seq of its operation, so since_seq = the seq of your last write reads what changed since then. summary: true returns, for the same ops, one row per changed item: {last_seq (the last op read; the next since_seq), actors: {id: {slug, name, kind}}, items: [{id, last_seq, count, ops (distinct op names), actors (actors keys)}]}, ordered by last_seq. Read the changed items with get_items {ids, compact: true}.

ParameterTypeRequiredDescription
boardstringyes—
since_seqnumberyes—
limitnumbernoDefault: 100.
summarybooleannoDefault: false.

Put stickies, shapes and text on a board, then move, resize, edit, nest or delete them. Every write takes an operation_id, so a retry does not add a second item.

create_item

Create one item on a board.write

create item

Create one item on a board. props may set backgroundColor (fill), strokeColor (the line; on a sticky or shape also the label text) and textColor (the text only, it wins over strokeColor for the text): transparent, #RRGGBB or #RRGGBBAA. props may set fontSize (8 to 256) and textAlign (left, center or right) on text, shape labels and stickies. Text props (text on a text item, a shape label or a sticky) may hold inline marks: bold, *italic*, __underline__, ~~strike~~ (one line per pair, a non-space right after the opener and right before the closer); write \* \_ \~ for a literal marker. A text with no marker is stored as given. A website preview is kind embed with props {url (https), title?, device? (desktop, tablet, mobile or {w, h} in CSS px, 200 to 4096), shared_location? {url, scroll_y?}}: the server checks whether the site allows framing and returns frameable (yes, no or unknown); a URL that resolves to a private or metadata address is refused with invalid_input. A mark over a website preview (kind shape, sticky or text) passes parent_id = the preview id: it moves, scales and deletes with the card. props.anchor {space:"frame", url, epoch?, frame:{x,y,w,h}, device:{w,h}} is optional (frame and device in device-viewport CSS px); without it the server computes the anchor from the item box at the preview home URL. An anchor without a preview parent is refused with invalid_input. The result includes the saved item and a reveal hint. A text that does not fit its w and h fails with text_does_not_fit and details {suggested_h (the box height that fits at your w), min_w (the smallest width for the longest word), suggested_font_size (when a smaller font fits the box)}: retry with those values. fit: "grow" makes h grow to the text instead of failing (w and h stay the minimum). Retry: send your own operation_id (a UUID). After a timeout or a lost response, call again with the same operation_id and the same input: the server returns the stored result and creates nothing new. Other input with that operation_id fails with operation_conflict. For 3 or more items, use one upsert_items call (up to 100 items, one commit, a lean response), not parallel create_item calls. return: "changed" (the default) gives a lean response {id, version, kind, bbox, overlaps} (a website preview adds frameable), with no raw elements: use it when you only need the id. overlaps (create_item and create_item_near) lists the ids of the items whose box the new item intersects (arrows, lines and the containing frames excluded), so you need no image read to check the placement. return: "compact" gives the get_items compact item with neighbours_summary. return: "full" gives the whole item with elements and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
kindenumyesOne of: text, sticky, shape, frame, image, embed, report, pdf_page, diagram, document, spec_run, sheet, plan, agent_card, repo, sandpack.
namestringno—
descriptionstringno—
xnumberno—
ynumberno—
wnumberno—
hnumberno—
parent_idstringno—
propsobjectnoDefault: {}.
fitliteral("grow")no—
media_urlstringno—
iconobjectno—
returnenumnoOne of: changed, compact, full.

create_item_near

Create an item beside an anchor.write

create item near

Create an item beside an anchor. An ambiguous query returns candidates and does not write. A website preview (kind embed, props {url}) is probed like create_item and returns frameable. return: "changed" (the default) gives a lean response {id, version, kind, bbox, overlaps} (a website preview adds frameable), with no raw elements: use it when you only need the id. overlaps (create_item and create_item_near) lists the ids of the items whose box the new item intersects (arrows, lines and the containing frames excluded), so you need no image read to check the placement. return: "compact" gives the get_items compact item with neighbours_summary. return: "full" gives the whole item with elements and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
kindenumyesOne of: text, sticky, shape, frame, image, embed, report, pdf_page, diagram, document, spec_run, sheet, plan, agent_card, repo, sandpack.
namestringno—
descriptionstringno—
xnumberno—
ynumberno—
wnumberno—
hnumberno—
parent_idstringno—
propsobjectnoDefault: {}.
fitliteral("grow")no—
anchorobject | objectyes—
sideenumyesOne of: right, left, above, below.
gapnumbernoDefault: 24.
alignenumnoOne of: start, center, end. Default: "center".
avoid_overlapbooleannoDefault: true.
returnenumnoOne of: changed, compact, full.

update_item

Update one item with the supplied changed fields.write

update item

Update one item with the supplied changed fields. props may set backgroundColor (fill), strokeColor (the line; on a sticky or shape also the label text) and textColor (the text only, it wins over strokeColor for the text): transparent, #RRGGBB or #RRGGBBAA. props may set fontSize (8 to 256) and textAlign (left, center or right) on text, shape labels and stickies. Text props (text on a text item, a shape label or a sticky) may hold inline marks: bold, *italic*, __underline__, ~~strike~~ (one line per pair, a non-space right after the opener and right before the closer); write \* \_ \~ for a literal marker. A text with no marker is stored as given. On an arrow, props may set startArrowhead and endArrowhead (arrow or none) and arrowheadSize (s, m or l); on an arrow or a line, strokeWidth (1 to 40). On an image, caption sets the alt text (1 to 500 characters): it replaces the generated caption, get_item reads it with caption_source: user, and the caption worker never overwrites it. Use base_version to reject stale edits. By default the response is lean: {id, version, changed: {field: stored value}} for the fields you sent, with no raw elements. return: "compact" gives the get_items compact item (id, kind, name, text, description, bbox, parent_id, version) with neighbours_summary; return: "full" gives the whole item as get_item does, with neighbours_summary and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idstringyes—
namestringno—
descriptionstringno—
captionstringno—
lockedbooleanno—
propsobjectno—
returnenumnoOne of: changed, compact, full.

upsert_items

Create or update 1 to 100 items in one board-service operation.write

upsert items

Create or update 1 to 100 items in one board-service operation. Batch descriptions: send items as up to 100 {id, description} entries, for example {board, items:[{id:"a1", description:"Card A"}, {id:"b2", description:"Card B"}]}. For an existing item only the fields you send change; the rest of the item (text, label, style, position, parent, arrow bindings) is kept. An update entry may also set x, y (move, as set_item_position) and w, h (resize, as set_item_size); send each pair whole. So {board, items:[{id:"a1", x:0, y:0}, {id:"b2", x:240, y:0}]} moves many items in one call and one commit; one stale base_version or one locked item refuses the whole batch. More than 100 entries are refused with invalid_input; split them into several calls. Item props may set backgroundColor and strokeColor: transparent, #RRGGBB or #RRGGBBAA. Item props may also set fontSize (8 to 256) and textAlign (left, center or right). Text props (text on a text item, a shape label or a sticky) may hold inline marks: bold, *italic*, __underline__, ~~strike~~ (one line per pair, a non-space right after the opener and right before the closer); write \* \_ \~ for a literal marker. A text with no marker is stored as given. A new website preview (kind embed) is probed like create_item: its props carry frameable. A new mark may set parent_id to a website preview and props.anchor, as in create_item. Build a diagram in ONE call: a create entry may set ref (a local name, [A-Za-z0-9_-], 1 to 64), and a later entry may use it. place {anchor: {id} or {ref}, side (right, left, above, below), gap (40), align (center)} puts a new entry beside an item or an earlier entry, instead of x, y. layout {direction (row, column or grid), x, y, gap (40), columns (grid, default the square root)} lays out, in input order, every create entry that has no x, y and no place. A connector entry {kind:"connector", from: {id} or {ref}, to: {id} or {ref}, from_anchor?, to_anchor?, routing?, label?, stroke_color?, start_arrowhead?, end_arrowhead?, stroke_width?} draws an arrow as create_connector does; its ends must be earlier entries or existing items. A ref that is not defined by an earlier entry is refused with invalid_input. Retry: send your own operation_id (a UUID). After a timeout or a lost response, call again with the same operation_id and the same input: the server returns the stored result and creates nothing new. Other input with that operation_id fails with operation_conflict. By default the response is lean: {items:[{id, version, changed}]} with the stored value of each field sent per item (a new item: {id, version, created:true, kind, bbox, ref when you sent one}), with no raw elements. return: "compact" gives the get_items compact item per entry, with neighbours_summary; return: "full" gives {items, reveal} with the whole items, each with neighbours_summary.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
itemsobject | object | object[]yes—
layoutobjectno—
returnenumnoOne of: changed, compact, full.

create_mind_map

Create a whole mind map in ONE call from a tree: {board, root: {text, children?: [{text, children?}]}, x?, y?, direction?write

create mind map

Create a whole mind map in ONE call from a tree: {board, root: {text, children?: [{text, children?}]}, x?, y?, direction? (right, default; or left), routing? (curved default, straight or orthogonal), operation_id}. x, y (default 0, 0) are the scene point of the top-left corner of the root; call get_board_outline first and pick a free area. The server lays the tree out (tidy tree: each depth is one column, each subtree its own band, a parent sits at the middle of its children) so no two nodes overlap and every child is to the right of its parent (to the left with direction left). A node is a sticky of 240 px width whose height follows its text (text 1 to 300 characters, marks allowed); an edge is one connector bound at both ends. Limits: 200 nodes, depth 8. The server writes at most 50 nodes per commit, so a larger tree is several commits (batches in the result). Turn a long text into the tree yourself: short node texts, 3 to 7 children per node. Returns {root_id, node_count, connector_count, batches, nodes:[{id, text, depth, parent_id, bbox}], connector_ids, reveal}. The parent of a node is the connector that ends on it; to extend the map later, create stickies and connectors with upsert_items, using the ids returned here. Retry: send your own operation_id (a UUID). After a timeout or a lost response, call again with the same operation_id and the same input: the server returns the stored result and creates nothing new. Other input with that operation_id fails with operation_conflict.

ParameterTypeRequiredDescription
boardstringyes—
rootobjectyes—
xnumbernoDefault: 0.
ynumbernoDefault: 0.
directionenumnoOne of: right, left. Default: "right".
routingenumnoOne of: straight, orthogonal, curved. Default: "curved".
operation_idstringno—

delete_item

Delete one item by id. This operation can remove the item and its owned elements.write

delete item

Delete one item by id. This operation can remove the item and its owned elements.

ParameterTypeRequiredDescription
boardstringyes—
base_versionnumberno—
idstringyes—
operation_idstringno—

set_item_position

Move one item. Exactly one alternative: x plus y, or anchor plus side with optional gap (24), align (center), avoid_overlap (true).write

set item position

Move one item. Exactly one alternative: x plus y, or anchor plus side with optional gap (24), align (center), avoid_overlap (true). Do not mix alternatives. An ambiguous anchor returns candidates without a write. By default the response is lean: {id, version, changed: {field: stored value}} for the fields you sent, with no raw elements. It also carries overlaps: the ids of the items whose box the moved item intersects (arrows, lines and the containing frames excluded). return: "compact" gives the get_items compact item (id, kind, name, text, description, bbox, parent_id, version) with neighbours_summary; return: "full" gives the whole item as get_item does, with neighbours_summary and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
idstringyes—
operation_idstringno—
base_versionnumberno—
xnumberno—
ynumberno—
anchorobject | objectno—
sideenumnoOne of: right, left, above, below.
gapnumberno—
alignenumnoOne of: start, center, end.
avoid_overlapbooleanno—
returnenumnoOne of: changed, compact, full.

set_item_size

Set one item width and height.write

set item size

Set one item width and height. The board service preserves its geometry rules. By default the response is lean: {id, version, changed: {field: stored value}} for the fields you sent, with no raw elements. return: "compact" gives the get_items compact item (id, kind, name, text, description, bbox, parent_id, version) with neighbours_summary; return: "full" gives the whole item as get_item does, with neighbours_summary and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idstringyes—
wnumberyes—
hnumberyes—
keep_aspectbooleannoDefault: false.
returnenumnoOne of: changed, compact, full.

set_item_description

Set the description of one item.write

set item description

Set the description of one item. For more than one item, use upsert_items with up to 100 {id, description} entries in one call. By default the response is lean: {id, version, changed: {field: stored value}} for the fields you sent, with no raw elements. return: "compact" gives the get_items compact item (id, kind, name, text, description, bbox, parent_id, version) with neighbours_summary; return: "full" gives the whole item as get_item does, with neighbours_summary and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idstringyes—
descriptionstringyes—
returnenumnoOne of: changed, compact, full.

set_item_parent

Place items in a frame or a website preview, or remove them from their current parent (frame_id null).write

set item parent

Place items in a frame or a website preview, or remove them from their current parent (frame_id null). frame_id names a frame or a preview (an embed item). A preview takes marks only (shapes, lines, arrows, pen strokes, text, stickies): they move, scale and delete with the card, and each gets props.anchor in frame space at the preview home URL. An item that leaves a preview loses its anchor.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idsstring[]yes—
frame_idstringyes—

Box related items in a titled frame, or group items so they move together.

create_frame

Create a frame. Exactly one alternative: x, y, w, h bounds, or fit_ids with optional padding (48).write

create frame

Create a frame. Exactly one alternative: x, y, w, h bounds, or fit_ids with optional padding (48). Do not mix alternatives. Both require board and title. return: "changed" (the default) gives a lean response {id, version, kind, bbox, overlaps} (a website preview adds frameable), with no raw elements: use it when you only need the id. overlaps (create_item and create_item_near) lists the ids of the items whose box the new item intersects (arrows, lines and the containing frames excluded), so you need no image read to check the placement. return: "compact" gives the get_items compact item with neighbours_summary. return: "full" gives the whole item with elements and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
titlestringyes—
operation_idstringno—
base_versionnumberno—
xnumberno—
ynumberno—
wnumberno—
hnumberno—
fit_idsstring[]no—
paddingnumberno—
returnenumnoOne of: changed, compact, full.

create_group

Group the selected items and return the new group id.write

create group

Group the selected items and return the new group id.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idsstring[]yes—

remove_group

Remove one group from all items that contain it.write

remove group

Remove one group from all items that contain it.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
group_idstringyes—

Add an image, a Lucide icon or emoji, every page of a PDF, or a markdown document card to a board.

add_asset

Upload one PNG, JPEG or WebP image (base64, max 6 MiB) to the board.write

add asset

Upload one PNG, JPEG or WebP image (base64, max 6 MiB) to the board. Returns a stable media URL. Pass that URL to create_item with kind image.

ParameterTypeRequiredDescription
boardstringyes—
file_contentstringyes—
file_namestringyes—
mime_typeenumyesOne of: image/png, image/jpeg, image/webp.
operation_idstringno—

add_image

Upload and place one image in one call.write

add image

Upload and place one image in one call. Exactly one source: file_content (base64 PNG, JPEG or WebP, max 6 MiB; file_name and mime_type are then required), media_url (a https://media.devfellowship.com/<id> link, read without a session; a server without MEDIA_ANONYMOUS_KEY_PREFIXES answers not_available) or url (any public https:// image URL: the server downloads it, max 6 MiB and 10 s, accepts PNG, JPEG or WebP by their bytes only, never SVG, HTML or animated images, refuses private, internal and DFL fleet addresses also after a redirect, and stores a re-encoded copy without EXIF; the item keeps props.source_url, and the result returns source_url; a refusal answers url_refused with the rule that refused it). Optional x, y (scene point of the top-left corner) and w (display width; the height keeps the ratio). A retry with the same operation_id returns the first result. By default the response is lean: {id, version, kind, bbox (the stored position and size), media_url, file_id}, with no raw elements. return: "compact" gives the get_items compact item (id, kind, name, text, description, bbox, parent_id, version) with neighbours_summary; return: "full" gives the whole item as get_item does, with neighbours_summary and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
file_contentstringno—
media_urlstringno—
urlstringno—
file_namestringno—
mime_typeenumnoOne of: image/png, image/jpeg, image/webp.
xnumberno—
ynumberno—
wnumberno—
operation_idstringno—
returnenumnoOne of: changed, compact, full.

search_images

Search Wikimedia Commons for photos and diagrams (free licences, no key).read

search images

Search Wikimedia Commons for photos and diagrams (free licences, no key). Returns {provider, query, results:[{url, width, height, title, author, licence, licence_url, source_page, original_width, original_height}]}. url is an 800 px JPEG, PNG or WebP: pass it as-is to add_image {url}. Put author, licence and source_page in the item description of the image you add. Not for company logos or product screenshots: Commons holds mostly photos, maps and diagrams. Limit: 30 uncached searches per actor per minute (rate_limited). resolver_upstream means Commons failed: retry once.

ParameterTypeRequiredDescription
querystringyes—
limitnumbernoDefault: 5.

add_stroke

Draw 1 to 50 freehand strokes in one call (a line, a path, a highlight, a sketch).write

add stroke

Draw 1 to 50 freehand strokes in one call (a line, a path, a highlight, a sketch). Each stroke is {points: [[x, y], ...] (scene coordinates, 2 to 10,000), color? (#RRGGBB, default #E07A4A), width? (1 to 32), opacity? (1 to 100), brush? (pen, marker or highlighter), pressures? (one value 0 to 1 per point)}. brush pen (or no brush) uses pressures; marker keeps one width; highlighter is 3 times the default width with opacity 40. A brush sets only width and opacity; your explicit width or opacity wins. The server simplifies each stroke like the web pen and splits it above 5,000 points, so one stroke can give more than one id. Each stroke is a shape item with props.geo freedraw (get_item shows strokeWidth and point_count); get_board_image draws it. Optional parent_id puts the strokes in a frame. By default the response is lean: {ids, bbox (the union box), version}; return: "full" gives {items, reveal}. All strokes are one operation. Retry: send your own operation_id (a UUID). After a timeout or a lost response, call again with the same operation_id and the same input: the server returns the stored result and creates nothing new. Other input with that operation_id fails with operation_conflict.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
strokesobject[]yes—
parent_idstringno—
returnenumnoOne of: changed, full.

add_icon

Place one icon or emoji on a board, as the toolbar picker does.write

add icon

Place one icon or emoji on a board, as the toolbar picker does. Exactly one of query (the picker name and tag search, best hit wins: "users" finds the users icon) or name (exact Lucide name such as users, or an emoji character or name). set (lucide or emoji) narrows the search; without it Lucide icons come first. A Lucide icon becomes an image item (256 px PNG, stroke color, default #f6f1e7) with customData.dfl.icon = {set, name, color}. The same icon and color on a board reuses the stored file (reused: true, no upload). An emoji becomes a text item. Optional x, y (scene point of the top-left corner), size (display size in scene units, default 96) and color (#RGB or #RRGGBB, Lucide only). Returns the saved item with its set and name. A retry with the same operation_id returns the first result.

ParameterTypeRequiredDescription
boardstringyes—
querystringno—
namestringno—
setenumnoOne of: lucide, emoji.
xnumberno—
ynumberno—
sizenumberno—
colorstringno—
operation_idstringno—

create_items_from_pdf

Import a PDF (max 20 MB, 50 pages) as one frame named after the file, with one image item per page in a grid (columns, default 4).write

create items from pdf

Import a PDF (max 20 MB, 50 pages) as one frame named after the file, with one image item per page in a grid (columns, default 4). Exactly one source: file_content (base64) or media_url (a https://media.devfellowship.com/<id> link). Returns frame_id, page_ids and page_count. A retry with the same operation_id returns the first result.

ParameterTypeRequiredDescription
boardstringyes—
file_contentstringno—
media_urlstringno—
file_namestringno—
xnumberno—
ynumberno—
columnsnumberno—
operation_idstringno—

add_markdown

Add one markdown card. The markdown (max 20,000 characters) is saved as a DFL document with YOUR DFL JWT, so documents access rules decide the write; the board stores only a reference and renders the markdown inline.write

add markdown

Add one markdown card. The markdown (max 20,000 characters) is saved as a DFL document with YOUR DFL JWT, so documents access rules decide the write; the board stores only a reference and renders the markdown inline. Optional title (else the first heading), x, y (top-left scene point), w, h. Read back with get_item; its entity_id is the document id. Edit later with update_item {id, props:{markdown}}. A retry with the same operation_id returns the first result.

ParameterTypeRequiredDescription
boardstringyes—
markdownstringyes—
titlestringno—
xnumberno—
ynumberno—
wnumberno—
hnumberno—
operation_idstringno—

Connect two items with an arrow that follows them when they move, and pick its route (straight, elbow or curved).

create_connector

Create an arrow bound to two items (from_id to to_id), listed in both items boundElements.write

create connector

Create an arrow bound to two items (from_id to to_id), listed in both items boundElements. Optional from_anchor and to_anchor (top, right, bottom, left; default: the sides that face each other), from_anchor_mode and to_anchor_mode (auto or manual; default auto: the end re-picks the facing side when an item moves; manual pins the end to its side, as a browser drop on an anchor point does, and without an anchor it pins the facing side), routing (straight, orthogonal, curved; default straight), label, stroke_color, start_arrowhead and end_arrowhead (arrow or none; default none and arrow), arrowhead_size (s, m or l; default m), stroke_width (1 to 40; default 2). The arrow follows both items when either one moves or resizes. Returns the arrow item with from, to, from_anchor, to_anchor and routing in props, plus from_anchor_mode or to_anchor_mode for a manual end. return: "changed" (the default) gives a lean response {id, version, kind, bbox, overlaps} (a website preview adds frameable), with no raw elements: use it when you only need the id. overlaps (create_item and create_item_near) lists the ids of the items whose box the new item intersects (arrows, lines and the containing frames excluded), so you need no image read to check the placement. return: "compact" gives the get_items compact item with neighbours_summary. return: "full" gives the whole item with elements and the reveal hint.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
from_idstringyes—
to_idstringyes—
from_anchorenumnoOne of: top, right, bottom, left.
to_anchorenumnoOne of: top, right, bottom, left.
from_anchor_modeenumnoOne of: auto, manual.
to_anchor_modeenumnoOne of: auto, manual.
routingenumnoOne of: straight, orthogonal, curved.
labelstringno—
stroke_colorstringno—
start_arrowheadenumnoOne of: none, arrow.
end_arrowheadenumnoOne of: none, arrow.
arrowhead_sizeenumnoOne of: s, m, l.
stroke_widthnumberno—
returnenumnoOne of: changed, compact, full.

update_connector

Change one arrow in place; its id stays.write

update connector

Change one arrow in place; its id stays. Pass at least one change. from_id / to_id re-pin that end to another item (the arrow leaves the old item boundElements and joins the new one). from_anchor / to_anchor (top, right, bottom, left) and from_anchor_mode / to_anchor_mode (auto or manual, as in create_connector) change an end; a free end takes them only with an item id. An anchor you leave out stays when its item stays (for an auto end, when the other item stays too); else it is the side that faces the other end. Also routing (straight, orthogonal, curved), stroke_color, start_arrowhead and end_arrowhead (arrow or none), arrowhead_size (s, m or l), stroke_width (1 to 40). Use base_version to reject stale edits. Refused with invalid_input: a non-arrow id, the same item on both ends, an arrow or a bound label as an end. Returns the saved arrow item.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idstringyes—
from_idstringno—
to_idstringno—
from_anchorenumnoOne of: top, right, bottom, left.
to_anchorenumnoOne of: top, right, bottom, left.
from_anchor_modeenumnoOne of: auto, manual.
to_anchor_modeenumnoOne of: auto, manual.
routingenumnoOne of: straight, orthogonal, curved.
stroke_colorstringno—
start_arrowheadenumnoOne of: none, arrow.
end_arrowheadenumnoOne of: none, arrow.
arrowhead_sizeenumnoOne of: s, m, l.
stroke_widthnumberno—

set_connector_routing

Set the routing of one arrow: straight (2 points), orthogonal (elbow points) or curved (4 points, one cubic Bezier).write

set connector routing

Set the routing of one arrow: straight (2 points), orthogonal (elbow points) or curved (4 points, one cubic Bezier). The points are recomputed from the bound items.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
idstringyes—
routingenumyesOne of: straight, orthogonal, curved.

Point a live website preview at a page, and read the marks that people drew over it.

set_preview_location

Present a page of one website preview (an embed item) to everyone: it writes props.shared_location = {url, scroll_y?, set_by, set_at}; the server fills set_by (your actor id) and set_at.write

set preview location

Present a page of one website preview (an embed item) to everyone: it writes props.shared_location = {url, scroll_y?, set_by, set_at}; the server fills set_by (your actor id) and set_at. Browsers that follow you navigate their preview to url. url must be an https address under the embed URL policy. Each viewer still navigates the preview on their own (navigation is per viewer). Returns the saved preview item.

ParameterTypeRequiredDescription
boardstringyes—
operation_idstringno—
base_versionnumberno—
item_idstringyes—
urlstringyes—
scroll_ynumberno—

list_preview_annotations

List the marks drawn over one website preview (an embed item): {preview_id, url, device, shared_location, annotations}.read

list preview annotations

List the marks drawn over one website preview (an embed item): {preview_id, url, device, shared_location, annotations}. Each annotation is an item in the get_item shape; its parent_id is the preview and props.anchor is {space:"frame", url, epoch, frame:{x,y,w,h}, device:{w,h}}: the page URL the board knew when the mark was drawn, the navigation epoch, and the mark box in device-viewport CSS px. Pass url to keep only the marks of that page. It writes nothing. To add a mark, call create_item with parent_id = the preview id (and an optional props.anchor).

ParameterTypeRequiredDescription
boardstringyes—
item_idstringyes—
urlstringno—

Render a board or a selection to a PNG, and make or read a link that opens a board on a given item.

get_board_image

Render the board, a viewport {x,y,w,h} in scene units, or a selection (item_ids, up to 200; the image box is their union plus 24 px, and only those items, their bound labels, the children of a selected frame and arrows…write

get board image

Render the board, a viewport {x,y,w,h} in scene units, or a selection (item_ids, up to 200; the image box is their union plus 24 px, and only those items, their bound labels, the children of a selected frame and arrows with both ends selected draw), with optional scale, to a PNG and return a stable media.devfellowship.com link. Any signed-in DFL user holding the link can read this snapshot, even if they cannot open the board; later board access changes do not revoke it. Format svg is not available.

ParameterTypeRequiredDescription
boardstringyes—
formatenumnoOne of: png, svg. Default: "png".
scalenumberno—
item_idsstring[]no—
viewportobjectno—
Make a link that opens the board with up to 50 items selected and in view: {url}.read

make board link

Make a link that opens the board with up to 50 items selected and in view: {url}. Use it to point a person at items you just read or made. Every id must be a live item of the board. The link has no credential: the reader still needs access to the board.

ParameterTypeRequiredDescription
boardstringyes—
item_idsstring[]yes—
Use this when a user pasted a board link (a boards.devfellowship.com/b/<slug>?focus=<ids> URL) to say where they are or what they mean.read

resolve board link

Use this when a user pasted a board link (a boards.devfellowship.com/b/<slug>?focus=<ids> URL) to say where they are or what they mean. One call returns {board_id, slug, missing_ids, items}: the selected items in the get_item shape (kind, text, description, bbox, elements). missing_ids lists the ids that are deleted or unknown. A board the caller cannot read answers like the read tools.

ParameterTypeRequiredDescription
urlstringyes—

Move what you (or your agent) look at on a board, select items for the others to see, and follow another actor.

set_viewport

Set an explicitly logical 1280x720 CSS-unit camera, not a physical browser frame.write

set viewport

Set an explicitly logical 1280x720 CSS-unit camera, not a physical browser frame. Exactly one alternative: fit with optional padding (default 64 scene units), or center plus zoom. Do not mix alternatives. An impossible fit fails; ambiguous item queries return candidates without mutation.

ParameterTypeRequiredDescription
boardstringyes—
fitobject | object | objectno—
paddingnumberno—
centerobjectno—
zoomnumberno—

get_viewport

Read the calling actor's current viewport on an authorized board as {center, zoom}, in the logical 1280x720 camera frame.read

get viewport

Read the calling actor's current viewport on an authorized board as {center, zoom}, in the logical 1280x720 camera frame. Returns null when no viewport is stored. Read only.

ParameterTypeRequiredDescription
boardstringyes—

move_viewport

Move the calling actor's stored viewport.write

move viewport

Move the calling actor's stored viewport. direction is up, down, left or right. Each of steps (1..10, default 1) moves the camera by step_fraction (0.1..1, default 0.5) of the logical 1280x720 frame divided by zoom. Zoom does not change. Fails with not_found when no viewport is stored: call set_viewport first. Then the move follows the set_viewport path and returns the same LogicalCamera.

ParameterTypeRequiredDescription
boardstringyes—
directionenumyesOne of: up, down, left, right.
stepsnumberno—
step_fractionnumberno—

set_selection

Select actual live elements on an authorized board.write

set selection

Select actual live elements on an authorized board. An empty list clears selection. Preserve the actor camera and pointer.

ParameterTypeRequiredDescription
boardstringyes—
idsstring[]yes—

set_follow_target

Request one actor follow target in the current board.write

set follow target

Request one actor follow target in the current board. Self-follow and cycles fail. Ambiguity returns candidates without mutation. No browser follow control is sent yet.

ParameterTypeRequiredDescription
boardstringyes—
targetstringyes—

remove_follow_target

Remove this actor follow request in the current board with a new command revision.write

remove follow target

Remove this actor follow request in the current board with a new command revision. No other actor or tab is controlled.

ParameterTypeRequiredDescription
boardstringyes—

The people and agents on a board: who is online, their board profile and where they look. Not the DFL identity actors of the ops host.

list_actors

Read actual public actor profiles.read

list actors

Read actual public actor profiles. Online means current authorized subscribers or unexpired agent activity leases. Reads do not renew leases. Viewport is returned only for an explicit authorized board.

ParameterTypeRequiredDescription
boardstringno—
online_onlybooleannoDefault: false.

search_actors

Search actual public profiles, including reciprocal linked-agent aliases.read

search actors

Search actual public profiles, including reciprocal linked-agent aliases. Return at most five deterministic candidates. No lease is created or renewed.

ParameterTypeRequiredDescription
querystringyes—

get_actor

Read one actual public actor profile.read

get actor

Read one actual public actor profile. Exactly one selector: id, slug, or me:true. Mixed or absent selectors fail. This read does not create online activity.

ParameterTypeRequiredDescription
idstringno—
slugstringno—
meliteral(true)no—

update_actor

Update only name or a canonical media avatar URL for your own actor or a currently reciprocal linked actor.write

update actor

Update only name or a canonical media avatar URL for your own actor or a currently reciprocal linked actor. A paired board agent renames only itself: 1-40 characters, not another board actor name, not a reserved word. A paired board agent may also set the avatar, never the name, of its owner (the reciprocally linked human on the same board). No new board activity lease is created.

ParameterTypeRequiredDescription
idstringyes—
namestringno—
avatar_media_urlstringno—

Read and post the board chat, and react to a message.

post_chat_message

Post one chat message on a board, seen live by every human and agent on it.write

post chat message

Post one chat message on a board, seen live by every human and agent on it. Text is one line, 1-500 characters after trim; control and bidi characters are refused. Optional reply_to: the id of a message on the same board; the new message replies to it (an unknown id or a message of another board is invalid_input). Needs write access to the board. Limit: 10 messages per 30 s per actor (rate_limited). Fails with chat_disabled when the board owner has not turned chat on (settings.chat_enabled). Returns {id, created_at}.

ParameterTypeRequiredDescription
boardstringyes—
textstringyes—
reply_tostringno—

react_chat_message

Toggle the caller's emoji reaction on one chat message of a board: adds it, or removes it when the caller already reacted with that emoji.write

react to chat message

Toggle the caller's emoji reaction on one chat message of a board: adds it, or removes it when the caller already reacted with that emoji. emoji is one of 👍 ❤️ 😂 🎉 🤔 👀 🔥 ✅ (anything else is invalid_input). Needs write access to the board. Limit: 30 toggles per 30 s per actor (rate_limited). An unknown message_id is not_found. Fails with chat_disabled when chat is off on the board. Returns {message_id, reactions:[{emoji, count, actor_ids}]}.

ParameterTypeRequiredDescription
boardstringyes—
message_idstringyes—
emojistringyes—

list_chat_messages

List chat messages of a board, oldest first.read

list chat messages

List chat messages of a board, oldest first. Without since: the newest limit messages. With since (an ISO time or a message id): the first limit messages after it. limit 1-100, default 50. Returns [{id, author:{id,name,kind}, text, created_at, reply_to:{id, author_name, snippet}|null, reactions:[{emoji, count, actor_ids}]}]; snippet is at most 80 characters. A message the board owner deleted has deleted:true and text:null (a reply to it has reply_to.deleted:true and an empty snippet). Fails with chat_disabled when chat is off on the board.

ParameterTypeRequiredDescription
boardstringyes—
sincestringno—
limitnumbernoDefault: 50.
docs tools board 15 hosts published