Docs › Agents and teams
Aspire
AddNotato() in an Aspire app host runs the board and MCP with your apps, and switches Notato on in each of them.
Notato in your Aspire app host. AddNotato() runs the Notato board, the server your apps' notes go to, and MCP for your coding agent (Claude Code, Codex, Cursor and others) with the rest of your apps, and WithReference(notato) turns Notato on in each app that uses it and points it there. Nothing in the apps' code has to know which machine or port that is.
Quick start#
In the app host project:
dotnet add package Notato.Aspire
var builder = DistributedApplication.CreateBuilder(args);
var notato = builder.AddNotato();
builder.AddViteApp("web", "../web")
.WithReference(notato);
builder.Build().Run();
A file-based app host takes it as #:package Notato.Aspire@<version>. Run the app host as usual (aspire run): the dashboard lists notato with a Board link, and its details have the MCP address. Give that to your coding agent once; 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 line for Codex, Cursor, Gemini CLI and VS Code. Put the toolbar in the app as usual (npx notato init for a React app, provideNotato for Angular, UseNotato for .NET MAUI); WithReference does the rest.
What it runs#
AddNotato() runs npx --yes notato@<version> start --attach --port 4747, the notato npm package of the same release as this one, so Node.js has to be installed. It runs in the repository's root folder (the one with .git, above the app host), so the notes and screenshots are in .notato there, as with npx notato, and notato.config.json there is its settings file. npx notato init adds .notato/ to .gitignore; without it, add it yourself.
- The same port every run. Coding agents are given its address once, and phone builds bake it in, so it is not behind Aspire's proxy and does not move. The dashboard marks it healthy once
/healthanswers. - One already running is used. A Notato already on the port (the one your agent's
notato devstarted, another app host's, one you keep running) is used rather than refused: the resource stays running beside it, and serves the port itself if that one stops. Its console says which. - Stopping the app host stops it.
- Never published. Notato is a development tool: it is left out of what the app host publishes, and
WithReferencesets nothing then, so a deployed build never has Notato switched on by it.
| Call | |
|---|---|
AddNotato(name, port) | Default "notato" and 4747 |
.WithDataDirectory(path) | Keep the data somewhere else (--dir), such as "~/.notato" to share it between repositories. Relative to the app host's folder; ~ is your home folder |
.WithConfigFile(path) | Another settings file (--config): screenshots, MCP, webhooks (see notato config) |
.WithTunnel() | Also a dev tunnel, so phones reach it (--tunnel). Needs the devtunnel CLI, signed in once |
.WithNotatoCommand(command, args...) | Run it some other way: ("notato") for one that is installed, ("npx", "--yes", "notato@latest") for another version. Relative paths start at the repository's root |
What an app is given#
WithReference(notato) adds the app to Notato's references on the dashboard and sets two environment variables:
| The app | Variables |
|---|---|
A JavaScript app: AddViteApp, AddJavaScriptApp, AddNodeApp | VITE_NOTATO=true, VITE_NOTATO_SERVER=http://localhost:4747 |
| Anything else: a .NET MAUI app, an executable, a project, a container | NOTATO_ENABLED=true, NOTATO_SERVER=http://localhost:4747 |
WithReference(notato, enabled: false) gives false instead, which keeps Notato off in that app, in development too: handy behind a setting of your own.
What reads them:
<Notato />andprovideNotato, in an app built with Vite (or a framework on it):VITE_NOTATOdecides whether the toolbar starts, over theenabledprop, in a production build too. So an app that Aspire runs asvite build --watchwithvite previewhas the toolbar, and the same build made anywhere else does not.VITE_NOTATO_SERVERwins over theserverprop.@notato/viterecords source positions under the same switch, and the guardnpx notato initwrites checks it too.- Notato.Maui (
AddMauiProject):NOTATO_ENABLEDwins overEnabledand over the on or off remembered on the device, andNOTATO_SERVERoverServer. Aspire hands them to the iOS and Android builds itself. A phone or the Android emulator cannot reachlocalhost: with.WithTunnel(), a debug build reaches the server through the tunnel instead (it reads.notato/device.jsonat the repository's root when it is built; give<NotatoDataDirectory>with.WithDataDirectory). - The Swift package reads the same two from the process's environment, and Flutter from
--dart-define. - Next.js and other bundlers do not pass
VITE_variables to the page: giveenabledandserverfrom your own.