@composer-app/mcp 0.0.1-beta.5 → 0.0.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/CHANGELOG.md +145 -0
- package/README.md +160 -0
- package/dist/{chunk-A5KBJAJW.js → chunk-GPFWLOYB.js} +1402 -237
- package/dist/cli.js +1 -1
- package/dist/mcp.js +21 -1
- package/package.json +3 -2
- package/skill/commenting/SKILL.md +67 -0
- package/skill/create/SKILL.md +131 -0
- package/skill/export/SKILL.md +67 -0
- package/skill/join/SKILL.md +117 -0
- package/skill/monitor/SKILL.md +159 -0
- package/skill/suggesting/SKILL.md +177 -0
- package/skill/.claude/settings.local.json +0 -8
- package/skill/SKILL.md +0 -417
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@composer-app/mcp` are documented in this file.
|
|
4
|
+
|
|
5
|
+
This project uses pre-release semver under the `0.0.x-beta.N` track; each
|
|
6
|
+
release bumps the `beta.N` counter regardless of additive / breaking
|
|
7
|
+
distinction until the package graduates to `0.1.0`.
|
|
8
|
+
|
|
9
|
+
## 0.0.1-beta.7 — 2026-04-29
|
|
10
|
+
|
|
11
|
+
Polish on the COM-26 ack/state work shipped in `0.0.1-beta.6` (which was
|
|
12
|
+
never published to npm). Adds an explicit "skip" signal and fixes the
|
|
13
|
+
top-bar avatar pulsing forever after a reply finished.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **New tool: `composer_done`.** Explicit signal for the skip path —
|
|
18
|
+
off-topic chatter, self-mention, or any case where the agent decides
|
|
19
|
+
not to reply. Accepts `{ roomId, threadId, replyId? }`. Clears the
|
|
20
|
+
thread-head `agentWork` placeholder published by
|
|
21
|
+
`RoomState.onEventDelivered` when `composer_next_event` dequeued the
|
|
22
|
+
mention; optionally also clears a per-reply entry. Idempotent.
|
|
23
|
+
SKILL.md tells the agent to call it whenever it skips.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Top-bar PresenceBar avatar kept pulsing forever after a reply.**
|
|
28
|
+
`composer_next_event` publishes a thread-head
|
|
29
|
+
`agentWork(threadId, undefined, "thinking")` placeholder when it
|
|
30
|
+
dequeues a mention; the agent's ack reply then publishes a
|
|
31
|
+
reply-scoped entry. The `composer_agent_status({state: "ready"})`
|
|
32
|
+
handler cleared the reply-scoped entry but not the thread-head
|
|
33
|
+
placeholder, and `useAgentActivityByUser`'s max-severity reduction
|
|
34
|
+
kept the avatar pulsing.
|
|
35
|
+
- `performAgentStatus` ready branch now clears both
|
|
36
|
+
`(threadId, replyId)` and `(threadId, undefined)`.
|
|
37
|
+
- `performReplyComment` and `performReplySuggestion` also clear the
|
|
38
|
+
thread-head placeholder when posted with `state: "ready"` directly,
|
|
39
|
+
as defense in depth for callers that skip the state machine.
|
|
40
|
+
|
|
41
|
+
## 0.0.1-beta.6 — 2026-04-28
|
|
42
|
+
|
|
43
|
+
Agent acknowledgment + live state indicators (COM-26). Layered onto the
|
|
44
|
+
socket-driven presence model from 0.0.1-beta.5 (PR #24); the awareness
|
|
45
|
+
heartbeat is no longer used — `agentWork` updates ride on the natural
|
|
46
|
+
tool-call cadence instead.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **New tool: `composer_agent_status`.** Lets the agent advance an
|
|
51
|
+
in-flight ack's state without re-sending text, and atomically rewrite
|
|
52
|
+
the ack at completion. Accepts `{ roomId, threadId, replyId?, state,
|
|
53
|
+
text?, note?, kind? }`. `kind` defaults to `"comment"`; set
|
|
54
|
+
`"suggestion"` to target a thread-head agent-authored suggestion. Omit
|
|
55
|
+
`replyId` to update a thread-head record directly; pass it to update a
|
|
56
|
+
reply inside the parent thread. Returns `{ id }` for thread-head
|
|
57
|
+
updates and `{ replyId }` for reply updates.
|
|
58
|
+
- **Optional `state` argument on `composer_reply_comment`,
|
|
59
|
+
`composer_reply_suggestion`, `composer_add_comment`, and
|
|
60
|
+
`composer_add_suggestion`.** Allowed values: `"thinking" | "working" |
|
|
61
|
+
"replying" | "ready"`. Absent = existing behavior (legacy callers
|
|
62
|
+
unaffected).
|
|
63
|
+
- **`invokerUserId` and `invokerName` on the `mention` event payload.**
|
|
64
|
+
Resolved server-side from the triggering reply's or thread's
|
|
65
|
+
`authorUserId` / `authorName`. For `solo_room`, this is the sole human
|
|
66
|
+
in awareness. Lets the model post an ack that `@-mentions` the invoker
|
|
67
|
+
back without a round-trip lookup.
|
|
68
|
+
- **Decision 9 filter on the mention observer.** `attachMentionObserver`
|
|
69
|
+
now skips `active_thread` and `solo_room` emissions when the
|
|
70
|
+
triggering reply has `authorIsAgent === true`. Direct `direct_mention`
|
|
71
|
+
triggers still fire cross-agent (explicit `@<otherAgent>` is
|
|
72
|
+
legitimate). Prevents multi-agent ping-pong amplification on every
|
|
73
|
+
state transition.
|
|
74
|
+
- **Truth-ordering + self-heal in `composer_agent_status`.** On `ready`
|
|
75
|
+
transitions the awareness `agentWork` entry is pruned BEFORE the CRDT
|
|
76
|
+
write, so a mid-op crash leaves at worst an ephemeral anomaly rather
|
|
77
|
+
than a stuck persisted state. Every `composer_agent_status` handler
|
|
78
|
+
call self-heals stale `agentWork` entries whose target record is
|
|
79
|
+
already `ready`.
|
|
80
|
+
|
|
81
|
+
### Host-side SKILL.md
|
|
82
|
+
|
|
83
|
+
- **Ack-first behavior** — the model is now instructed to post a brief
|
|
84
|
+
ack reply (`state: "thinking"` with the invoker in the `mentions[]`
|
|
85
|
+
sidecar) before any substantive work on every mention it decides to
|
|
86
|
+
act on. The ack body is ≤ 24 chars — e.g., `@<invokerName> — on it`.
|
|
87
|
+
- **Generalized "standalone artifact IS the reply" rule.** The old
|
|
88
|
+
"suggestion IS the reply; do not also post a comment reply" guidance
|
|
89
|
+
is superseded by a rule covering any standalone artifact (suggestion,
|
|
90
|
+
cross-span comment on a different anchor, separate document). The ack
|
|
91
|
+
gets rewritten to a thin pointer on completion; no duplicate pointer
|
|
92
|
+
comment is posted.
|
|
93
|
+
- **Progress status section** documents `composer_agent_status`, the
|
|
94
|
+
`thinking → working → replying → ready` state machine, the UI's 400 ms
|
|
95
|
+
minimum-visible collapse window, and the 2-second silence ceiling
|
|
96
|
+
before a progress call is expected.
|
|
97
|
+
- **Worked example** added showing the full ack-then-suggestion flow
|
|
98
|
+
end to end.
|
|
99
|
+
- **Ask-then-auto-suggest reconciliation.** On a yes-variant
|
|
100
|
+
confirmation inside an active ask-then-suggest round-trip, the agent
|
|
101
|
+
skips the ack — the prior reply already delivered the "I heard you"
|
|
102
|
+
signal, and the suggestion is the immediate answer.
|
|
103
|
+
|
|
104
|
+
### Changed
|
|
105
|
+
|
|
106
|
+
- **`addReply` and `addSuggestionReply` on the web side** now accept an
|
|
107
|
+
optional `{ silent?: boolean }` opts bag (propagated to
|
|
108
|
+
`emitActivity`). The MCP does not call these directly, but the
|
|
109
|
+
`composer_agent_status` handler passes `silent: true` internally for
|
|
110
|
+
every non-`ready` transition so the activity feed doesn't spam on
|
|
111
|
+
every `thinking → working → replying` flip. Default is
|
|
112
|
+
`silent: false` — existing callers unaffected.
|
|
113
|
+
|
|
114
|
+
### Infrastructure
|
|
115
|
+
|
|
116
|
+
- **New `mcp/vitest.config.ts`** so `npm -w @composer-app/mcp run test`
|
|
117
|
+
no longer picks up the root `vitest.config.ts`'s `projects` list and
|
|
118
|
+
crashes. Fixes followup #3 for the mcp workspace.
|
|
119
|
+
|
|
120
|
+
### Backward compatibility
|
|
121
|
+
|
|
122
|
+
All additions are strictly additive:
|
|
123
|
+
|
|
124
|
+
- Older clients that don't know the `state` field ignore it on read; the
|
|
125
|
+
ack reply's literal text still renders legibly with no indicator.
|
|
126
|
+
- Older models running a pre-ack-first SKILL.md continue to work — they
|
|
127
|
+
just don't call `composer_agent_status` and go straight from `thinking`
|
|
128
|
+
(if they use the new `state` arg) or a plain reply (if they don't) to
|
|
129
|
+
the final answer.
|
|
130
|
+
- Existing tool handlers preserve their v1 return shapes (`{id}` /
|
|
131
|
+
`{replyId}`); new fields are additive.
|
|
132
|
+
- The `mention` event payload's new `invokerUserId` / `invokerName`
|
|
133
|
+
fields are optional — older consumers that don't read them are
|
|
134
|
+
unaffected.
|
|
135
|
+
|
|
136
|
+
### Rollback
|
|
137
|
+
|
|
138
|
+
Revert `0.0.1-beta.4` to `0.0.1-beta.3`. Browser clients rendering
|
|
139
|
+
`state`-bearing records posted before rollback fall through the
|
|
140
|
+
unknown-state branch and render the record's literal text — no crash, no
|
|
141
|
+
broken layout.
|
|
142
|
+
|
|
143
|
+
## 0.0.1-beta.3 and earlier
|
|
144
|
+
|
|
145
|
+
Unreleased baseline. See git log for commit-level history.
|
package/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# @composer-app/mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [Composer](https://usecomposer.app) — a realtime
|
|
4
|
+
collaborative markdown editor with first-class agent support.
|
|
5
|
+
|
|
6
|
+
The MCP server runs locally under an MCP-capable coding CLI (Claude Code
|
|
7
|
+
today; Codex / OpenCode adapters are follow-up work) and connects to a
|
|
8
|
+
Composer room as a standard Yjs peer. It exposes a small, typed tool
|
|
9
|
+
surface the model uses to read the doc, react to mentions, post
|
|
10
|
+
comments, and suggest edits — all through the same CRDT path humans use.
|
|
11
|
+
|
|
12
|
+
## Install / setup
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @composer-app/mcp@latest setup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Writes `~/.composer/user.json` (persistent machine identity +
|
|
19
|
+
self-chosen display name), registers `composer-mcp` with your coding
|
|
20
|
+
CLI, and installs the host-side SKILL prompt at
|
|
21
|
+
`~/.claude/skills/composer/SKILL.md`.
|
|
22
|
+
|
|
23
|
+
Restart your CLI once setup completes.
|
|
24
|
+
|
|
25
|
+
## Tools
|
|
26
|
+
|
|
27
|
+
### Read
|
|
28
|
+
|
|
29
|
+
- **`composer_attach_room`** — attach to an existing room by ID and
|
|
30
|
+
return a snapshot (full doc markdown, outline, version).
|
|
31
|
+
- **`composer_get_full_doc`** — fetch the current doc as markdown.
|
|
32
|
+
- **`composer_get_section`** — fetch a single section by `headingId`.
|
|
33
|
+
- **`composer_get_thread`** — fetch a thread's body + every reply +
|
|
34
|
+
anchored text + containing section markdown (for catch-up on
|
|
35
|
+
conversations the model was tagged into mid-flight).
|
|
36
|
+
- **`composer_next_event`** — block for up to `timeoutSec` (default
|
|
37
|
+
600 s) waiting for a remote event. Returns `mention` or `timeout`.
|
|
38
|
+
|
|
39
|
+
The `mention` event carries the triggering text, the anchored doc
|
|
40
|
+
range, the containing section as markdown, and (new in 0.0.1-beta.4)
|
|
41
|
+
**`invokerUserId` + `invokerName`** — so the model can `@mention` the
|
|
42
|
+
invoker back without a client-side lookup. The `reason` field is one
|
|
43
|
+
of: `"direct_mention"`, `"active_thread"`, or `"solo_room"`.
|
|
44
|
+
|
|
45
|
+
### Write
|
|
46
|
+
|
|
47
|
+
- **`composer_add_comment`** — comment anchored to text.
|
|
48
|
+
- **`composer_add_suggestion`** — propose a text replacement (lands as
|
|
49
|
+
pending).
|
|
50
|
+
- **`composer_reply_comment`** / **`composer_reply_suggestion`** — reply
|
|
51
|
+
on a thread.
|
|
52
|
+
- **`composer_resolve_thread`** — mark a thread resolved.
|
|
53
|
+
- **`composer_agent_status`** (new in 0.0.1-beta.4) — advance an
|
|
54
|
+
in-flight ack's state, and atomically rewrite the ack's text on
|
|
55
|
+
completion. See [Progress status](#progress-status) below.
|
|
56
|
+
|
|
57
|
+
### Create / join rooms
|
|
58
|
+
|
|
59
|
+
- **`composer_create_room`** — create a new doc, optionally seeded from
|
|
60
|
+
a markdown file or inline string. Returns the browser URL so the
|
|
61
|
+
invoking human can open it.
|
|
62
|
+
- **`composer_join_room`** — attach to an existing room by browser URL.
|
|
63
|
+
|
|
64
|
+
## Agent reply states
|
|
65
|
+
|
|
66
|
+
Every agent-authored reply, comment, or suggestion can carry an
|
|
67
|
+
optional `state` field (new in 0.0.1-beta.4):
|
|
68
|
+
|
|
69
|
+
| State | Meaning | UI |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `thinking` | Ack posted, no tool use yet | Violet status dot + name-row shimmer |
|
|
72
|
+
| `working` | Agent is using tools | Blue dot + indeterminate bar under row |
|
|
73
|
+
| `replying` | Final response is being assembled / streamed | Teal dot + blinking caret |
|
|
74
|
+
| `ready` | Terminal; record holds the final content (or a pointer to a standalone artifact) | Neutral grey dot (no indicator) |
|
|
75
|
+
|
|
76
|
+
The UI also derives a `stalled` view when the agent's awareness
|
|
77
|
+
presence drops while a non-`ready` state persists for > 60 s (4× the
|
|
78
|
+
MCP's 15 s heartbeat) — amber dot with a slower pulse and an inline
|
|
79
|
+
"Retry" affordance.
|
|
80
|
+
|
|
81
|
+
Legacy records and older browsers ignore the `state` field and render
|
|
82
|
+
the literal reply text — no crash, no broken layout.
|
|
83
|
+
|
|
84
|
+
## Progress status
|
|
85
|
+
|
|
86
|
+
The model drives state transitions through the `composer_agent_status`
|
|
87
|
+
tool. The canonical lifecycle:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
# Mention arrives
|
|
91
|
+
composer_next_event() → { kind: "mention", threadId, invokerUserId, invokerName, ... }
|
|
92
|
+
|
|
93
|
+
# 1. Acknowledge first
|
|
94
|
+
composer_reply_comment({
|
|
95
|
+
roomId, threadId,
|
|
96
|
+
text: "@<invokerName> — on it",
|
|
97
|
+
mentions: [invokerUserId],
|
|
98
|
+
state: "thinking",
|
|
99
|
+
}) // → { replyId }
|
|
100
|
+
|
|
101
|
+
# 2. Advance state as you work (optional but recommended for >2 s spans)
|
|
102
|
+
composer_agent_status({
|
|
103
|
+
roomId, threadId, replyId,
|
|
104
|
+
state: "working",
|
|
105
|
+
note: "reading section 3…",
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
# 3. Land the substantive answer
|
|
109
|
+
composer_add_suggestion({ roomId, fromThreadId: threadId, replacementText: "…" })
|
|
110
|
+
|
|
111
|
+
# 4. Atomically rewrite the ack to a pointer + mark ready
|
|
112
|
+
composer_agent_status({
|
|
113
|
+
roomId, threadId, replyId,
|
|
114
|
+
state: "ready",
|
|
115
|
+
text: "Posted a suggestion below.",
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Key invariants:
|
|
120
|
+
|
|
121
|
+
- **Prune awareness before writing `ready` to the CRDT.** The handler
|
|
122
|
+
enforces this internally; a mid-op crash leaves at worst an ephemeral
|
|
123
|
+
anomaly, never a stuck persisted state masked by a stale heartbeat.
|
|
124
|
+
- **Self-heal on handler entry.** Every call prunes awareness entries
|
|
125
|
+
whose target record is already `ready`. Idempotent; converges on
|
|
126
|
+
retries.
|
|
127
|
+
- **Silent intermediate transitions.** Non-`ready` state flips pass
|
|
128
|
+
`silent: true` to the activity-feed path, so the feed only sees the
|
|
129
|
+
initial ack and the final `ready` rewrite.
|
|
130
|
+
|
|
131
|
+
See [`skill/SKILL.md`](./skill/SKILL.md) — shipped with the package and
|
|
132
|
+
installed into your CLI's skill directory by `setup` — for the full
|
|
133
|
+
host-side behavior contract (when to ack vs skip, when suggestion IS
|
|
134
|
+
the reply, ask-then-auto-suggest reconciliation, multi-agent etiquette).
|
|
135
|
+
|
|
136
|
+
## Environment
|
|
137
|
+
|
|
138
|
+
The MCP reads two env vars (set by `setup` when registering with your
|
|
139
|
+
CLI):
|
|
140
|
+
|
|
141
|
+
- `COMPOSER_SERVER_HOST` — the Composer server host (e.g.,
|
|
142
|
+
`usecomposer.app` or `localhost:5173` for local dev).
|
|
143
|
+
- `COMPOSER_APP_BASE` — the base URL of the Composer web app (e.g.,
|
|
144
|
+
`https://usecomposer.app` or `http://localhost:5173`).
|
|
145
|
+
|
|
146
|
+
Identity is stored at `~/.composer/user.json` with mode `0600`.
|
|
147
|
+
Delete the file to reset; setup will prompt for a new name on next run.
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
cd mcp
|
|
153
|
+
npm run typecheck # tsc --noEmit -p .
|
|
154
|
+
npm run build # tsup → dist/cli.js + dist/mcp.js
|
|
155
|
+
npm run test # vitest run (uses mcp/vitest.config.ts; 131 tests as of 0.0.1-beta.4)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT
|