virwave-breathe
OfficialThis server provides guided, animated breathing sessions and breathing-pattern information for MCP clients.
breathe: Start a breathing session from a chosen pattern, shape, and length (minutes or exact breath cycles); defaults to a hold-free Circle In & Out 4-8 session.start_session: Match a session to how the person feels, what they'd like instead, and how long they have (2, 5, 10, or 15 minutes); sessions move through stages and are always hold-free.list_patterns: List available breathing patterns with their phases, timings, benefits, compatible shapes, and whether they include breath holds.Resources: Access pattern data (
virwave://patterns), shape descriptions (virwave://shapes), and the chat-display session view (ui://virwave-breathe/session-...html).Prompt
breathing-break: Start a matched session from a plain-language description of how the person feels and how long they have.Delivery options: Sessions appear in the chat when the client supports MCP Apps, otherwise they are saved as HTML and opened in the browser; all sessions wait for the user to press Begin.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@virwave-breatheI need a breathing break."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
VirWave Breathe
Calm, animated breathing sessions from the VirWave app, as an MCP server. Ask for a breathing break and you get a session paced to your breath. In Claude Desktop the session appears in the chat itself; elsewhere it opens in your browser. Either way it waits for you to press Begin.
It runs on your computer, makes no network requests, and collects nothing. It works with Claude Desktop, Claude Code, and any other MCP client that can start a local server.
Install
You need Node.js 18 or newer for the npx routes. The Claude Desktop extension uses the Node.js that comes with Claude Desktop.
Claude Desktop, as an extension
Download
virwave-breathe.mcpbfrom the latest release.In Claude Desktop, open Settings, then Extensions, and drag the file in (or double-click it).
Choose Install. The options let you keep sessions in the chat (the default) or send them to your browser, and choose whether and where session pages are saved.
The first time a session appears in the chat, Claude asks for permission to show it. Choose "Always allow" and later sessions appear straight away.
Claude Desktop, by hand: add this to claude_desktop_config.json (Settings, Developer, Edit Config), then restart Claude Desktop.
{
"mcpServers": {
"virwave-breathe": { "command": "npx", "args": ["-y", "virwave-breathe"] }
}
}Claude Code
claude mcp add virwave-breathe -- npx -y virwave-breatheFor any other MCP client, the command is npx -y virwave-breathe (stdio).
Claude on the web, iPhone, and Android, with nothing to install
VirWave Breathe is also hosted, at one address:
https://xswebtvkueusdaeboizp.supabase.co/functions/v1/breatheIn Claude (on a paid plan), open Settings, then Connectors, choose "Add custom connector", give it the name VirWave Breathe and that address, and add it. It needs no sign-in. The same address works in ChatGPT with developer mode on, and in any MCP client that connects to a URL. See "Hosted" below for what is different.
Related MCP server: Health Reminder MCP Server
What to say
"I need a breathing break."
"I feel wired and I have five minutes. Can you match me a breathing session?"
"Start a box breathing session for two minutes."
"Which breathing patterns don't hold the breath?"
"I'd rather watch something move than follow a line. Start a ripple session."
In Claude Desktop the session appears in the chat, as a card you can expand to fill the window. In a client that can't show it in the chat, it opens in your default browser. In Claude Code, Claude publishes it as an Artifact instead. Every way, it opens at rest and only starts when you press Begin.
Tools
Kind | Name | Does |
Tool |
| Matches a session to how you are, what you'd like instead, and how long you have (2, 5, 10, or 15 minutes). Moves through stages at one steady pace, with no breath holds |
Tool |
| Creates a session from a pattern and shape you choose, for a number of minutes or breath cycles |
Tool |
| Lists the patterns: phases and seconds, what each is good for, its shapes, and whether it holds the breath |
Resource |
| Same data as |
Resource |
| The seven shapes, a plain line on each, and the patterns each draws |
Resource |
| The session as it appears in the chat (an MCP Apps view). One fixed page for every session |
Prompt |
| "Here's how I feel and how long I have": matches a session (or picks a hold-free pattern) and starts it |
list_patterns only reads. When the session is shown in the chat, breathe and start_session write nothing. Otherwise each saves one new HTML file (the session page) on your computer and, unless you turn it off, opens it in your browser. They never change or delete anything. The tool result always says which happened: "Shown in the chat", "Opened in their browser", or the file path.
With no arguments, breathe plays the app's own default session: In & Out, 4 seconds in and 8 seconds out, with no breath holds, drawn on the circle (DEFAULT_BREATH_CONFIG).
Settings
Setting | Extension option | Environment variable | Default |
Show sessions in the chat | "Show sessions in the chat" |
|
|
Save a copy of sessions shown in the chat | "Also save the session page to a folder" |
| Off |
Open sessions in the browser | "Open sessions in my browser automatically" |
| On |
Where session pages are saved | "Where session pages are saved" |
| A |
How the server decides: a client that can show MCP Apps says so when it connects (capabilities.extensions["io.modelcontextprotocol/ui"], as the MCP Apps specification sets out). With VIRWAVE_INLINE=auto the server follows that: such a client gets the session in the chat, with no browser and no file, and every other client gets exactly what version 1.0 gave. off sends every client to the browser. on answers for the chat view even if the client didn't say it supports it. The browser and folder settings apply whenever the session is not shown in the chat; the folder also applies to saved copies.
The temporary folder is the default because it needs no permission prompt, keeps your own folders tidy, and is cleared by the system. When opening is off, or a browser can't be opened, the tool result says so and gives the file path instead. When a caller passes its own out_dir (as Claude Code does, to publish an Artifact), the browser is left alone.
The hosted server has none of these settings: it saves nothing and opens no browser (see "Hosted").
Safety
Sessions are for relaxing and resetting. They are not medical care, and nothing here is described as treatment. The server's instructions and the breathing-break prompt follow the app's own rules (src/domain/distressProtocol.ts):
Patterns with no breath holds come first. A pattern with a hold is only offered when the person asks for one or says holds feel comfortable for them. Matched sessions (
start_session) never hold the breath at all.No breath holds for anyone who says they're panicking, distressed, dizzy, or pregnant, or who mentions a heart or breathing condition. They get In & Out with a long breath out instead.
Anyone who feels lightheaded is told to stop and breathe normally.
Anyone in crisis is pointed to local emergency services or a crisis line, not a session.
The page never starts by itself. It waits for Begin.
test/instructions.test.ts fails if any of these lines go missing.
Accessibility
Reduced motion: when your system asks for less motion, the rings hold still, the particles and sweep stop, fades are instant, and each shape shows its still version. The countdown and phase text still guide the breath.
Screen readers: phase changes are announced, every button has a label, and the decorative drawing is hidden from assistive technology.
Keyboard and voice control: every control is a real button with a visible focus ring, and Space begins, pauses, or resumes. This holds inside the chat too, and the chat view never pulls the keyboard away from the message box.
Not colour alone: phases are always named in text, and counts can be switched on or off.
Dark by design, with text on frosted surfaces for contrast. There is no sound.
Privacy Policy
VirWave Breathe, as an extension or through npx, runs entirely on your computer. The hosted server is covered at the end of this section.
Data collection: none. The server collects no personal data, no usage data, and no analytics. It has no accounts and no sign-in, and the extension and the
npxcommand make no network requests.Usage and storage: the tools use only the choices passed to them (pattern, shape, and length, or the feeling, goal, and minutes for a matched session) to build the session page. A session shown in the chat writes nothing. Otherwise the only thing written is that page: an HTML file saved on your computer in the folder you chose (by default a
VirWave Breathefolder in your temporary files). Your choices are not logged or kept anywhere else. The page, and the view in the chat, load nothing from the internet and store nothing in your browser. The chat view declares an empty list of allowed internet addresses, so the client blocks it from the network as well.Third-party sharing: none. Nothing leaves your computer. The finished screen has a "Get the VirWave app" link, which opens the App Store or Google Play page only if you choose it, with no tracking parameters. In the chat, Claude asks you to confirm before it opens. Those stores have their own privacy policies.
Data retention: VirWave keeps nothing, because it receives nothing. Session pages stay on your computer until you delete them or your system clears its temporary files.
Contact: info@virwave.com
VirWave's full privacy policy: https://virwave.com/privacy/. Terms: https://virwave.com/terms/.
The hosted server (see "Hosted") is the same code at an address on the internet, for Claude on the web and phones and for ChatGPT. What changes: your assistant's requests to it (the tool's inputs: pattern, shape, and length, or feeling, goal, and minutes) travel to that server, which builds the session and sends it back, and a session opened from its link is fetched from it. The server keeps no record of them. It has no database, no accounts, and no analytics, and it writes nothing. A session link opens the session page on GitHub Pages with the session in the part of the address after #, which browsers never send to a server. The hosting platform and GitHub keep ordinary request logs (address, path, time, and outcome) for a limited time to run the service, as any web host does, and VirWave reads them only to find faults. Nothing about you is sent anywhere else.
Your conversation with Claude, or with any other assistant you use this with, is covered by that product's own privacy policy, not this one.
Licence
MIT, copyright 2026 VirWave OAM, Inc.
The published bundle includes these parts of the VirWave app's code, under the same licence: the breathing engine (src/engine/breathingEngine.ts), the rhythm, timing, breakdown, shape, and session-matching data from src/domain/, and a snapshot of the design tokens the session page uses (src/theme.generated.ts). It also bundles the MCP TypeScript SDK and zod, both MIT, with their dependencies. The chat view follows the MCP Apps specification (MIT); its few messages are written out in src/player/bridge.ts, so the MCP Apps SDK is not bundled and adds nothing to the licence list. The rest of the VirWave app, the VirWave name, and the logo are not covered by this licence.
Support: open an issue, or write to info@virwave.com.
How it works
The rest of this page is for people working on the package.
Matched sessions
In the app, Breathe opens app/begin.tsx: colour wheel, then how it feels, what you'd like instead, and how long you have. start_session is that flow without the screen. It's a separate tool rather than more inputs on breathe because a match picks its own shapes, rhythm, and length, so pattern, shape, and cycles would only conflict with it.
Inputs:
feeling(flat, faint, nameable, directional, insistent, saturating),goal(grounded, calm, clear, unstuck, settled), andminutes(2, 5, 10, or 15). The descriptions are the app's own labels and notes fromsrc/domain/sessionMatch.ts. The feeling is how clearly something comes through, never which emotion; Claude is told never to name, guess, or ask about one, and to ask at most one plain question when it can't tell.The colour wheel isn't ported. It's a touch interaction, and nothing in the match reads it.
Stages:
sessionPlangives the stages and seconds;resolveModalitygives each stage's shape and whether it's counted. The page swaps the drawing at each boundary withactiveStageAt, instantly, asapp/session.tsxswaps the renderer. Phase text and counts follow each stage until the person uses T or #.Rhythm: one breath pace for the whole session, from the core (the stage carrying the match, as
app/begin.tsxpicks it withcoreSegment) throughshapeSelectionPatchandderiveSessionRuntimeConfig. Every modality the match can reach runs In & Out 4-8, so every matched session is hold-free, whatever the answers: breathe in, a longer breath out.test/match.test.tsandnpm run smokecheck all 120 combinations for a hold and fail if one appears.Length and progress: cycles are the app's
matchedCycles, the session ends on the meditation timer at the chosen minutes, and the bar shows one segment per cycle (capped at 8), as the app's bar does. It doesn't show stages.Why: the app stores
whyLinebut doesn't show it on the session screen, so it's only in the tool result for Claude.One difference: the app starts counting down as soon as the screen opens, showing the core stage's shape until the first stage takes over. The page waits at rest for Begin, so it rests on the first stage's shape instead.
test/match.test.ts checks all 120 feeling, goal, and length combinations against the app's functions.
Shapes
Shape | What you see | Patterns |
| A square whose outline draws itself once per breath cycle | Box Rhythm, In & Out, In, Hold, Out |
| A triangle whose outline draws itself once per breath cycle | In, Hold, Out, 4-7-8, In & Out |
| A ring that draws itself once per breath cycle, with no corners to turn | In & Out, In, Hold, Out, Box Rhythm, 4-7-8 |
| A soft point crosses a line as you breathe in and comes back as you breathe out | In & Out |
| A soft point travels a figure-eight, once around per breath cycle | In & Out |
| Rings spread out from a still centre and fade, once per breath cycle | In & Out |
| Soft colour swells and settles, once per breath cycle | In & Out |
The last four are the app's breath-locked modalities. The app pairs them with In & Out only, so this server does too. Their names and one-line descriptions come straight from src/domain/modalityConfig.ts.
Why the default is the circle. It's the app's own: DEFAULT_BREATH_CONFIG opens every new session on the circle with In & Out 4-8, and the matched Breathing stages run there too. The app gives the circle to everyone, so every pattern can be drawn on it; for patterns with holds, the box or triangle comes first. For In & Out the box remains the best fit after it (a two-phase rhythm turns on a corner), and the triangle would switch phase mid-side, so it ranks last.
Reduced motion. Each shape has the app's still version: the box, triangle, and circle show their full outline, the focus point rests at the middle of its line, the infinity point rests at the crossing, the ripple's rings hold evenly spaced, and the colour field holds at its resting size.
The session page
The page is the app's session screen (app/session.tsx), rebuilt for the browser and checked side by side against iPhone 16e screenshots of the app:
Background: the session gradient (
sessionTokens.background, navy to teal, corner to corner) under the app's default dim, with the twelve ambient particles spread across it, at the percentage positionsCinematicParticlesgives them.Orb: the three
SessionAurarings (outer and inner breathe in opposite directions, the middle sweep turns once every 20 seconds) and theShapeAuraglow, sized withcomputeAuraRingSizesand driven by the app'sresolveAuraInstruction. The shape sits inside it atlayout.shapeRatio.Text: the 3, 2, 1 countdown, then the phase name and count centred in the shape on a frosted pill. Box, triangle, and circle start counted; focus point, infinity, ripple, and colour field start uncounted, as their app modalities do.
Controls: the glass pill with pause or resume, end, phase text, and count, which dims after a few seconds without interaction; the time left shows under it while paused; the thin segmented bar shows progress, one segment per cycle.
Start and finish: the app starts straight into the countdown. A page can't, so it opens on the orb at rest with a single Begin button in the same glass pill and a quiet line with the rhythm and length (plus the hold note for patterns with a long hold). Ending shows the app's "Well done" or "Session ended" message with Breathe again, and under it a quiet "Get the VirWave app" text link: the App Store (
apps.apple.com/app/id6738364276, fromeas.json) on Apple devices and Google Play (com.virwave.virwave) elsewhere, chosen from the user agent, App Store without JavaScript. It opens in a new tab and carries no tracking parameters.The title stays in
<title>and a heading only screen readers see. Phase changes are announced, every button has a label and a visible focus ring, and Space begins, pauses, or resumes.Reduced motion matches the app: the rings hold their resting size, the sweep and particles stop, the countdown and fades are instant, the controls don't dim, and each shape takes its still pose.
The app sizes the screen in points with fixed caps. The page keeps the iPhone proportions and scales them to the window (up to layout.maxContentWidth), so a desktop browser shows the same composition, larger, rather than a shape that outgrows its orb.
The session in the chat
Claude Desktop, and any other client that supports MCP Apps, shows the session inside the conversation. It is the same page and the same player, not a second design:
breatheandstart_sessionpoint at one view,ui://virwave-breathe/session-<fingerprint>.html(the fingerprint changes whenever the view does, because hosts keep the first copy they fetch) (_meta.ui.resourceUri). The view is a single self-contained HTML document with all seven drawings and no session in it.The session (rhythm, shape or stages, timings, labels, and any hold note) travels as data in the tool result's
structuredContent. The words in the result are for the assistant; the data is for the view. The view fills itself in and waits for Begin.Size: the card is a wide, short panel so the chat stays readable: 0.55 of its width, never under 340 px or over 420 px tall (about 405 px in a typical Claude Desktop chat), and smaller if the host allows less. The expand button opens the full screen.
Expand: when the client offers full screen, a small glass button in the top corner asks for it (
ui/request-display-mode), and the same button brings the session back to the chat. Full screen uses the saved page's layout, and respects the safe areas the client reports.Links: "Get the VirWave app" goes through the client (
ui/open-link), which asks you to confirm. Without a client that can open links it stays an ordinary link.Network: none. The view declares empty allow-lists (
_meta.ui.csp), which is the tightest policy the specification has, and asks for no camera, microphone, location, or clipboard.It was checked in the MCP Apps reference host (
examples/basic-hostin the ext-apps repository) at chat-column and phone widths, side by side with the app.
Hosted
The hosted server is the same code over Streamable HTTP at one address, for clients that cannot run a program on your computer: Claude on the web and phones, ChatGPT, and any other MCP client that connects to a URL.
https://xswebtvkueusdaeboizp.supabase.co/functions/v1/breatheWhat is different from the extension:
Nothing is installed and nothing is saved. There is no folder, no browser setting, and no
out_dir.Every result carries both the session for the chat and a link. The server is stateless: it answers each request afresh and cannot remember whether the client said, when it connected, that it draws MCP Apps views. So a client that does shows the session in the conversation, and any other client gets a link to the same session as a web page (
…/session?pattern=…&shape=…&cycles=…, or…/session?feeling=…&goal=…&minutes=…). The link opens the session page, https://virwave.github.io/virwave-breathe/, with the session carried in the address after#, which never reaches a server. It is the chat view's own document, standing on its own. (A server that can serve HTML on its own domain answers the link with the page directly instead; VirWave's hosting cannot, so it redirects.)No sign-in. The tools need no identity, and the server holds nothing worth protecting, so any origin may call it.
What the address answers.
POSTis the MCP endpoint (plain JSON responses, no sessions). A plainGETreturns a short JSON description of the server.GET …/session?…redirects to the session page with that session in the address, or serves the page itself where it can; either may be cached for a day.Where it runs. A serverless edge function under VirWave's own backend project. It is one file,
dist/hosted.js(virwave-breathe/hostedon npm): a fetch-style request handler with the player built in, for Deno and the edge runtimes built on it (Deno.serve(handleRequest)), Cloudflare Workers (export default { fetch: handleRequest }), Bun, or Node. Two optional settings:VIRWAVE_PUBLIC_URLgives the address clients use when a proxy rewrites it, andVIRWAVE_SESSION_PAGE_URLmakes session links redirect to a copy ofdist/session.htmlserved elsewhere, for a host that cannot serve HTML itself.
To host it yourself: npm install virwave-breathe, then import { handleRequest } from 'virwave-breathe/hosted' and serve it, or npm run build here and deploy dist/hosted.js. npm run smoke:hosted checks the bundle in process, and VIRWAVE_SMOKE_HOSTED=<address> npm run smoke:hosted checks a live one.
How it reuses the app
The sessions are built from the VirWave app's own files, unchanged. In the app's repository the package compiles them in place from the app's src/ folder, which is how the paths below are written. In the public repository, virwave/virwave-breathe, the same files are copies under vendor/virwave/ (so src/engine/breathingEngine.ts is vendor/virwave/engine/breathingEngine.ts). The copies are made by a script and never edited by hand; see vendor/virwave/README.md. The one exception is domain/worlds.ts, which is a short stand-in there: the app's file lists its background themes, and this project only uses the default one. Design tokens are not copied at all: src/theme.generated.ts is a snapshot of the few values the session page reads (npm run generate:theme, app repository only).
src/engine/breathingEngine.tsis bundled unchanged into the page and drives the animation.Patterns come from
src/domain/rhythmTemplates.tsandtimingPresets.ts: free-tier presets only, gated toFREE_SHAPES.Breakdowns are composed by the app's
resolveBreakdownFromRhythmAndTiming.The default pattern is
DEFAULT_BREATH_CONFIG.timingPresetId, so it follows the app.The geometry of all seven shapes is ported from
src/render/shapes/with the same constants. For the four breath-locked shapes, the maths inside each renderer'suseAnimatedPropsworklet is now a plain function insrc/player/geometry.ts, driven by the same(phaseIndex + progress) / totalPhasesand the app's default motion intensity (0.7). The app's renderers weren't changed;test/geometry.test.tschecks positions, radii, opacities, and scale at key points in the cycle.Every colour, space, radius, and type size comes from the app's design tokens and
DEFAULT_BREATH_CONFIG.src/theme.generated.tsis a snapshot of the tokens the page uses, written from the app's own theme files, and a check in the app's repository fails when it falls out of date.
Develop
From the root of virwave/virwave-breathe (or from packages/virwave-mcp in the VirWave app's repository, where the package is developed):
npm ci
npm run build # dist/server.js (MCP SDK and zod bundled in) and dist/player.js
npm test # vitest: catalog, planner, schema, geometry parity, page safety, the chat view, delivery, publishing files
npm run typecheck
npm run smoke # spawns dist/server.js over stdio, as a client with MCP Apps and as one without, and exercises every tool, resource, and promptTo try a local build, point a client at it: claude mcp add virwave-breathe -- node "$(pwd)/dist/server.js".
npm run smoke always starts the server with VIRWAVE_OPEN_BROWSER=false, so it never launches a browser. Set VIRWAVE_SMOKE_SERVER=/path/to/server.js to run the same checks against an installed copy (the npm tarball, or an unpacked .mcpb).
CI runs the same checks on every push: .github/workflows/ci.yml in the public repository, and .github/workflows/virwave-mcp.yml in the app's repository (where the root tsconfig.json and eslint.config.js skip packages/**, so this package owns its own checks).
The public repository is an export
The app itself is private. npm run export:public -- <folder> (app repository only) writes the standalone project that becomes virwave/virwave-breathe: this package at the root, plus the few app files it compiles under vendor/virwave/, with the path aliases pointed there. The script copies only the files on its allowlist (scripts/public-files.mjs), removes a short, documented list of internal comments from the copies without touching any code, and refuses to finish if the code of a copy differs from the app's. It also refuses to finish if any word on its never-ship list would become public. After building the exported folder, npm run sweep:public -- <folder> checks the same list against the source, the built dist/*.js, and the tarball npm pack makes. test/export.test.ts fails when the package starts compiling an app file that isn't on the allowlist, so nothing new becomes public without a deliberate change. Changes are made in the app's repository and exported again; the public copy is not edited by hand.
Release
package.json holds the version. build.mjs passes it into the server, and test/package.test.ts fails if manifest.json or server.json disagree with it.
npm run validate:mcpb # checks manifest.json against the MCPB spec
npm run pack:mcpb # builds, then writes dist/virwave-breathe.mcpb (not committed)
npm pack --dry-run # shows exactly what npm would publishRelease from the public repository, not from the app's. A readable bundle keeps some source comments, and only the public copies have had the app's internal comments removed; the code in the two builds is the same.
npm:
npm publishruns the build, typecheck, tests, and smoke first (prepublishOnly). Two files run:dist/server.jsanddist/player.js. There are no runtime dependencies.Claude Desktop extension:
manifest.json,icon.png, and.mcpbignoredefine the.mcpb. It runs the same two files.MCP registry:
server.json, withmcpNameinpackage.jsonto show the npm package belongs to the same name.
Not yet
The remaining app shapes (heart, star, rainbow, and the rest)
The app's pause dissolve (the moving parts fade while paused); here they hold still where they stopped
The rest of the app's completion screen (stats, journal, favourites, and the glow that blooms behind the title)
Sound (needs a play gesture; silence is the default)
Available Tools
3 toolsbreatheStart a breathing sessionAInspect
Creates an animated VirWave breathing session the person can follow with their eyes. Invoke it when someone asks for a breathing break, a breathing exercise, guided breathing, or a moment to calm down, relax, or reset: the visual session is the breathing break. In a client that supports MCP Apps (Claude Desktop, for example), the session appears in the chat itself, and no browser opens and no file is saved unless out_dir is given or the person has turned on saving a copy. In any other client, it is saved as a self-contained HTML page on this computer and, unless out_dir is given, opens in the person's default browser (they can turn that off in settings). The result says which happened. Either way the session opens at rest and starts when the person presses Begin, so nothing moves without their say-so. With no inputs, it plays the default Circle 4-8 Breathing session, which has no breath holds.
| Name | Required | Description | Default |
|---|---|---|---|
| shape | No | Shape to draw. Each pattern lists the shapes it can use; defaults to the pattern's first. box: A square whose outline draws itself once per breath cycle. triangle: A triangle whose outline draws itself once per breath cycle. circle: A ring that draws itself once per breath cycle, with no corners to turn. focus-point: A calm point drifting slowly across the field. infinity: A continuous figure-eight with no start or end. ripple: Rings spreading out from a point of contact. color-field: Slow colour folding into itself. | |
| cycles | No | Exact number of breath cycles. Takes precedence over minutes. | |
| minutes | No | Approximate session length; rounded to whole breath cycles. | |
| out_dir | No | Directory to write the page into, for a client that shows the page itself (for example, by publishing it as an Artifact). When set, the page is not opened in the browser. When left out, the page is saved to the person's chosen folder (by default a VirWave Breathe folder in the system temp directory) and opened in their browser. | |
| pattern | No | Pattern id from list_patterns. Defaults to in-out-extended-exhale. list_patterns marks each hold-free pattern with "holdFree": true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are all false, so they carry no behavior signal and the description must do the work—it does. It details the two client-type behaviors (appears in chat vs. saved HTML that opens in a browser), when files are saved, how out_dir suppresses the browser, that nothing starts until the user presses Begin, and the no-input default.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a dense single paragraph of about 200 words, but every clause earns its place: trigger conditions, client-specific behavior, default behavior, and user consent to start. It front-loads the most decision-relevant facts and uses parentheticals to keep asides from derailing the main thread.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description notes 'The result says which happened'—minimal but sufficient expectation-setting for return behavior. It also covers defaults, side effects, and the two client environments, leaving little an agent needs to call it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage the baseline is 3; the description exceeds it by explaining the no-input default ('default Circle 4-8 Breathing session'), the effect of out_dir on browser and file behavior, and noting the default has no breath holds. It avoids re-documenting individual parameters, which the schema already covers thoroughly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Creates an animated VirWave breathing session the person can follow with their eyes.' It clearly identifies the tool's function, but it never contrasts with sibling start_session, so a caller must infer the boundary from the word 'breathing' rather than explicit differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use conditions: 'Invoke it when someone asks for a breathing break, a breathing exercise, guided breathing, or a moment to calm down, relax, or reset.' It clarifies the session itself is the break, but offers no when-not-to-use guidance or reference to alternatives like start_session or list_patterns.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_patternsList breathing patternsARead-onlyInspect
Lists the VirWave breathing patterns this server can play: phases and seconds, what each rhythm is good for, which shapes can draw it, whether it is hold-free, and any safety note about breath holds. Hold-free patterns are listed first.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark it read-only, and the description adds useful behavioral details beyond that: result ordering ('Hold-free patterns are listed first'), the scope ('this server can play'), and included safety notes about breath holds. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and resource, then adds a compact enumeration of the returned fields and the ordering guarantee. Every clause earns its place without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully covers what the agent should expect: phases, seconds, purpose, shapes, hold-free status, and safety notes. The ordering behavior is also disclosed, making the tool self-contained for a parameterless read-only call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema is empty, so there is nothing semantic to document. The baseline of 4 applies because there is no parameter ambiguity for an agent to resolve.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Lists') and resource ('VirWave breathing patterns this server can play'), then enumerates the details returned. This clearly differentiates it from the action-oriented siblings breathe and start_session.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes it clear this is the tool for discovering available patterns and what they are good for, which implies use before or without starting a session. It does not explicitly name alternatives or exclusions, but the context is strong enough for an agent to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_sessionStart a matched sessionAInspect
Matches a VirWave session the way the app's entry flow does: how clearly a feeling is coming through, what they'd like instead, and how long they have. Invoke it when someone says how they are feeling, or what they would like to feel instead, and wants a breathing session that fits. The session moves through stages (arrive, the matched core, close), each with its own shape, at one steady breath pace, and ends at the chosen length. In a client that supports MCP Apps (Claude Desktop, for example), the session appears in the chat itself, and no browser opens and no file is saved unless out_dir is given or the person has turned on saving a copy. In any other client, it is saved as a self-contained HTML page on this computer and, unless out_dir is given, opens in the person's default browser (they can turn that off in settings). The result says which happened. Either way the session waits for Begin, and the result says why it was picked and which stages it has. Every matched session is hold-free: breathe in, a longer breath out.
| Name | Required | Description | Default |
|---|---|---|---|
| goal | Yes | What they'd like instead. grounded (Grounded: Back in the body, contact restored.) calm (Calm: Slower, softer, less pressure.) clear (Clear: One thing at a time, in focus.) unstuck (Unstuck: The loop loosens and moves on.) settled (Settled: Steady enough to rest.) | |
| feeling | Yes | How the feeling is coming through: how clearly, not which feeling it is. The options describe how clear the signal is, and none of them names an emotion. flat (Flat / no signal: Numb, far off, nothing registers.) faint (Faint trace: Something is there but not describable.) nameable (Nameable: A word fits, with hedging.) directional (Directional: It points at something specific.) insistent (Insistent: Hard to set aside, keeps returning.) saturating (Saturating: Too much at once, loud and fast.) | |
| minutes | Yes | How long they have: 2, 5, 10, or 15 minutes. Longer sessions move through more stages, not just more time. | |
| out_dir | No | Directory to write the page into, for a client that shows the page itself (for example, by publishing it as an Artifact). When set, the page is not opened in the browser. When left out, the page is saved to the person's chosen folder (by default a VirWave Breathe folder in the system temp directory) and opened in their browser. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With all annotations being false (no positive hints), the description carries the full behavioral burden. It discloses session structure (stages, steady pace, hold-free), client-specific side effects (saving to HTML, opening browser, appearing in chat), the absence of file saving unless out_dir is provided, and what the result communicates. It goes well beyond what annotations or schema provide, making the tool's behavior fully transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average but highly informative. It is front-loaded with the core purpose then covers usage, session behavior, client differences, and result content. No sentence is redundant; each contributes necessary context. It is structured logically but could be tightened without losing value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description covers the essential context: what the session does, side effects across client types, when it waits for a Begin signal, and what the result conveys. With no output schema present, the description gives a reasonable (if high-level) explanation of the result content. It could be more specific about the exact result fields, but it is sufficient for an agent to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already explains each parameter in detail. The description adds semantic context by linking the parameters to the matching logic ('how clearly a feeling is coming through, what they'd like instead, and how long they have') and by detailing the client-specific behavior of out_dir. This adds meaning beyond the schema, though the schema already does substantial work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Matches a VirWave session the way the app's entry flow does.' It clearly identifies the inputs (feeling, goal, minutes) and the output behavior. However, it does not explicitly distinguish this from sibling tools like 'breathe' or 'list_patterns' by name, so the differentiation is implied rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear trigger: 'Invoke it when someone says how they are feeling, or what they would like to feel instead, and wants a breathing session that fits.' This is explicit about when to use the tool, but it does not mention alternative tools or provide exclusionary guidance ('when not to use'). The context is clear, but the absence of explicit alternatives keeps it at a 4 rather than a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v1.2.0- Changed
breathe1 field changed- changed
Input schema / properties / pattern / enumPrevious value: -[ - "in-out-equal-4", - "in-out-extended-exhale", - "in-out-quick-2", - "in-hold-out-equal-4", - "in-hold-out-extended-exhale", - "in-hold-out-quick-2", - "box-equal-4", - "box-quick-3", - "4-7-8-signature" -]New value: +[ + "in-out-equal-4", + "in-out-slow-5", + "in-out-extended-exhale", + "in-out-quick-2", + "in-hold-out-equal-4", + "in-hold-out-extended-exhale", + "in-hold-out-quick-2", + "box-equal-4", + "box-quick-3", + "4-7-8-signature" +]
3 tool updates
v1.0.0- First observed
breathe - First observed
list_patterns - First observed
start_session
TDQS
Scored across 3 tools
list_patterns is clearly distinct, but breathe and start_session both create VirWave sessions and their trigger conditions overlap (e.g., 'I'm stressed, give me a breathing exercise' could reasonably invoke either). The descriptions clarify the default vs. matched distinction, but an agent may still struggle to pick the right one without careful reading.
start_session and list_patterns follow a consistent verb_noun pattern, but breathe breaks it by being a bare verb with no noun. The naming is still readable and predictable overall, with only a minor deviation.
Three tools is well within the typical 3-15 range and each tool earns its place: create a default session, create a matched session, and list available patterns. The count fits the server's narrow, focused purpose without redundancy.
The server covers listing patterns and creating default or matched sessions, but there is no way to start a specific pattern chosen from list_patterns—a user who picks a rhythm from the list creates a dead end. Basic session creation works, but the missing pattern-selection session is a notable gap that agents cannot work around cleanly.
Maintenance
Related MCP Connectors
Personalized hypnosis sessions and multi-day journeys, a free session library, and audio rendering.
- DoneThatOAuthai.donethat
Privacy-first work tracking with summaries, reports, coaching, and AI-ready long-term memory.
The adaptive health-messaging engine for apps and agents. Federally-sourced. Not medical advice.
Read-only mindfulness games, guided practices, research, glossary and PanchaVikas resources.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides compassionate mental health support tools including mood tracking, emotional check-ins, and personalized coping strategies. Stores mood logs and journal entries locally while offering empathetic guidance for stress management and emotional well-being.1-
- AlicenseAqualityDmaintenanceSends periodic system notifications to remind users to take breaks and move around, with customizable intervals, messages, and cross-platform notification support.414 npm1MIT
- AlicenseNot gradedqualityDmaintenanceA daily-rhythm support MCP server for ADHD and bipolar disorder, providing 23 tools for mood tracking, social rhythm regularity, early warning detection, task breakdown, and crisis support, all running locally with zero dependencies.MIT
- AlicenseNot gradedqualityDmaintenanceEnables local browser automation using Stagehand without cloud services. Supports navigation, data extraction, and autonomous agent tasks through natural language.Apache 2.0