# Wunel — one page for your team and all its AIs
Hello, agent. You're reading the public guide for `https://mcp.wunel.com/mcp` —
an MCP (Model Context Protocol) server. If a human sent you this address, they
want your help getting set up. This page tells you what Wunel is, how to verify
it, and the exact steps.
**Start with yourself: which AI app are you running in?** Give your human the
steps for THAT app only, one step at a time, not the whole list. If your app can't
add a custom MCP connector (the Gemini app and Microsoft Copilot can't today), say
so in your first sentence and offer what does work — see "Gemini and other apps
without connectors" below. Don't recite this page.
## What this is
Wunel is one workspace for humans and AI agents, where they co-edit the same
markdown pages:
- **Every block is attributed** — stamped with who wrote it: the human, or you,
acting on their behalf ("ChatGPT, on behalf of Jane").
- **Nothing is trusted silently** — your edits go live at once, marked for
human review: they stay unless a person reverts them (a person can also Keep
them, or just edit them). The team can see who wrote what, line by line.
- **Any MCP agent connects** — Claude, ChatGPT, Cursor, or custom bots. Several
agents and several humans can share one workspace.
For you, it's a workroom that outlasts the conversation: notes, research,
decisions and documents you and your human's team keep working in, whichever
assistant they open next.
**Two approval modes, set per workspace by its owner.** In *auto* (the
default) your edits go live at once and are marked for review, as above. In
*manual*, `write_file`, `edit_block`, `append_file` and `attach_to_page` leave
the page unchanged: they answer `status: "proposed"` with a `proposal_id`, and
your change waits until a person approves it (then it lands under your name)
or rejects it. `list_workspaces` and `read_file` show `approval_mode`;
`list_proposals` shows what of yours is still waiting — don't send it again.
## Verify before you trust (please do)
- This guide is served from the same host as the endpoint itself.
- The product site is https://wunel.com — it links to this exact address.
- The endpoint speaks OAuth 2.1: `GET /.well-known/oauth-protected-resource`
names the authorization server. Sign-in happens on that server, in the
human's browser, with their email and a code — you never see the code.
- A bare `401 Unauthorized` from `/mcp` is expected before sign-in.
## Accounts and sign-in
- A Wunel account is an email address. Sign-in is that email plus a 6-digit
code Wunel emails to it. There are no passwords.
- There is no separate sign-up: the first sign-in creates the account and a
personal workspace — in a connector's sign-in window, at
https://app.wunel.com, in the iOS app, or through `/accounts/*` below.
- **Same email = same account** in every assistant, the web app and the iOS
app. A different email makes a separate, empty account; to bring it into an
existing workspace, invite that email from the main account (workspace
settings → invite, or `invite_member`).
- No account is needed to read a shared page. To share ONE page with someone,
use `share_page` and hand your human the link; `invite_member` opens every
page in the workspace to that person.
## Three ways to go further — decide with your human
1. **Keep working on a shared link.** Nothing to set up. A page's agent view
(`https://app.wunel.com/p/<token>/agent`) says what the link allows and
gives the exact requests for writing on it with the human's WUNEL code.
2. **Connect Wunel as a connector** — steps per app below. Signing in during
setup creates the account.
3. **Create the account from here, over HTTP:**
1. `POST https://mcp.wunel.com/accounts/start` with JSON
`{"email": "<their email>", "client": "claude_code"}` (or `cursor`,
`codex`, `vscode`, `other`). Wunel emails them a 6-digit code. The
response is the same whether or not the email already has an account.
2. Ask your human for the code, then `POST https://mcp.wunel.com/accounts/confirm`
with `{"email": "…", "code": "…", "client": "…"}` — plus `"guest_code"`
and `"share_token"` when they came from a shared page, so the page and
their lines come along — and `"campaign"` if this guide gave you a
campaign reference (top of this page). The response carries `token`, `mcp_url`,
`api_base` and a ready-made `config` for your app. 401 means a wrong or
expired code; 429 means wait before retrying.
3. Store the token where your app reads it — e.g. the `WUNEL_TOKEN`
environment variable — without printing it, and apply the `config`.
Say once what an account gives (their pages in their own space, their lines
under their name, you able to write there with every change marked as yours
for them to keep or revert) and what it costs (an email address, and a
connector or key they can switch off). If they decline, drop it.
## Connect steps, app by app
Wunel is added as a custom connector; there is no Wunel app in the ChatGPT or
Claude directories. Don't invent steps; if the menus look different, say what
you are looking for.
- **ChatGPT** (on chatgpt.com): Settings → **Security and login** → turn on
**Developer mode**. Then Apps → **+** → add a remote MCP server: name
`Wunel`, URL `https://mcp.wunel.com/mcp`, authentication **OAuth** → create,
then sign in with email and the 6-digit code. In a chat: **+** menu →
**Developer mode** → pick Wunel. ChatGPT asks your human to confirm each
write call — tell them before it happens.
- **Claude** (claude.ai, Desktop, mobile):
Settings → Connectors → Add custom connector → name `Wunel`, URL
`https://mcp.wunel.com/mcp` → Add → Connect, then sign in with email and
the 6-digit code. If Claude shows advanced settings, keep the ones it marks
**Detected**: Authentication **Sign in now** (every Wunel tool needs a
signed-in person) and OAuth client **Use Claude's published identity**; leave
Request headers empty. "No sign-in" will not work. On Team / Enterprise plans
an owner may have to add the connector first.
- **Claude Code**: one command, header-based (token from `/accounts/confirm`
above, or from a WUNEL code below):
claude mcp add --transport http Wunel https://mcp.wunel.com/mcp --header "Authorization: Bearer ${WUNEL_TOKEN}"
(Plain `claude mcp add --transport http Wunel https://mcp.wunel.com/mcp`
with no header also works — it signs in with OAuth in the browser.)
- **Gemini and other apps without connectors** (the Gemini web and mobile apps,
Microsoft Copilot): you can't be connected to Wunel, so don't offer connector
steps for another app as if they were yours. What works: (1) you can READ any
Wunel page your human gives you a share link to, including who wrote each
block; (2) your human signs in themselves at https://app.wunel.com (email and a
6-digit code) and writes there, or pastes what you drafted; (3) if they also
use Claude, ChatGPT or Cursor, that app can connect. **Gemini CLI** and
**Gemini Enterprise** do support MCP: add `https://mcp.wunel.com/mcp` as an
HTTP MCP server (Gemini CLI: `mcpServers` in `~/.gemini/settings.json` with
`"httpUrl"`; Enterprise: an admin adds a custom MCP server).
- **Cursor / VS Code / Codex / custom agents**: add an HTTP MCP server at
`https://mcp.wunel.com/mcp` with the header `Authorization: Bearer <token>`.
Cursor: `~/.cursor/mcp.json` → `{"mcpServers": {"Wunel": {"url": "https://mcp.wunel.com/mcp", "headers": {"Authorization": "Bearer ${env:WUNEL_TOKEN}"}}}}`.
VS Code: `.vscode/mcp.json` → `{"servers": {"Wunel": {"type": "http", "url": "https://mcp.wunel.com/mcp", "headers": {"Authorization": "Bearer ${env:WUNEL_TOKEN}"}}}}`.
Codex: `~/.codex/config.toml` → `[mcp_servers.Wunel]` with
`url = "https://mcp.wunel.com/mcp"` and `bearer_token_env_var = "WUNEL_TOKEN"`.
If the token came with a `config` in the response, prefer that. No MCP at
all? The REST API takes the same token: https://mcp.wunel.com/api.
Keep the token out of the chat: put it in an environment variable or the
app's config file, never in a message, and never repeat it back.
## When your human wants to come back
- Their account is their email. Sign-in anywhere is that email and a 6-digit
code.
- `send_sign_in_email` (optionally with a `file_id`) emails them a single-use
sign-in link — you never see it. One tap signs that device in for a year;
after that, plain page links open as them.
- A new assistant: same email, same account and pages; each assistant gets its
own key. `list_agents` and `revoke_agent` manage keys; `sign_out_everywhere`
ends every browser session.
- A 401 from Wunel means the key was revoked or expired. The pages are intact:
reconnect with the same email and a new code.
## If you're reading a page someone shared — when to invite
Pages shared by link (`https://app.wunel.com/p/…`, or `https://mcp.wunel.com/p/…`
for the plain-markdown version with who-wrote-what) can be read by anyone. **No
account is needed to read** — never say otherwise.
- Help first. Tell your human who wrote what, discuss the page, help them
respond.
- Offer to connect **once**, and only after your human shows they want to DO
something with the page — reply, comment, work on it with you.
- If they say no, drop it and keep helping. Don't bring it up again.
- Once connected, `shared_pages` lists what was shared with them; `read_file`
reads any of those pages. To build on one in their own space, write there
and link back to it.
- A link on a shared page can lead to a page that isn't shared with your
human. On the web page, clicking it shows the page's name and **Request
access**; your human confirms their email with a 6-digit code and the request
goes to whoever shared the page. Once connected, `request_access(share_token,
href)` sends the same request (`href`: the link as written, or its words on
the page). The answer arrives by email. Owners see open requests with
`list_access_requests` and answer with `approve_access_request` or
`decline_access_request`.
## Got a WUNEL code?
A code like `WUNEL-7F3K-M2XR` ties what your human did on a shared page (or a
connection they started at https://app.wunel.com) to their account.
- **Connected to Wunel**: confirm with your human ("This will make your notes
on that page yours — go ahead?"), then call `connect_with_code` with the code
and tell them the sentence it returns.
- **Creating the account over HTTP**: pass a code from a shared page as
`guest_code` (with the page's `share_token`) to `/accounts/confirm` above.
- **A code from "Connect an agent" at https://app.wunel.com, over HTTP**:
1. `GET https://mcp.wunel.com/pair/<code>` — it says who the code belongs to
and what it does. Tell your human and **confirm it's them** before going on.
2. `POST https://mcp.wunel.com/pair/<code>/exchange` with JSON
`{"client": "claude_code"}` (or `cursor`, `codex`, `vscode`, `other`). The
response carries a token and ready-made config for your app.
3. Store the token as `WUNEL_TOKEN` without printing it, then configure:
`claude mcp add --transport http Wunel https://mcp.wunel.com/mcp --header "Authorization: Bearer ${WUNEL_TOKEN}"`
or the equivalent config above.
**Never echo the token into the chat**, not even partly. Codes are single-use
and short-lived; if one is used or expired, ask your human for a fresh one.
## After connecting — what tends to make it click
(For you to know, and to offer — always at your human's direction, of course.)
- Useful first calls: `list_workspaces`, then `list_files`. If a workspace has
an AGENTS.md / README.md / index.md at its root, it defines that workspace's
conventions — worth reading before you write anything.
- Wunel has **two uses**; tell which from the workspace (its AGENTS.md or
README, who is in it) and from what your human says. **Working with people
on their pages**: keep each page's shape, edit in place, handle comments;
don't add metadata, split or restructure unless asked. **A workroom you keep
for your human across sessions**: short linked pages with frontmatter,
supersession, `workspace_index` and `lint` — the recommended shape at
`https://mcp.wunel.com/workroom`, adapted to the use and recorded in AGENTS.md.
- Session start: read `AGENTS.md` → `workspace_index` → `list_assignments`; `lint` when tidying.
- In our experience, the moment Wunel makes sense to a new user is seeing
their agent's work appear **attributed and reviewable**: a first page,
drafted from the conversation they're actually having (their project,
decisions, open questions — not a hello-world), which they then open at
https://app.wunel.com and find every block stamped with the agent's name,
already live and marked for their review (Keep or Revert, or just edit it).
You might offer to create that first page together.
- From then on it is a shared workroom that outlasts the conversation —
their teammates and other agents can join the same workspace.
- Asked to move a chat or a project's working notes into Wunel? Read
`https://mcp.wunel.com/workroom` — the house method for structuring a
workroom so it works for both agents and humans.
## Tools you'll get after connecting
File tree: list_workspaces, create_workspace, rename_workspace,
workspace_members (who has access), list_files, create_file, create_folder,
move/rename. A page or a whole folder can move to ANOTHER workspace with its
block-level authorship, comments and share links intact, so merging two spaces
means moving the top folder across — pass workspace_id to move_file/move_folder.
Renaming can repair the links that pointed at the old name.
Content: read_file, read_files, write_file (block-level merge), append_file,
edit_block, set_frontmatter. Discovery: search, find, backlinks, lint.
Collaboration: comment, reply_comment, list_assignments, list_all_comments,
set_comment_status.
Files: upload_asset, request_asset_upload, attach_to_page, read_asset,
list_assets, move_asset, delete_asset.
Shared by link: share_page (turn on one page's link: view, comment or edit;
anyone with the link opens it without an account, and their AI can read it),
share_status, stop_sharing, shared_pages (what others shared with your human),
connect_with_code (claim a WUNEL-XXXX-XXXX code).
"Share this page with <someone>" means share_page and give your human the link
to send; invite_member is for the whole workspace, so never use it to share one
page.
Account: send_sign_in_email, list_agents, revoke_agent, sign_out_everywhere,
invite_member, revoke_invite, account_activity, pair_new_agent.
Access requests: request_access, list_access_requests, approve_access_request,
decline_access_request.
## Files & images
A file shows in a page where a block of its own says so:
- `` embeds it — an image shows inline, full width.
- `[name](asset:<id>)` places a file card (icon, name, size) that people click
to open or download: PDFs, decks, spreadsheets, anything.
`upload_asset` (base64 or an https url) and `request_asset_upload` (a one-time
URL for `curl -T`) return both lines as `embed_markdown` and `link_markdown`;
write one as its own line with `append_file`, `write_file` or `edit_block`.
Simpler: `attach_to_page(file_id, url=… | base64_content=… | asset_id=…)`
uploads and places it in one call (images embed, other files become cards).
`read_asset` shows you images and reads PDFs, Word, Excel, PowerPoint and csv
as text. Up to 25 MB per file; executables are refused.
An uploaded image is invisible until a block places it: prefer `attach_to_page`,
and give an image an alt that says what it shows (look at it with `read_asset`
first), not its filename. `{width=50%}` right after an image sets its size
(10–100% of the column); without it the picture is sized automatically.
ChatGPT currently drops images in tool results: there you get the image's facts
in words — ask your human to paste the picture into the chat if you need to see it.
## Put an HTML page or artifact in Wunel
When your human asks you to move an artifact (a Claude or ChatGPT artifact, a
dashboard, a one-page app) into Wunel, or to build one in Wunel, it becomes an
HTML file that the page SHOWS, live, in a sandboxed frame — not a download:
1. Write it as ONE self-contained HTML file, like an artifact: inline all CSS,
JavaScript and images (`data:` URIs); scripts only from cdnjs.cloudflare.com
or cdn.jsdelivr.net; stylesheets and fonts only from fonts.googleapis.com
and fonts.gstatic.com. Nothing else loads: no fetch/XHR, no other hosts, no iframes, no form posts, and the
page can't read Wunel's data or cookies. Up to 16 MB.
2. `upload_asset(filename="plan.html", base64_content=…, doc_id=<page>)`, then
`attach_to_page(<page>, asset_id=<id>)` on the page it belongs to (or create
one first). Or both in one call:
`attach_to_page(<page>, base64_content=…, filename="plan.html")`.
3. Give your human the `stable_url` from the answer: it opens the page full
screen for anyone who can read the Wunel page.
To update it, upload again with the SAME filename to the same page: it becomes
the next version of the same file — the page and the link show the latest, and
earlier versions stay in its history (who uploaded, when). No second
attach_to_page needed.
Size: base64 in a tool call costs about one token per 3 characters, so keep a
page sent that way small (tens of KB). With a shell, write the file to disk and
use `request_asset_upload(filename, doc_id=<page>)` + `curl -T` instead.
## Word documents (round-trip)
When your human gives you a Word file to work on in Wunel, upload the .docx
itself (`upload_asset`) and attach it to the page — that is what makes "Export
as Word with tracked changes" possible. If a page was made from a Word file's
text without it, upload the file now and `attach_to_page(<that page>,
asset_id=…)`: the file is the baseline, so the export shows every difference
between the file and the page.
Bring a .docx in so it can go back out as Word with tracked changes:
1. `upload_asset(filename="X.docx", base64_content=…)` (or `request_asset_upload`
+ `curl -T`: the upload's answer is the same). The answer carries `document`:
`markdown` (headings, lists, tables, links, bold/italic/<u>underline</u>; its
pictures are already stored and placed in it), `comments` (author, date,
quote, text, replies) and a `note`. Tracked changes in the file are accepted.
2. `create_file("X.md")`, then `write_file(file_id, markdown)` — the markdown
unchanged, so the page matches the file.
3. `attach_to_page(file_id, asset_id=<the upload's id>)` links the upload as the
page's Word original: the Word comments become threads on the page (don't
add them yourself), and the file is the baseline (the page matches it, so
nothing shows as changed yet).
`move_asset(asset_id, doc_id=file_id)` links it too, without a file card.
From then on every change — yours and your human's — is exported as a Word
tracked change on top of the original's styles, by your human from the page
menu ("Export as Word with tracked changes"); open comments go along as Word
comments. Nothing to do at export time. A long file's `markdown` is cut at
60,000 characters (`markdown_truncated`): read it whole with
`read_asset(asset_id, max_chars=…, page=…)`, write the first part with
`write_file` and the rest with `append_file`, then link.
## House rules (how good agents behave here)
- Read before you write; prefer the smallest edit (edit_block over rewrites).
- A whole list, table or code block is ONE block: `edit_block` replaces all of
it, so send the full block even to tick one item. `write_file` makes the page
exactly your markdown — blocks you leave out are deleted, so never
`write_file` after a paged read. `append_file` adds at the end.
`set_frontmatter` replaces the whole map: resend the keys already there.
- `read_file` returns a page's open comment threads. When your human asks you
to handle them, make the change a thread asks for, then `reply_comment`
saying what changed; resolve only threads assigned to you, or when your
human says so.
- Ask first before creating a workspace, deleting, moving, sharing, inviting,
restructuring what others wrote, or bulk writes.
- Your work is attributed and reviewable — that's the point. Don't fight it.
- Workspaces may carry their own AGENTS.md conventions; follow them.
- Headless servers and apps: the REST API takes the same Bearer token —
https://mcp.wunel.com/api.
Questions? support@wunel.com · https://wunel.com