Cnvs.app vs Pushary
A side-by-side look at the Cnvs.app and Pushary MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.
Verdict: choose Cnvs.app for security work over a hosted endpoint; choose Pushary for security as a local process. You can also run both side by side in one mcpServers block.
Which MCP server should you choose?
Choose Cnvs.app when
- You need dedicated capabilities in the Security domain.
- You prefer a remote HTTP/SSE transport.
- You want tools like
open_board, create_board, get_board.
Choose Pushary when
- You need dedicated capabilities in the Security domain.
- You prefer a local stdio subprocess transport.
- You have the keys it needs:
PUSHARY_API_KEY. - You want tools like
send_notification, ask_user, wait_for_answer.
Feature & specification comparison
Rows where the two servers differ are marked.
| Spec | ||
|---|---|---|
| Category | Security | Security |
| Quality signal | 59/100 · Good | 57/100 · Good |
| Install command | Confirmed | Confirmed |
| Transport | Remote HTTP/SSE | Local subprocess (stdio) |
| Auth | Not declared | Not declared |
| Pricing | Not declared | Not declared |
| Required env vars | None listed | PUSHARY_API_KEY |
| Verified owner | Community listing | Community listing |
| GitHub stars | 1 | 1 |
| Directory activity | 1 views 0 installs 0 upvotes | 2 views 0 installs 0 upvotes |
| Tools | 25 | 6 |
| Full listing | View Cnvs.app | View Pushary |
Tools & capabilities
Cnvs.app tools 25
open_boardALWAYS call this first when given a board URL or ID. Resolves the canonical board id and auto-creates the board row if it does not exist yet. Returns a summary (item counts, authors). After this, call BOTH `get_preview` and `get_board` before editing so you can see the layout visually AND know the exact ids/coordinates — do not skip `get_preview`, otherwise you will place new items blindly on top of existing ones.create_boardCreate a fresh board in ONE call — optionally pre-filled with content, auto-laid-out, and/or PIN-locked at create time. Mirrors the extended `POST /api/boards` REST body exactly (same server-side implementation). With no arguments it returns a blank draw board; `mode: 'todo'` (+ optional `template`) seeds a kanban board. `content` imports initial items atomically: everything is validated FIRST and the board is created only if every item passes — on any invalid item you get a structured error naming its kind + index and NOTHING is created. `autolayout: true` (draw mode) fills in x/y for texts/images that omit them (deterministic masonry grid; explicit coordinates are never touched). `lock: 'write'|'all'` locks the board atomically with creation and returns the plaintext `access_key` ONCE — there is no recovery. The response's `imported` counts confirm what was created, `ids` returns the server-minted item ids per kind in the order you supplied them (index i of `ids.texts` is the id created for `content.texts[i]`; `ids.columns` is empty when the columns came from the template seed, and lanes have no id — they are keyed by board + lane index), and `embed_url` (the `?embed=1#<id>` iframe view) is returned for any board readable without a key — it is omitted for `lock:'all'` boards, whose embed frame can't read the board anonymously. Prefer this over open_board + N per-item calls when you are building a whole board from scratch.get_boardFull structured JSON state of a board: texts (id, x, y, content, color, width, postit, author), strokes (id, points, color, author), images (id, x, y, width, height, dataUrl, thumbDataUrl, author; heavy base64 >8 kB elided to dataUrl:null, tiny images inlined). Use this for EXACT ids/coordinates/content (needed for `move`, `erase`, editing a text by id). For visual layout (where is empty space? what overlaps?) call `get_preview` instead — it's much cheaper for spatial reasoning than a huge JSON dump.get_previewCompact schematic SVG render of the board (typically a few kB even for dense boards). Returns both an image/svg+xml content block (you can SEE it) and the raw SVG text. CALL THIS any time you need to understand where things are — before placing new items, before deciding whether the canvas is crowded, before picking a free region. AI-authored items get a purple border so you can tell which contributions were yours. For precise text content prefer `get_board`.add_textCreate a NEW text node, or update an existing one (pass the same `id` to overwrite content/position in place — preferred over creating a duplicate). Supports cnvs markup (Markdown-ish) and Mermaid diagrams in the content. When using Mermaid, the ENTIRE content of this text node must be a single Mermaid diagram (one ```mermaid fenced block and nothing else — no heading, no prose before or after). If you need prose + a diagram, create two separate text nodes. `postit: true` renders as a yellow sticky; `diagram: true` renders as a framed box (2px border in the text colour, centred text) — the two are mutually exclusive. Coordinates are in board-world pixels, +x right, +y DOWN; pick a spot that does not overlap existing items (check `get_preview` first). Default width auto-fits content up to ~320 px; pass `width` for explicit wrapping (160–4096). Keep content under 100 000 chars.add_linkDrop a URL capsule onto the board — rendered as a clickable pill showing the hostname. Use this instead of `add_text` when the node is just a link; the capsule styling signals clickability to humans. Same coordinate rules as `add_text` (+x right, +y down).add_imagePlace a raster or SVG image on the board at (x, y) with explicit width/height in board pixels. `data_url` MUST be a `data:image/(png|jpeg|gif|webp|svg+xml);base64,...` string ≤ ~900 kB; hosted URLs are not accepted. Strongly recommended: also pass a tiny `thumb_data_url` (≤8 kB JPEG/PNG/WebP, ~64 px on the long edge) — it is embedded into the SVG preview so OTHER AI viewers (and you, on later `get_preview` calls) can actually see the image instead of a placeholder box.draw_strokeDraw a freehand stroke on the board. Use for arrows, underlines, connector lines, annotations, or simple shapes — a straight line needs two points, a rough circle wants ~20. Stroke width is fixed at 3 px; `color` is a NAME, not hex (case-insensitive): 'auto'/''/'black'/omitted for theme-aware ink, or 'red', 'blue', 'green', 'orange', 'yellow', 'pink', 'purple', 'maroon', 'brown', 'gray', 'lightgray', 'teal', 'sage', 'sky', 'lavender' — anything else (including a literal hex like '#ff0000') silently clamps to auto. Accepts three equivalent point formats — pick whichever your MCP client serialises cleanly: nested `[[x,y],[x,y],...]`, flat `[x1,y1,x2,y2,...]`, or a JSON string of either. Some clients (Claude Code as of 2026-04) drop nested arrays during tool-call serialisation, so prefer the flat form or the JSON-string form when in doubt. To delete a stroke later, use `erase` with `kind: 'line'` and the id returned here.moveReposition an existing item to a new (x, y) without retyping its content. Works for every item kind: `text` and `link` set the top-left to (x, y); `line` translates every point so the stroke's bounding box top-left lands at (x, y); `image` sets the top-left like text. `kind` defaults to `text` for backward compat with older callers. Find the id + kind via `get_board`. Prefer `move` over re-creating an item when only the location changes — it preserves the id, content, author and avoids a round-trip of base64 bytes for images.eraseDelete a single item by id. `kind` MUST match the item type: 'text' for text nodes, 'line' for freehand strokes, 'image' for images — the wrong kind silently targets the wrong table and is a common mistake. Get the id + type from `get_board` (texts[], lines[], images[]). There is no bulk/erase-all tool: loop if you need to delete multiple items.wait_for_updateLong-poll: blocks until the next edit lands on this board, then returns. WHEN TO CALL THIS: if your MCP client does NOT surface `notifications/resources/updated` events from `resources/subscribe` back to the model (most chat clients do not — they receive the SSE event but don't inject it into your context), this tool is how you 'wait for the human' inside a single turn. Typical flow: you draw / write what you were asked to, then instead of ending your turn you call `wait_for_update(board_id)`. When the human adds, moves, or erases something, the call returns and you refresh with `get_preview` / `get_board` and continue the collaboration. Great for turn-based interactions (games like tic-tac-toe, brainstorming where you respond to each sticky the user drops, sketch-and-feedback loops, etc.). If your client DOES deliver resource notifications natively, prefer `resources/subscribe` — it's cheaper and has no timeout ceiling. BEHAVIOUR: resolves ~3 s after the edit burst settles (same debounce as the push notifications — this is intentional so drags and long strokes collapse into one wake-up). Returns `{ updated: true, timedOut: false }` on a real edit, or `{ updated: false, timedOut: true }` if nothing happened within `timeout_ms`. On timeout, just call it again to keep waiting; chaining calls is cheap. `timeout_ms` is clamped to [1000, 55000]; default 25000 (leaves headroom under typical 60 s proxy timeouts).set_board_modeChoose whether this board is a freeform whiteboard ('draw', the default) or a kanban task board ('todo'). Mode is switchable WHENEVER the board is empty of real content: drawings (text/strokes/images) and tasks. Empty or seeded columns DON'T count (switching to 'draw' clears them), so a cleared board can be switched again, and you can flip draw<->todo freely until the first stroke/text/image or task lands. Setting 'todo' auto-seeds three starter columns (To do / In progress / Done). Returns `{ mode, columns }`. Use the task/column tools (`create_task`, `create_column`, …) once the board is in 'todo' mode.- +13 more on the listing page
Pushary tools 6
send_notificationSend a push notification with optional rich context (file changes, errors, next steps)ask_userAsk the user a question via push - yes/no, multiple choice, or free textwait_for_answerLong-poll for the user's response to a questioncancel_questionCancel a pending question that's no longer relevantlist_sessionsRead-only view of your live agent sessions and pending questionspropose_scopeRatify the boundary of a run: file globs, enforced on supported hosts, or a recorded promise when the run changes no files
Ready-to-paste client configs
Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.
Cnvs.app
{
"mcpServers": {
"cnvs-app-2": {
"url": "https://cnvs.app/mcp"
}
}
}
Pushary
{
"mcpServers": {
"pushary": {
"command": "npx",
"args": [
"-y",
"pushary@latest"
],
"env": {
"PUSHARY_API_KEY": "YOUR_PUSHARY_API_KEY_HERE"
}
}
}
}
Frequently asked questions
Cnvs.app is categorized under Security and uses a remote HTTP/SSE transport. Pushary belongs to Security and uses a local stdio subprocess. Pick Cnvs.app for security work and Pushary for security.
Copy the mcpServers block from the config section on this page into your client's config (for example claude_desktop_config.json or ~/.cursor/mcp.json), then fully restart the client.
Cnvs.app has no declared pricing — check the project's own site. Pushary has no declared pricing — check the project's own site. If a server needs environment variables such as API keys, define them under the env key in your client's MCP config.
Yes. MCP clients support multiple servers: add cnvs-app-2 and pushary as separate keys in the same mcpServers object, and your assistant will call tools from either one.
On AllMCPs, Cnvs.app has a quality signal of 59/100 (Good) with 1 views, 0 installs and 1 GitHub stars. Pushary has 57/100 (Good) with 2 views, 0 installs and 1 GitHub stars.