Mount the workspace in Claude Code.

One line adds a Tuval workspace to Claude Code or Cursor as an MCP server. Twelve tools: search pages, databases, issues and projects in one call, open any of them as Markdown, read a board as prose, list what is in flight — and, with a key made to write, file a new record, change one, add to a page, or hand back a brief that becomes a board. The key decides which workspace, whether it may write at all, and the agent is shown exactly what the person who made that key can see.

The twelve tools

search

Words in titles and bodies, across pages, databases, issues and projects in one call. Postgres full-text does the matching, and an excerpt comes back with each id so a result can be judged before it is opened.

read_page

One page or issue in full, as Markdown, with its headings, lists and code intact. Not the JSON shape of a row — the text a model can reason over.

read_board

A canvas as prose: frames become sections, notes become bullets, connectors become a graph, comments stay attached to what they were about. It is the reading the browser wrote on its last save, and it comes back dated so a board nobody has opened lately is out of date on the record rather than in secret.

list_boards

The boards in this workspace, newest first, with how many items and frames each holds and the address to read it in full. What an agent asks before it decides which canvas the question is about.

list_records

Records of one kind, narrowed by status, project or assignee. Archived rows are left out, so an agent is never arguing about work somebody already put away.

workspace

What this key can reach, and the addresses inside it. It also says whether the key may write and how many writes are left today, so an agent finds out before it plans rather than after it fails.

create_record

File an issue, a page, a project, a person, a company or an event, with its status, assignee, priority, parent and opening text. The first three have a screen; a person, a company and an event are rows the API keeps and nothing in the product draws yet. Wants a key made to write; a read key is told so in words.

update_record

Change a title, a status, an assignee, a due date, or which project or cycle something belongs to. Only the fields you send move, and the change is signed with the key's name.

append_to_page

Add Markdown to the end of a page or issue. It becomes real paragraphs — headings, lists, code — the next time somebody opens that page, because a page is a shared document only a browser can edit. The band below says exactly what that delay costs.

create_board

Hand back a Markdown brief and get a board. Headings become frames, bullets become notes inside them, and a mermaid flowchart becomes the arrows between them. The brief waits on the board and the first browser to open it does the drawing, so what comes back is an address rather than a canvas full of work — and it says so in those words.

update_board

The same board again. Rename it, or send it another brief: append draws below what is already there, replace takes back what the last brief drew and redraws in its place. Every item a brief draws is marked as such, so replace never touches what a person put on the canvas by hand. A report that runs every week lives on one board instead of leaving a new one behind each time.

trash_board

Put a board in the trash, so an integration can clear up after itself instead of leaving its drafts for somebody to find. Marked rather than removed — everything drawn on a board hangs off one row, which makes deleting it the single thing here nobody could undo, so a person can still restore it from the board list.

Two lines

The server is a file in the repository and it speaks the protocol over stdin and stdout, so there is nothing to deploy and nothing listening on a port. It wants a key, made in Settings → API and webhooks, hashed the moment it exists and therefore shown exactly once. The full reference is docs/mcp.md in the checkout, rendered at /docs/mcp, because two copies of the same prose disagree within a month.

  • claude mcp add tuval -- node /path/to/tuval/scripts/mcp.mjs
  • TUVAL_API_KEY=tuv_... # in the environment, or in .env.local

What is not behind this door

A board is written in briefs and never in items. One makes a board, another sends the same board a new brief — enough to publish the same report on the same canvas every sprint, replacing what the last one drew and leaving whatever a person added by hand. What there is no verb for is the single item: nothing moves a sticky note somebody already put down, draws a connector between two that are there, or edits a frame, because the canvas is a shared document only a browser composes. The rows are the other half — pages, databases, issues, projects, people, companies, events, files and collections — and there the same line falls in the same place, at the paragraph already written.

Writing is a key you choose to make

Scope is set when the key is made and cannot be raised by the agent holding it. A read key answers 403 to every write, in a sentence rather than a number, and a key past its daily allowance answers 429 — two different problems, told apart on purpose, because one means come back with a better key and the other means come back tomorrow. Every write is signed with the key's name and the person behind it, and leaves a version somebody can put back.

Where a written paragraph actually lands

A page is a shared document held in the browsers editing it, not a column in a table, so no server here can open one. Text an agent adds waits on the record and is folded onto the end of the page the next time somebody opens it, with its structure intact. Until then the agent can read it back where it will sit, but search will not find it and nobody scrolling past will see it. That is a delay rather than a second place for text to live, and it is written down here rather than discovered in week two.

A key is never more than the person who made it

The agent reads with its maker's eyes. A page with people named on it stays shut unless they are one of them. Taking that person out of the workspace closes their key with them, and no parameter can move a call into another workspace, because the caller never chooses the workspace — the key does.

Held for the paid plan, open on your own install

The API and the MCP server that rides on it are what the hosted plan charges for, so on a free hosted workspace every call answers 401. Run it yourself and the same check passes: the self-hosted setting is read as the team plan and the seat, storage and API limits stop applying. Either way the reason comes back as text the model can read rather than as a broken pipe.

The round trip, and where it stops

A board goes out to an agent as a brief and a brief comes back as a board: the model writes Markdown, the endpoint keeps it, and the first browser to open that board turns it into frames, notes and arrows. Until somebody looks, the board is a brief waiting, and the answer says that rather than reporting a canvas full of work. Where it stops is editing. Nothing here moves a note already on a board, and nothing rewrites a paragraph already in a page, deletes one or reorders blocks. That is a limit rather than an oversight, and it belongs on the page where you are deciding rather than in week two.

You should not have to paste your own work into a prompt

The alternative to this door is copying a page into a chat window and copying the answer back. It works once. It does not survive the second week, and from the moment the tab closes the workspace and the model's idea of it drift apart. A key, one line, and the agent is reading the work rather than a paraphrase of it.