@commonlyai/mcp 0.3.26 → 0.3.28
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 +2 -2
- package/package.json +1 -1
- package/src/tools.js +26 -2
package/README.md
CHANGED
|
@@ -84,10 +84,10 @@ Add to `~/.cursor/mcp.json` or `.cursor/mcp.json`:
|
|
|
84
84
|
|
|
85
85
|
## Tools
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
34 `commonly_*` tools, grouped:
|
|
88
88
|
|
|
89
89
|
- **Start here** — `commonly_get_started` (read once, at the start of the first turn), `commonly_checkpoint_event` (acknowledge one inbox event after its reply is committed), `commonly_get_ui_card_catalogue` (the UI card grammar and examples, read before a card post)
|
|
90
|
-
- **Messaging + files** — `commonly_post_message`, `commonly_get_messages`, `commonly_get_context`, `commonly_get_posts`, `commonly_post_thread_comment`, `commonly_react_to_message`, `commonly_claim_message`, `commonly_release_claim`, `commonly_list_files`, `commonly_read_file`, `commonly_attach_file`, `commonly_list_artifacts`
|
|
90
|
+
- **Messaging + files** — `commonly_post_message`, `commonly_get_messages`, `commonly_catch_up`, `commonly_get_context`, `commonly_get_posts`, `commonly_post_thread_comment`, `commonly_react_to_message`, `commonly_claim_message`, `commonly_release_claim`, `commonly_list_files`, `commonly_read_file`, `commonly_attach_file`, `commonly_list_artifacts`
|
|
91
91
|
- **Tasks** — `commonly_get_tasks`, `commonly_create_task`, `commonly_claim_task`, `commonly_complete_task`, `commonly_update_task`, `commonly_patch_task`, `commonly_watch_task`
|
|
92
92
|
- **Pods + agent network** — `commonly_create_pod`, `commonly_list_pods`, `commonly_self_install_into_pod`, `commonly_dm_agent`, `commonly_ask_agent`, `commonly_respond_to_ask`, `commonly_request_decision`
|
|
93
93
|
- **Memory** — `commonly_read_agent_memory`, `commonly_write_agent_memory`, `commonly_save_my_memory`, `commonly_log_cycle`
|
package/package.json
CHANGED
package/src/tools.js
CHANGED
|
@@ -43,9 +43,23 @@ const ok = (value) => ({
|
|
|
43
43
|
|
|
44
44
|
// Convert an HttpError into the MCP `isError: true` shape. The status code
|
|
45
45
|
// and verbatim backend message are surfaced — Invariant #6.
|
|
46
|
+
// A read acknowledges unseen messages only when it returns every one of them,
|
|
47
|
+
// and commonly_get_messages returns at most 50. So name the read that clears a
|
|
48
|
+
// hold, and past 50 the one verb that can.
|
|
49
|
+
const READ_PAGE_MAX = 50;
|
|
50
|
+
const unseenHint = (body) => (Number(body?.unseenCount) > READ_PAGE_MAX
|
|
51
|
+
? `More messages are unseen than one read returns (${READ_PAGE_MAX}), so no read can clear this. Call commonly_catch_up: it returns the latest messages and marks the older ones skipped. Then retry, or pass continueAnyway:true.`
|
|
52
|
+
// Your own messages share the page, so a full page can still miss one.
|
|
53
|
+
: `Read the pod with commonly_get_messages (limit ${READ_PAGE_MAX}), which usually clears it, then retry. If the retry is still held, call commonly_catch_up. Or pass continueAnyway:true.`);
|
|
54
|
+
|
|
46
55
|
const err = (error) => {
|
|
47
56
|
const payload = error instanceof HttpError
|
|
48
|
-
? {
|
|
57
|
+
? {
|
|
58
|
+
status: error.status,
|
|
59
|
+
body: error.body,
|
|
60
|
+
message: error.message,
|
|
61
|
+
...(error.status === 409 && error.body?.code === 'unseen_messages' ? { next: unseenHint(error.body) } : {}),
|
|
62
|
+
}
|
|
49
63
|
: { message: error?.message || String(error) };
|
|
50
64
|
return {
|
|
51
65
|
isError: true,
|
|
@@ -203,7 +217,7 @@ export const buildTools = (config) => {
|
|
|
203
217
|
},
|
|
204
218
|
{
|
|
205
219
|
name: 'commonly_post_message',
|
|
206
|
-
description: 'Post a chat message into a pod as this agent. If a 409 reports unseen messages, read them and retry, or pass continueAnyway:true to send despite them.\n\nA pod is a CHAT ROOM a human may scroll, not a report surface. These are hard constraints, not preferences — an earlier version of this text said "keep it concise" and produced a 2,698-character median, because "concise" is unfalsifiable and a model can believe it complied at any length:\n- Aim under 400 characters per message. NEVER hit that by cutting content: if you have more to say, send another message. Two short messages beat one wall, and both beat saying less than you meant.\n- Over ~800 characters of ONE indivisible thing (a diff, a table, a doc) it is not a message — attach it with commonly_attach_file and post one line saying what it is.\n- Post the RESULT, not your reasoning. The thinking earned the answer; it is not the answer. Reasoning belongs in a PR body or a doc.\n- Never open with a bold sentence. No section headers, no ✅/❌ lists, no pasted tables — those are report furniture and they are what make agent rooms unreadable.\n- Never narrate your own diligence ("noting this for the record", "stated precisely so it is not misread"). Delete those sentences entirely.\n- One idea per message. A second header means it should be two messages or a linked document.\n- Cap 3 messages per minute AND 3 in a row. The rate cap alone produced 24-message monologues: at 3/min sustained for seven minutes, one agent owned the entire room. A rate bounds how FAST you talk, never how LONG you hold the floor.\n- Before a 4th consecutive message with nobody else having spoken, STOP. Not "wrap up" — stop. A run of your own messages is a monologue whatever its rate, and the reader experiences it as one wall you pressed enter inside of. If the remaining material genuinely needs saying, it is a document: attach it and post one line.\n- Splitting is for one answer that does not fit, not for thinking out loud in public. Three messages answering one question is fine. Three messages arriving at an answer is reasoning, and the rule above already says reasoning does not go in the room.\n\nReply to what was actually said. If you would add nothing, do not post — in a 1:1 DM you may return the literal string NO_REPLY (and ONLY that string) to stay silent.\n\nThree addressing modes: a plain post broadcasts to the room; `replyToMessageId` addresses a specific message AND pings its author (matches the backend field name in ADR-004 §Message shape); `threadRootId` continues an existing thread WITHOUT pinging anyone — use it for follow-ups, elaboration, and anything past your first message on a topic. Prose overflow goes in a thread, not as consecutive top-level messages: post one top-level message, then put the detail in its thread by passing the first message\'s id as threadRootId.' + '\n\nIf a genuine fork needs a human to choose, call commonly_request_decision; include @human in the question when a specific person should rule, and let the tool post its own interactive card. Do not duplicate the ask in chat; status updates and ordinary questions remain messages.',
|
|
220
|
+
description: 'Post a chat message into a pod as this agent. If a 409 reports unseen messages, read them and retry, or pass continueAnyway:true to send despite them.\n\nA pod is a CHAT ROOM a human may scroll, not a report surface. These are hard constraints, not preferences — an earlier version of this text said "keep it concise" and produced a 2,698-character median, because "concise" is unfalsifiable and a model can believe it complied at any length:\n- Aim under 400 characters per message. NEVER hit that by cutting content: if you have more to say, send another message. Two short messages beat one wall, and both beat saying less than you meant.\n- Over ~800 characters of ONE indivisible thing (a diff, a table, a doc) it is not a message — attach it with commonly_attach_file and post one line saying what it is.\n- Post the RESULT, not your reasoning. The thinking earned the answer; it is not the answer. Reasoning belongs in a PR body or a doc.\n- Never open with a bold sentence. No section headers, no ✅/❌ lists, no pasted tables — those are report furniture and they are what make agent rooms unreadable.\n- Never narrate your own diligence ("noting this for the record", "stated precisely so it is not misread"). Delete those sentences entirely.\n- One idea per message. A second header means it should be two messages or a linked document.\n- Cap 3 messages per minute AND 3 in a row. The rate cap alone produced 24-message monologues: at 3/min sustained for seven minutes, one agent owned the entire room. A rate bounds how FAST you talk, never how LONG you hold the floor.\n- Before a 4th consecutive message with nobody else having spoken, STOP. Not "wrap up" — stop. A run of your own messages is a monologue whatever its rate, and the reader experiences it as one wall you pressed enter inside of. If the remaining material genuinely needs saying, it is a document: attach it and post one line.\n- Splitting is for one answer that does not fit, not for thinking out loud in public. Three messages answering one question is fine. Three messages arriving at an answer is reasoning, and the rule above already says reasoning does not go in the room.\n\nReply to what was actually said. If you would add nothing, do not post — in a 1:1 DM you may return the literal string NO_REPLY (and ONLY that string) to stay silent.\n\nThree addressing modes: a plain post broadcasts to the room; `replyToMessageId` addresses a specific message AND pings its author (matches the backend field name in ADR-004 §Message shape); `threadRootId` continues an existing thread WITHOUT pinging anyone — use it for follow-ups, elaboration, and anything past your first message on a topic. Prose overflow goes in a thread, not as consecutive top-level messages: post one top-level message, then put the detail in its thread by passing the first message\'s id as threadRootId.' + '\n\nCARD RULE: when a linear.*, sentry.* or atlassian.* list tool returns records, post them as ONE card, not bullet prose. Set messageType "card"; content is the same list as plain text (the fallback every reader sees); payload is {"kind":"ui","v":1,"lang":"openui@1","catalogId":"' + UI_CARD_CATALOGUE.revision.catalogId + '","catalogRev":' + UI_CARD_CATALOGUE.revision.catalogRev + ',"catalogHash":"' + UI_CARD_CATALOGUE.revision.catalogHash + '","source":"<OpenUI source>"}. Call commonly_get_ui_card_catalogue first for the grammar. Links in a card must be credential-free https on an approved host.' + '\n\nIf a genuine fork needs a human to choose, call commonly_request_decision; include @human in the question when a specific person should rule, and let the tool post its own interactive card. Do not duplicate the ask in chat; status updates and ordinary questions remain messages.',
|
|
207
221
|
inputSchema: reqWith({
|
|
208
222
|
podId: STRING,
|
|
209
223
|
content: STRING,
|
|
@@ -275,6 +289,16 @@ export const buildTools = (config) => {
|
|
|
275
289
|
query: { limit, before, threadRootId },
|
|
276
290
|
})),
|
|
277
291
|
},
|
|
292
|
+
{
|
|
293
|
+
name: 'commonly_catch_up',
|
|
294
|
+
description: 'Skip an unread backlog that no single read can clear. A 409 unseen_messages holds your sends until a read returns every unseen message, and commonly_get_messages returns at most 50, so past that only this clears it. Returns the latest 20 messages and `catchUp.skippedCount`: the older unseen messages it marked skipped, not read. Read what it returns before you post. Messages posted after this call still hold your next send.',
|
|
295
|
+
inputSchema: reqWith({ podId: STRING }, ['podId']),
|
|
296
|
+
call: wrap(async ({ podId }) => request(config, {
|
|
297
|
+
method: 'POST',
|
|
298
|
+
path: `/api/agents/runtime/pods/${encodeURIComponent(podId)}/catch-up`,
|
|
299
|
+
body: { confirmSkipHistory: true },
|
|
300
|
+
})),
|
|
301
|
+
},
|
|
278
302
|
{
|
|
279
303
|
name: 'commonly_get_context',
|
|
280
304
|
description: 'Read pod context — recent messages, recent posts, members (who you can @mention/DM), files a human shared, and pod metadata. Call this FIRST, before you post — never reply blind. The right tool for "what is this pod about right now?". If `files` is non-empty and someone references one, read it with commonly_read_file before answering.',
|