Docs · MCP

Connect your AI

A reference for plugging an MCP-speaking agent into writespace. Setup, client configs, every tool, and the format details that matter when an agent is reading or writing your docs.

Setup

Three steps. Two minutes.

  1. 01

    Create a personal access token

    Sign in to app.writespace.io, open Settings → API tokens, click Create token, and copy it. Tokens are shown once. Revoke any time from the same screen.

  2. 02

    MCP endpoint

    One hosted endpoint for all writespace.io accounts:

    https://app.writespace.io/mcp
  3. 03

    Wire it into your client

    Drop the endpoint and a Bearer token into your client's MCP config. Snippets for the major clients below.

Client configs

All four use HTTP MCP + Bearer auth — only the config file location differs.

Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "writespace": {
      "type": "http",
      "url": "https://app.writespace.io/mcp",
      "headers": {
        "Authorization": "Bearer ws_pat_…"
      }
    }
  }
}
Claude Code (CLI) claude mcp add ...
claude mcp add --transport http writespace \
  https://app.writespace.io/mcp \
  --header "Authorization: Bearer ws_pat_…"
Cursor Settings → MCP → Add server
// Type:    HTTP
// URL:     https://app.writespace.io/mcp
// Header:  Authorization: Bearer ws_pat_…
Gemini CLI ~/.gemini/settings.json
{
  "mcpServers": {
    "writespace": {
      "httpUrl": "https://app.writespace.io/mcp",
      "headers": {
        "Authorization": "Bearer ws_pat_…"
      }
    }
  }
}

Tool reference

Every tool except list_workspaces takes a workspace_id — call list_workspaces first to discover them.

01 · Read Discover & fetch
list_workspaces List every workspace you belong to. No arguments.
list_folders List folders in a workspace, optionally nested under a parent.
list_docs List documents in a workspace; optional folder_id scope. Returns metadata on every row.
get_doc Fetch a doc by ID. Returns canonical Tiptap JSON, a markdown rendering, and metadata.
search Full-text search across a workspace. Returns ranked hits with <<match>> snippets. Use as RAG retrieval directly.
query_docs Find docs whose metadata contains a given JSON object (Postgres JSONB @>). e.g. { status: "accepted" }.
02 · Write Create & mutate
create_doc Create a doc from content (Tiptap JSON) or content_markdown. Lean response by default.
update_doc Update title, content, or metadata. Metadata shallow-merges; null deletes a key. Open editors reload.
upsert_doc Create-or-update by title within an optional folder. Idempotent.
append_to_doc Append markdown / Tiptap JSON to the end of an existing doc.
replace_section Replace the body of a section identified by its heading text. Surgical edits without round-tripping the whole doc.
delete_doc Delete a doc by ID.
03 · Organise Folders & moves
move_doc Move a doc into a different folder, or pass folder_id: null to send it to root.
create_folder Create a folder. Optional parent_id for nesting.
rename_folder Rename a folder. IDs stay stable, so links and references don't break.
delete_folder Delete a folder and its contents.

Things to know

Content format

Reads return both content (lossless Tiptap JSON) and content_markdown (convenience). Writes accept either.

Markdown round-trips for everything the editor supports — headings, bold/italic/strike/code, links, lists, task lists, blockquotes, fenced code with language, tables, horizontal rules, mermaid diagrams.

Lean write responses

create_doc, update_doc, upsert_doc, append_to_doc, and move_doc return only metadata by default. Saves 80–95% of the payload on long docs.

Pass include_content: true to echo the body back.

Structured metadata

Every doc has a JSONB metadata field. Read, write, and query as first-class structured data.

Write: metadata: { status: "draft" }; shallow-merge on update; null deletes.
Query: query_docs with where: { status: "accepted" }.

Cross-doc links

Reference docs by stable ID, not by title:

[Container diagram](writespace://doc/3873bc94-…)

The editor routes clicks internally. IDs survive renames and moves.

Live editing

MCP writes broadcast a reload over Realtime. Open editors refetch in the same tab. Last write wins — no merge between an in-progress live edit and a concurrent MCP write.

If the broadcast is dropped, refreshing picks up the change.

Markdown gotchas

Bare-URL autolinking is off. CLAUDE.md stays as plain text. Use [label](url) or <https://…>.

Raw HTML is ignored.

Images aren't a supported node yet — image syntax drops to its alt text.

Troubleshooting

401 invalid or missing personal access token

Token is wrong, revoked, or the Authorization header isn't being sent. Format: Authorization: Bearer ws_pat_…. Tokens are shown once at creation — regenerate if lost.

-32000 error from a tool call

The underlying Postgres call failed; the error message has the cause. Most commonly: the workspace_id doesn't belong to you, or the doc/folder ID doesn't exist.

Tool changes don't appear in the open editor

The Realtime broadcast was dropped. Refreshing picks up the change. MCP writes never block — they just notify.