@mindfullabai/onda-mcp 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.js +48 -0
- package/package.json +1 -1
- package/skills/onda-mcp-usage/SKILL.md +53 -8
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
MCP server to control [Onda](https://onda.dev) terminal from AI agents (Claude Code, Cursor, Windsurf, etc.)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
31 tools across 7 categories let AI agents split panes, run commands, manage tabs and workspaces, coordinate across multiple windows, and orchestrate multi-agent workflows -- all through the standard [Model Context Protocol](https://modelcontextprotocol.io/).
|
|
6
6
|
|
|
7
7
|
Since v0.2.0 Onda MCP is **multi-window aware**: agents can discover windows, locate workspaces, address terminals unambiguously (each entry carries `windowId` + `workspaceId` + `paneId`), and launch full Claude/agent sessions in one atomic call with the `onda_launch_session` macro.
|
|
8
8
|
|
|
@@ -94,6 +94,9 @@ Same MCP config format as above.
|
|
|
94
94
|
|------|-------------|
|
|
95
95
|
| `onda_window_list` | List Onda main windows. Each entry: `{windowId, isFocused, title, workspaceIds[], activeWorkspaceId, uiMode}`. |
|
|
96
96
|
| `onda_window_new` | Open a fresh empty main window. Returns `{windowId}`. |
|
|
97
|
+
| `onda_window_focus` | Bring a window to the foreground (restore + raise + focus). When `windowId` is omitted, focuses the primary window. |
|
|
98
|
+
| `onda_window_mount_workspace` | Mount a workspace in a specific window. Idempotent; orchestrates an atomic transfer if the workspace is currently owned by another window. Returns `{success, workspaceId, windowId, transferred}`. |
|
|
99
|
+
| `onda_workspace_unmount` | Remove a workspace from whichever window currently hosts it. The workspace continues to exist globally — only its on-screen mounting is dropped. Returns `{success, workspaceId, windowId, alreadyUnmounted}`. |
|
|
97
100
|
|
|
98
101
|
### Macro
|
|
99
102
|
|
package/dist/index.js
CHANGED
|
@@ -487,6 +487,48 @@ const TOOLS = [
|
|
|
487
487
|
description: 'Open a fresh empty main window (analogue of File > New Window). Returns { windowId }. Useful when an agent needs to host a workspace in a brand new window without contaminating existing ones.',
|
|
488
488
|
inputSchema: { type: 'object', properties: {} },
|
|
489
489
|
},
|
|
490
|
+
{
|
|
491
|
+
name: 'onda_window_focus',
|
|
492
|
+
description: 'Bring a specific main window to the foreground (restore if minimized, raise, focus). When windowId is omitted, focuses the primary window. Returns { success, windowId }. Use after mounting a workspace remotely, or to wake Onda from a background CLI subagent.',
|
|
493
|
+
inputSchema: {
|
|
494
|
+
type: 'object',
|
|
495
|
+
properties: {
|
|
496
|
+
windowId: { type: 'string', description: 'Target window id. Omit to focus the primary window.' },
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
name: 'onda_window_mount_workspace',
|
|
502
|
+
description: 'Mount a workspace in a specific window. Idempotent when the workspace is already there. If the workspace is currently mounted in another window, orchestrates an atomic transfer via the unmount-request flow (same path the in-app "Move workspace here?" dialog uses). Returns { success, workspaceId, windowId, transferred }. Pass `direction` to control how the new tile is spliced into the mosaic (mirrors the Cmd+P picker: Enter = down, Cmd+Enter = right).',
|
|
503
|
+
inputSchema: {
|
|
504
|
+
type: 'object',
|
|
505
|
+
properties: {
|
|
506
|
+
workspaceId: { type: 'string', description: 'Workspace to mount.' },
|
|
507
|
+
windowId: { type: 'string', description: 'Destination window id.' },
|
|
508
|
+
direction: {
|
|
509
|
+
type: 'string',
|
|
510
|
+
enum: ['down', 'right'],
|
|
511
|
+
description: 'Optional. Where to splice the new tile relative to the anchor workspace in the mosaic. Default: "down".',
|
|
512
|
+
},
|
|
513
|
+
anchorWorkspaceId: {
|
|
514
|
+
type: 'string',
|
|
515
|
+
description: 'Optional. Workspace id to anchor the split next to. Default: currently active workspace in the target window.',
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
required: ['workspaceId', 'windowId'],
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
name: 'onda_workspace_unmount',
|
|
523
|
+
description: 'Remove a workspace from whichever window currently hosts it (drops it from that window\'s tiled mosaic and releases the mount registry slot). The workspace continues to exist in the global list — only its on-screen mounting is dropped. Returns { success, workspaceId, windowId, alreadyUnmounted }.',
|
|
524
|
+
inputSchema: {
|
|
525
|
+
type: 'object',
|
|
526
|
+
properties: {
|
|
527
|
+
workspaceId: { type: 'string', description: 'Workspace to unmount.' },
|
|
528
|
+
},
|
|
529
|
+
required: ['workspaceId'],
|
|
530
|
+
},
|
|
531
|
+
},
|
|
490
532
|
// --- Advanced terminal spawn ---
|
|
491
533
|
{
|
|
492
534
|
name: 'onda_terminal_spawn',
|
|
@@ -629,6 +671,9 @@ const TOOL_MAP = {
|
|
|
629
671
|
workspaceId: args.workspaceId || ONDA_CONTEXT.workspaceId || undefined,
|
|
630
672
|
cwd: args.cwd,
|
|
631
673
|
shell: args.shell,
|
|
674
|
+
waitForReady: args.waitForReady,
|
|
675
|
+
direction: args.direction,
|
|
676
|
+
relativeToPaneId: args.relativeToPaneId,
|
|
632
677
|
}),
|
|
633
678
|
},
|
|
634
679
|
onda_workspace_tile: { method: 'workspace.setLayout' },
|
|
@@ -636,6 +681,9 @@ const TOOL_MAP = {
|
|
|
636
681
|
// Window
|
|
637
682
|
onda_window_list: { method: 'window.list' },
|
|
638
683
|
onda_window_new: { method: 'window.new' },
|
|
684
|
+
onda_window_focus: { method: 'window.focus' },
|
|
685
|
+
onda_window_mount_workspace: { method: 'window.mountWorkspace' },
|
|
686
|
+
onda_workspace_unmount: { method: 'workspace.unmount' },
|
|
639
687
|
// Advanced spawn + macro
|
|
640
688
|
onda_terminal_spawn: {
|
|
641
689
|
method: 'terminal.spawnInPane',
|
package/package.json
CHANGED
|
@@ -2,13 +2,22 @@
|
|
|
2
2
|
name: onda-mcp-usage
|
|
3
3
|
description: Best practices for driving Onda (terminal emulator) from Claude Code via the `onda` MCP server (`mcp__onda__*`). Covers workspaces/windows/panes/terminals + buffer reading (read/subscribe/poll/wait_for/send_keys) + spatial awareness (layout/screenshot). Use whenever you call any `mcp__onda__*` tool or the user mentions Onda, pane, workspace, terminal listener, presence badge, inception loop (Claude controlling Onda from inside Onda). Triggers — onda mcp, drive onda, control onda terminal, show pane, workspace layout, onda screenshot, kai watcher, terminal listener.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.3.1
|
|
6
6
|
source: '@mindfullabai/onda-mcp'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Onda MCP usage skill
|
|
10
10
|
|
|
11
|
-
This skill tells you **how to correctly use the
|
|
11
|
+
This skill tells you **how to correctly use the `mcp__onda__*` tools** exposed by the `onda-mcp` server (~40 tools as of 0.3.1). It is installed alongside the MCP server. Without this guide you miss non-obvious patterns (subscribe vs read, direction semantics, multi-window orchestration, inception loop).
|
|
12
|
+
|
|
13
|
+
## Compatibility note
|
|
14
|
+
|
|
15
|
+
Some bug fixes shipped in `@mindfullabai/onda-mcp@0.3.1` + Onda 1.9.1+:
|
|
16
|
+
- `terminal_read` now returns the full buffer even on first call (eager tap attach at PTY spawn). Pre-0.3.1 a fresh terminal returned an empty buffer until `subscribe` was active.
|
|
17
|
+
- `workspace_add_terminal` now respects `direction='down'` (was silently rewritten to `'row'` whenever the anchor was already in a row split).
|
|
18
|
+
- `window_mount_workspace` now actually splices the workspace into the tiled mosaic (pre-fix the registry was updated but the UI tab/tile never appeared). Accepts `direction` ('down'|'right', default 'down') and `anchorWorkspaceId` mirroring the Cmd+P picker.
|
|
19
|
+
|
|
20
|
+
If you are talking to an older host, fall back to the legacy patterns: subscribe before run, avoid direction='down' on add_terminal, click-mount via the user.
|
|
12
21
|
|
|
13
22
|
## Mental model
|
|
14
23
|
|
|
@@ -30,6 +39,10 @@ Internal workspace layout = mosaic-component tree. Read it via `onda_workspace_l
|
|
|
30
39
|
| "How is workspace X laid out" | `onda_workspace_layout` |
|
|
31
40
|
| "I want to see what the user sees" | `onda_window_screenshot` |
|
|
32
41
|
| "Open a new terminal right/below pane X" | `onda_workspace_add_terminal` with `direction` + `relativeToPaneId` |
|
|
42
|
+
| "Mount workspace W in window X as a new tile" | `onda_window_mount_workspace` with `windowId` + `direction` ('down' or 'right') |
|
|
43
|
+
| "Move workspace W from one window to another" | `onda_window_mount_workspace` with target `windowId` (atomic transfer, returns `transferred: true`) |
|
|
44
|
+
| "Drop workspace from its window without deleting it" | `onda_workspace_unmount` (registry slot released, PTYs survive) |
|
|
45
|
+
| "Bring a window to front" | `onda_window_focus` (omit `windowId` to focus primary) |
|
|
33
46
|
| "Read what the terminal has printed so far" | `onda_terminal_read` (no subscribe needed) |
|
|
34
47
|
| "I want to receive every new output chunk" | `subscribe` + `poll` loop |
|
|
35
48
|
| "Wait until the build finishes" | `onda_terminal_wait_for` with regex |
|
|
@@ -40,16 +53,18 @@ Internal workspace layout = mosaic-component tree. Read it via `onda_workspace_l
|
|
|
40
53
|
|
|
41
54
|
## Pattern: working with terminal buffer (reads)
|
|
42
55
|
|
|
43
|
-
**
|
|
56
|
+
Onda 1.9.1+ attaches the MCP tap **eagerly at PTY spawn**, so `terminal_read` and `subscribe.bufferSnapshot` return the full history regardless of when you first ask. The pre-0.3.1 anti-pattern (subscribe-before-run) is no longer required for correctness.
|
|
44
57
|
|
|
45
58
|
```
|
|
46
|
-
|
|
47
|
-
✓
|
|
59
|
+
✓ run → read (run + check, works post-fix)
|
|
60
|
+
✓ subscribe → run → poll loop (live streaming + history snapshot)
|
|
61
|
+
✓ wait_for(pattern) (synchronize on a substring)
|
|
48
62
|
```
|
|
49
63
|
|
|
50
64
|
Ring buffer size:
|
|
51
|
-
- **200 KB** when no listener (`read`-only mode)
|
|
52
|
-
- **1 MB** when at least one `subscribe` is active
|
|
65
|
+
- **200 KB** when no listener is attached (`read`-only mode)
|
|
66
|
+
- **1 MB** when at least one `subscribe` is active (auto-promoted)
|
|
67
|
+
- Shrinks back to 200 KB after the last `unsubscribe`, without losing the tap
|
|
53
68
|
|
|
54
69
|
For high-throughput output (`find /`, `tail -F` on logs) the ring saturates. Use `wait_for` with a precise pattern instead of subscribe + scan.
|
|
55
70
|
|
|
@@ -106,6 +121,36 @@ new = workspace_add_terminal(workspaceId,
|
|
|
106
121
|
|
|
107
122
|
Use `down` when the new pane will emit continuous output (logs, build). Use `right` for parallel work terminals.
|
|
108
123
|
|
|
124
|
+
## Pattern: multi-window mosaic orchestration
|
|
125
|
+
|
|
126
|
+
A workspace lives in **at most one window at a time**. `window_mount_workspace` is idempotent and handles three cases:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
1. Workspace unmounted → direct claim into target window (transferred: false)
|
|
130
|
+
2. Already in target → no-op (transferred: false)
|
|
131
|
+
3. Mounted elsewhere → atomic transfer via unmount-request/ack (transferred: true)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
# Setup: workspace X visible as a tile under the current window
|
|
136
|
+
window_mount_workspace(workspaceId=X, windowId=current, direction="down")
|
|
137
|
+
|
|
138
|
+
# Move workspace X to a fresh window
|
|
139
|
+
new_id = window_new().windowId
|
|
140
|
+
window_mount_workspace(workspaceId=X, windowId=new_id, direction="down")
|
|
141
|
+
# returns { transferred: true }
|
|
142
|
+
window_focus(new_id) # bring the new window to front
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`direction` mirrors the Cmd+P picker semantics: `down` = stack below the anchor workspace (Enter), `right` = side-by-side (Cmd+Enter). `anchorWorkspaceId` lets you pick which existing tile to split next to; default is the target window's current active workspace.
|
|
146
|
+
|
|
147
|
+
To drop a workspace from its window without destroying it:
|
|
148
|
+
```
|
|
149
|
+
workspace_unmount(workspaceId=X)
|
|
150
|
+
# registry slot freed, workspace still exists in global list
|
|
151
|
+
# PTYs inside it stay alive (orphaned terminals) until kill or app restart
|
|
152
|
+
```
|
|
153
|
+
|
|
109
154
|
## Pattern: visual verification
|
|
110
155
|
|
|
111
156
|
When you need to visually confirm an action succeeded (layout changed, badge appeared, modal opened) use `window_screenshot`:
|
|
@@ -257,7 +302,7 @@ Con: prompt cache miss every 15 min (cache threshold 5 min), non-zero token cost
|
|
|
257
302
|
2. **`terminal_send` with raw bytes** (`"\x03"` for Ctrl+C): nope. Use `send_keys(["Ctrl+C"])`.
|
|
258
303
|
3. **`workspace_add_terminal` without prior `workspace_layout`**: blind placement. Append-right quickly becomes unreadable.
|
|
259
304
|
4. **Listener without unsubscribe**: leak for 30 min TTL. UI badge stays. Clean up.
|
|
260
|
-
5. **`window_new`** when the user just wants "one more workspace on the right": NO
|
|
305
|
+
5. **`window_new`** when the user just wants "one more workspace on the right": NO. Use `window_mount_workspace(workspaceId, windowId=current, direction='right')` to splice it into the existing window as a side-by-side tile. Open a new window only when the user actually wants two separate windows.
|
|
261
306
|
6. **Assuming `app_info.name === "Onda-dev"`** distinguishes dev vs prod: NO. Use `app_info.path` or an explicit flag.
|
|
262
307
|
7. **`terminal_run` alone to submit a prompt to Claude TUI**: NO. The TUI treats `\n` as newline buffer. You must always follow with `send_keys(["Enter"])` to actually submit. (Validated 21 May 2026 spawning a dedicated Kai.)
|
|
263
308
|
8. **Spawning Kai and then waiting for Mario to click and type**: anti-pattern. If you spawned the session, you drive it to "Kai is working" (pattern "drive a remote Claude Code session"). Mario shouldn't be a human postman in your agent team.
|