Docs › Agents and teams
Your coding agent
Run it with one command, then connect Claude Code, Codex, Cursor, Gemini CLI, Copilot or any MCP client: the tools, what the agent gets and critique.
Run it#
npx notato
That is the whole server: the board at http://localhost:4747, and MCP for your coding agent at http://localhost:4747/mcp, until you stop it. Point any agent at the MCP address. On your own machine it needs no token:
claude mcp add --transport http --scope user notato http://localhost:4747/mcp
The board's Settings › Agents has the same line for Codex, Cursor, Gemini CLI and VS Code, and shows which agents are connected. Then put the toolbar in your app (below), or on any page with the bookmark. npx notato --tunnel adds a dev tunnel for phones; npx notato --help lists the rest. Run it again while one is running and it tells you where that one is.
Works with your coding agent#
Notato is an MCP server plus two Agent Skills, so it works with any agent that speaks MCP. There are two ways to connect one: point it at a running server's /mcp (above), or let the agent start Notato itself over stdio, which is what init sets up. init sets up the ones it finds (their command is installed, or their folder is in the project), or the ones you name with --agent claude,codex,cursor,gemini,copilot (or --agent all, or NOTATO_AGENTS):
| Agent | The MCP server | The skills |
|---|---|---|
| Claude Code | claude mcp add notato -- npx notato dev --project <id> (--mcp-scope local, project or user) | .claude/skills/ |
| Codex | codex mcp add notato -- npx notato dev (Codex keeps one list for every project) | .agents/skills/ |
| Cursor | .cursor/mcp.json | .agents/skills/ |
| Gemini CLI | .gemini/settings.json | .agents/skills/ |
| GitHub Copilot (VS Code) | .vscode/mcp.json | .github/skills/ |
| Anything else | Run npx notato dev as a stdio MCP server | Copy .agents/skills/notato wherever it reads skills |
A config file that already has other servers keeps them; one with comments in it is left alone, and init prints the entry to add. Each reply and status change is signed with the agent's own name ("Codex resolved #3"), taken from what its MCP client calls itself, and the toolbar and board say who they are asking ("Ask Codex to revert"). Clients that give up on a long tool call (Codex after 60 seconds) get a shorter notato_watch, which the agent simply calls again.
MCP tools#
| Tool | Purpose |
|---|---|
notato_list_open | Open annotations, filterable by project, route, severity, intent, bundle, a page at a time |
notato_get | One annotation, with its screenshots as image content, at the detail level you ask for |
notato_watch | Block until new annotations, replies or revert requests arrive (with a collection window), then return the batch |
notato_acknowledge · notato_reply · notato_resolve · notato_dismiss | Work through it, with notes in the thread. notato_resolve also takes the files and commit of the change |
notato_variants_ready | Offer versions you put in the code for the person to compare; they pick one in the page |
notato_reverted | Report that a change you were asked to undo has been undone |
notato_import_bundle | Load a tester's zip from a path |
notato_annotate | Agent mode: ask a connected page to annotate an element (a >>> selector reaches into iframes and shadow roots) |
notato dev binds to loopback only. A second agent session (another Claude Code, or a Codex beside it) attaches to the first one's server as an MCP-only client, and takes over if it goes away.
Several repositories, one server. Every repository's notato dev shares the server on 4747, so without a project each agent would be handed every app's notes, and could "fix" one in the wrong codebase. --project <id> (repeat it, or separate ids with commas, for a repository with several apps; or NOTATO_PROJECT) keeps an agent to its own projects. notato_watch and notato_list_open hand over only their notes. A note from another project can still be read by id, labelled as not this session's, but not changed. The app's toolbar says an agent is there only when that agent works on its project. Over HTTP it is /mcp?project=<id>. init writes --project into the registration for this repository (Claude Code's local and project scopes, Cursor, Gemini CLI, VS Code); when a second app in the same repository is set up, its project is added beside the first. Codex and Claude Code's user scope keep one list for every folder, so they stay on every project.
MCP over HTTP. Every server also serves MCP at /mcp: npx notato and notato dev on your machine, notato serve for a team. On your machine it is as open as the rest of the dev server, with no token, but only to programs on it. A web page is refused (agents send no Origin header and browsers always do, so no page you visit can act as your agent), and so is anything that comes through the dev tunnel or a proxy, even with the device token, because that token is built into every debug build of your app. Over HTTP, notato_import_bundle reads paths on your machine as it does over stdio; on a shared server it cannot.
Turning agents off. Agents are on by default. Switch them off with Settings › Agents on the board, npx notato config set mcp off, or NOTATO_MCP=off; --no-mcp on notato start or notato serve keeps them off for as long as that process runs. Off means every agent is refused, and told why and how to turn it back on: at /mcp, an agent that started its own notato dev (or attached to yours), and on a shared server the agent tokens (for *). A notato_watch that is waiting gets the same answer within a second. Pages stop showing an agent as connected. Apps keep sending notes. On your own machine this is a switch, not a lock (anything running as you can read .notato/ anyway); on a shared server it is a lock. A settings file that cannot be read turns it off, as it does screenshots, until it is fixed.
@ mentions: plugins on the server#
@name in a note or a reply calls one of the server's mention plugins, such as @jira or @slack. None is built in, and none is needed to reach the agent: it gets everything people write (see what the agent gets).
Apps and the board learn what @ can call from the server: GET /config has mentions (each with its name, description and whether it is available now) and agent (whether an agent is connected and watching), and the event stream sends mentions and agent events when they change. Webhooks carry the @names someone just wrote in mentions, so a flow can branch on them. Without a plugin of that name, @name is just text.
A plugin is small: a name, a description for the @ menu, whether it is available, and what to do when it is mentioned. On a server you embed, backend.mentions.register({ name, description, available, watch, onMention }) adds one; plugins from notato.config.json are a next step.
Critique mode#
The notato-critique skill has the agent do what a careful reviewer would: open your running app in a browser it can drive (a browser built into the agent, a browser extension it controls, Playwright or Chrome DevTools MCP), use it (menus, forms, keyboard, a phone width, empty and error states), and file the five to eight things that matter most as annotations, through window.__notato.annotate or notato_annotate. They arrive like yours, with the element, the screenshots and the code location, marked as from an agent. Then it works them with the notato loop. It needs a browser tool and the page open with Notato mounted; the skill checks that first and says so if not. Questions it cannot answer from the code it leaves for you.
Agent mode#
<Notato mode="agent" project="checkout-web" server="http://localhost:4747" />
An agent driving the browser (Playwright MCP, Chrome DevTools MCP, Claude in Chrome) calls the page API, so its annotations go through the same pipeline as a person's:
await window.__notato.annotate({
target: "#pay", // selector or Element
comment: "No loading state",
severity: "minor",
steps: [{ action: "click", target: "#pay", at: new Date().toISOString() }], // optional: seen steps are used otherwise
screenshot: base64Png, // optional: real pixels, e.g. from Page.captureScreenshot
})
window.__notato.list()
await window.__notato.package() // { bundleId, filename, zipBase64, … }
With no direct page access, notato_annotate relays the call to an open agent-mode tab.