You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
basecamp mcp: rich-text fields are stored as literal Markdown instead of being converted like the CLI does #896
Found while evaluating basecamp mcp as a replacement for dyve/basecamp-cli-mcp, a self-built MCP server, written with Claude, that wraps the basecamp CLI. It exists because we wanted read/write Basecamp access from Claude Cowork and Claude Desktop, which have no terminal for the CLI or the Basecamp skill. Now that the CLI ships its own MCP server, we would rather use that than maintain ours; this issue is one of the gaps in the way.
basecamp-cli-mcp inherits the CLI's Markdown conversion and passes an optional format: "markdown" | "html" through to --format on its ten rich-text tools.
Rich-text fields sent through basecamp mcp go to the API exactly as written. Agents write Markdown by default, so it is stored as literal text.
Repro (v0.13.2, macOS, Basecamp 3 account)
basecamp_todos → create_todo with:
{ "todolistId": <id>, "content": "test","description": "**bold** and a [link](https://example.com)\n\n- item one\n- item two" }
Stored description:
**bold** and a [link](<a … class="autolinked" href="https://example.com">https://example.com</a>)\n\n- item one\n- item two
The bold markers and list dashes are stored as typed, and Basecamp's autolinker breaks the Markdown link syntax apart. The same content through basecamp todos create … --description renders correctly, because the CLI converts Markdown by default (#832).
Why it matters
The CLI made Markdown the stated default for every rich-text field precisely because agents write Markdown (#692, #832). basecamp mcp is the agent-facing surface, yet it is the one place that doesn't convert. Every agent-written description, message, comment and document is affected.
Suggestion
Run rich-text fields (content/description on todos, cards, messages, comments, documents, uploads) through the same richTextToHTML path the CLI uses. Give each a format: "markdown" | "html" parameter matching the CLI's --format flag, so an agent writing back HTML it read from a get action can opt out. create_comment's synthetic mentions already does client-side expansion before posting, so there is precedent for this kind of preprocessing in the gateway.
AI Disclosure
This issue was written and researched with the help of Claude Code.
Re-tested on v0.22.0. A replace_todo description of Some **bold** text and a [link](https://basecamp.com) followed by a two-item list is stored with the asterisks, brackets and dashes as literal text. The CLI turns the same input into bold, a link and a list.
An idea for a fix: give the gateway the CLI's own rich-text handling. Agents write Markdown by default, and the CLI already does the right thing with it: Markdown is converted, --format html passes HTML through, and a URL alone on its line becomes an embed.
As far as I can see, what's missing is knowing which fields are rich text. The model has no marker for it, and only some field descriptions say "rich text (HTML)". One way to close that gap:
Mark rich-text request fields in the SDK model, e.g. x-basecamp-rich-text: true on description, content and body where they are HTML. The same pattern as x-basecamp-clearable.
In the gateway, run marked fields through the CLI's existing Markdown conversion. Add an optional format: "markdown" | "html" param per call, mirroring --format, so an agent writing back HTML it just read isn't converted twice.
Until then, it would help if those parameter schemas said the field is HTML. An agent could then at least send HTML on purpose instead of guessing.
Activity
dyve commentedon Oct 31, 2026
Re-tested on v0.22.0. A
replace_tododescription ofSome **bold** text and a [link](https://basecamp.com)followed by a two-item list is stored with the asterisks, brackets and dashes as literal text. The CLI turns the same input into bold, a link and a list.An idea for a fix: give the gateway the CLI's own rich-text handling. Agents write Markdown by default, and the CLI already does the right thing with it: Markdown is converted,
--format htmlpasses HTML through, and a URL alone on its line becomes an embed.As far as I can see, what's missing is knowing which fields are rich text. The model has no marker for it, and only some field descriptions say "rich text (HTML)". One way to close that gap:
x-basecamp-rich-text: trueondescription,contentandbodywhere they are HTML. The same pattern asx-basecamp-clearable.format: "markdown" | "html"param per call, mirroring--format, so an agent writing back HTML it just read isn't converted twice.Until then, it would help if those parameter schemas said the field is HTML. An agent could then at least send HTML on purpose instead of guessing.