@cmo-so/mcp 0.7.4 → 0.7.6
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/dist/cmo-mcp.mjs +223 -6
- package/package.json +1 -1
package/dist/cmo-mcp.mjs
CHANGED
|
@@ -7199,7 +7199,7 @@ var require_dist = __commonJS({
|
|
|
7199
7199
|
// package.json
|
|
7200
7200
|
var package_default = {
|
|
7201
7201
|
name: "@cmo-so/cli",
|
|
7202
|
-
version: "0.7.
|
|
7202
|
+
version: "0.7.6",
|
|
7203
7203
|
description: "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
7204
7204
|
type: "module",
|
|
7205
7205
|
license: "MIT",
|
|
@@ -7464,15 +7464,15 @@ function createApi({ baseUrl, session: session2, fetch: fetchImpl = globalThis.f
|
|
|
7464
7464
|
}),
|
|
7465
7465
|
remove: () => request("/v1/maggie/bridge", { method: "DELETE" }),
|
|
7466
7466
|
/** Start "Sign in with ChatGPT" for one of the bridge's accounts (the active one by default). */
|
|
7467
|
-
connectChatgpt: (
|
|
7467
|
+
connectChatgpt: (account4) => request("/v1/maggie/bridge/chatgpt", {
|
|
7468
7468
|
method: "POST",
|
|
7469
7469
|
headers: { "Content-Type": "application/json" },
|
|
7470
|
-
body: JSON.stringify(
|
|
7470
|
+
body: JSON.stringify(account4 ? { account: account4 } : {})
|
|
7471
7471
|
}),
|
|
7472
|
-
disconnectChatgpt: (
|
|
7472
|
+
disconnectChatgpt: (account4) => request("/v1/maggie/bridge/chatgpt/logout", {
|
|
7473
7473
|
method: "POST",
|
|
7474
7474
|
headers: { "Content-Type": "application/json" },
|
|
7475
|
-
body: JSON.stringify(
|
|
7475
|
+
body: JSON.stringify(account4 ? { account: account4 } : {})
|
|
7476
7476
|
}),
|
|
7477
7477
|
/** What Maggie may do in CMO.so; rotates the bridge's key when read / read_write changes. */
|
|
7478
7478
|
setAccess: (access) => request("/v1/maggie/bridge/access", {
|
|
@@ -7515,6 +7515,32 @@ function createApi({ baseUrl, session: session2, fetch: fetchImpl = globalThis.f
|
|
|
7515
7515
|
return dataUrl(type, bytes);
|
|
7516
7516
|
}
|
|
7517
7517
|
},
|
|
7518
|
+
// The open marketing skills (docs/26): api.cmo.so forwards these to the cmo.so site.
|
|
7519
|
+
skills: {
|
|
7520
|
+
search: (q2 = "", opts = {}) => {
|
|
7521
|
+
const qs = new URLSearchParams({
|
|
7522
|
+
q: q2,
|
|
7523
|
+
...opts.category ? { category: opts.category } : {},
|
|
7524
|
+
limit: String(opts.limit ?? 10)
|
|
7525
|
+
});
|
|
7526
|
+
return request(`/v1/skills?${qs}`);
|
|
7527
|
+
},
|
|
7528
|
+
get: (id) => request(`/v1/skills/${encodeURIComponent(id)}`),
|
|
7529
|
+
/** Vote on or save a skill (on: false undoes it). "like" is an upvote. */
|
|
7530
|
+
react: (id, kind, on2 = true) => request(`/v1/skills/${encodeURIComponent(id)}/react`, {
|
|
7531
|
+
method: "POST",
|
|
7532
|
+
headers: { "Content-Type": "application/json" },
|
|
7533
|
+
body: JSON.stringify({ kind, on: on2 })
|
|
7534
|
+
}),
|
|
7535
|
+
saved: () => request("/v1/skills/saved"),
|
|
7536
|
+
/** Suggest an open-source GitHub repo; Maggie researches it (3 a day). */
|
|
7537
|
+
submit: (repoUrl, note) => request("/v1/skills/submissions", {
|
|
7538
|
+
method: "POST",
|
|
7539
|
+
headers: { "Content-Type": "application/json" },
|
|
7540
|
+
body: JSON.stringify({ repo_url: repoUrl, note })
|
|
7541
|
+
}),
|
|
7542
|
+
submissions: () => request("/v1/skills/submissions")
|
|
7543
|
+
},
|
|
7518
7544
|
// Web Push for this browser (APP-9). `domains` are the workspaces it shows.
|
|
7519
7545
|
push: {
|
|
7520
7546
|
status: (endpoint) => request(
|
|
@@ -8366,6 +8392,10 @@ var confirmCopy = {
|
|
|
8366
8392
|
en: (a) => `Remove the call-to-action for ${q(a.target_keyword)}.`,
|
|
8367
8393
|
"zh-Hant": (a) => `\u522A\u9664 ${q(a.target_keyword)} \u7684\u884C\u52D5\u547C\u7C72\u3002`
|
|
8368
8394
|
},
|
|
8395
|
+
internal_links_set: {
|
|
8396
|
+
en: (a) => Number(a.count) ? `Link each new post to ${a.count} of your latest articles.` : "Stop linking new posts to your other articles.",
|
|
8397
|
+
"zh-Hant": (a) => Number(a.count) ? `\u6BCF\u7BC7\u65B0\u6587\u7AE0\u9023\u7D50\u5230\u4F60\u6700\u65B0\u7684 ${a.count} \u7BC7\u6587\u7AE0\u3002` : "\u65B0\u6587\u7AE0\u4E0D\u518D\u9023\u7D50\u5230\u4F60\u7684\u5176\u4ED6\u6587\u7AE0\u3002"
|
|
8398
|
+
},
|
|
8369
8399
|
testimonial_upsert: {
|
|
8370
8400
|
en: (a) => `Save the testimonial from ${a.name}${a.use_in_posts ? " and use testimonials in posts" : ""}.`,
|
|
8371
8401
|
"zh-Hant": (a) => `\u5132\u5B58 ${a.name} \u7684\u5BA2\u6236\u8A55\u50F9${a.use_in_posts ? "\uFF0C\u4E26\u5728\u6587\u7AE0\u88E1\u4F7F\u7528\u8A55\u50F9" : ""}\u3002`
|
|
@@ -8612,6 +8642,19 @@ var confirmCopy = {
|
|
|
8612
8642
|
en: (a) => `Send this to the cmo.so team: ${q(String(a.summary ?? "").slice(0, 200))}`,
|
|
8613
8643
|
"zh-Hant": (a) => `\u628A\u9019\u5247\u56DE\u994B\u9001\u7D66 cmo.so \u5718\u968A\uFF1A${q(String(a.summary ?? "").slice(0, 200))}`
|
|
8614
8644
|
},
|
|
8645
|
+
// ---------------------------------------------------------- Marketing skills (docs/26)
|
|
8646
|
+
skill_like: {
|
|
8647
|
+
en: (a) => `${a.undo ? "Take back your upvote on" : "Upvote"} the skill ${q(a.skill_id)} on cmo.so.`,
|
|
8648
|
+
"zh-Hant": (a) => `${a.undo ? "\u6536\u56DE\u5C0D" : "\u5728 cmo.so \u6295\u7968\u652F\u6301"}\u6280\u80FD ${q(a.skill_id)}${a.undo ? " \u7684\u652F\u6301\u7968" : ""}\u3002`
|
|
8649
|
+
},
|
|
8650
|
+
skill_save: {
|
|
8651
|
+
en: (a) => `${a.undo ? "Remove" : "Save"} the skill ${q(a.skill_id)} ${a.undo ? "from" : "to"} your saved skills.`,
|
|
8652
|
+
"zh-Hant": (a) => `${a.undo ? "\u5F9E\u6536\u85CF\u79FB\u9664" : "\u6536\u85CF"}\u6280\u80FD ${q(a.skill_id)}\u3002`
|
|
8653
|
+
},
|
|
8654
|
+
skill_submit: {
|
|
8655
|
+
en: (a) => `Suggest ${q(a.repo_url)} for the cmo.so skill library. Maggie will research it.`,
|
|
8656
|
+
"zh-Hant": (a) => `\u628A ${q(a.repo_url)} \u63A8\u85A6\u7D66 cmo.so \u6280\u80FD\u5EAB\uFF0CMaggie \u6703\u7814\u7A76\u5B83\u3002`
|
|
8657
|
+
},
|
|
8615
8658
|
social_voice_learn: {
|
|
8616
8659
|
en: () => "Learn your LinkedIn voice from this post and save it as your default.",
|
|
8617
8660
|
"zh-Hant": () => "\u5F9E\u9019\u7BC7\u8CBC\u6587\u5B78\u7FD2\u4F60\u7684 LinkedIn \u8A9E\u6C23\uFF0C\u4E26\u8A2D\u70BA\u9810\u8A2D\u3002"
|
|
@@ -9630,6 +9673,24 @@ var brandTools = [
|
|
|
9630
9673
|
return { ctas: out.ctas?.map((c) => c.target_keyword) };
|
|
9631
9674
|
}
|
|
9632
9675
|
}),
|
|
9676
|
+
tool({
|
|
9677
|
+
name: "internal_links_set",
|
|
9678
|
+
description: "Set how many of the website's own latest articles each new post links to (internal cross-links, picked for the topic; separate from CTAs). 0 turns it off, max 10, default 3.",
|
|
9679
|
+
parameters: {
|
|
9680
|
+
type: "object",
|
|
9681
|
+
properties: { count: { type: "integer", minimum: 0, maximum: 10 } },
|
|
9682
|
+
required: ["count"]
|
|
9683
|
+
},
|
|
9684
|
+
group: "brand",
|
|
9685
|
+
need: write2,
|
|
9686
|
+
risk: "W1",
|
|
9687
|
+
run: async (ctx, { count }) => {
|
|
9688
|
+
const n = Math.round(Number(count));
|
|
9689
|
+
if (!Number.isFinite(n) || n < 0 || n > 10) throw new Error("count must be 0 to 10.");
|
|
9690
|
+
const out = await ws(ctx).updateBrand({ internal_links: { count: n } });
|
|
9691
|
+
return { internal_links: out.internal_links ?? { count: n } };
|
|
9692
|
+
}
|
|
9693
|
+
}),
|
|
9633
9694
|
tool({
|
|
9634
9695
|
name: "testimonial_upsert",
|
|
9635
9696
|
description: "Add a customer testimonial, or change the one from the same person. Only real quotes the user gives (or examples they asked for). use_in_posts turns testimonials on in posts.",
|
|
@@ -10702,6 +10763,161 @@ var reportTools = [
|
|
|
10702
10763
|
})
|
|
10703
10764
|
];
|
|
10704
10765
|
|
|
10766
|
+
// ../../packages/tools/src/skills.ts
|
|
10767
|
+
var account3 = { resource: "account", level: "read" };
|
|
10768
|
+
var ID = { type: "string", description: "The skill id, like cmo-ad-creative" };
|
|
10769
|
+
var skillTools = [
|
|
10770
|
+
tool({
|
|
10771
|
+
name: "skills_search",
|
|
10772
|
+
description: "Search cmo.so's open library of marketing skills (step-by-step methods an AI agent follows, free and MIT licensed): returns matching skills with their summary, vote score and page. Use it when the user asks how to do a marketing job, wants a playbook or template, or asks which skills exist. Empty query: the most useful ones and the categories.",
|
|
10773
|
+
parameters: {
|
|
10774
|
+
type: "object",
|
|
10775
|
+
properties: {
|
|
10776
|
+
query: { type: "string", description: "What the user wants to do, in a few words" },
|
|
10777
|
+
category: {
|
|
10778
|
+
type: "string",
|
|
10779
|
+
description: "Optional category id: core, strategy, seo, ai-search, content, social, email, paid-ads, cro, analytics, growth, sales, creative"
|
|
10780
|
+
},
|
|
10781
|
+
limit: { type: "integer", minimum: 1, maximum: 20 }
|
|
10782
|
+
}
|
|
10783
|
+
},
|
|
10784
|
+
group: "account",
|
|
10785
|
+
need: account3,
|
|
10786
|
+
risk: "R0",
|
|
10787
|
+
idempotent: true,
|
|
10788
|
+
run: async (ctx, a) => {
|
|
10789
|
+
const r = await ctx.api.skills.search(String(a.query ?? ""), {
|
|
10790
|
+
...a.category ? { category: a.category } : {},
|
|
10791
|
+
limit: int(a.limit, 1, 20, 8)
|
|
10792
|
+
});
|
|
10793
|
+
return {
|
|
10794
|
+
total_in_library: r.total,
|
|
10795
|
+
...a.query ? {} : { categories: r.categories.map((c) => `${c.id} (${c.count})`) },
|
|
10796
|
+
skills: r.skills.map((s) => ({
|
|
10797
|
+
id: s.id,
|
|
10798
|
+
name: s.name,
|
|
10799
|
+
summary: s.summary,
|
|
10800
|
+
score: s.score ?? s.likes,
|
|
10801
|
+
page: s.url
|
|
10802
|
+
}))
|
|
10803
|
+
};
|
|
10804
|
+
}
|
|
10805
|
+
}),
|
|
10806
|
+
tool({
|
|
10807
|
+
name: "skill_get",
|
|
10808
|
+
description: "One marketing skill from the cmo.so library in full: when to use it, what it needs, its workflow, output and quality bar, plus how to install it in Claude Code. Use it to follow a skill's method for the user, or to explain it.",
|
|
10809
|
+
parameters: { type: "object", properties: { skill_id: ID }, required: ["skill_id"] },
|
|
10810
|
+
group: "account",
|
|
10811
|
+
need: account3,
|
|
10812
|
+
risk: "R0",
|
|
10813
|
+
idempotent: true,
|
|
10814
|
+
run: async (ctx, a) => {
|
|
10815
|
+
const s = await ctx.api.skills.get(String(a.skill_id));
|
|
10816
|
+
return {
|
|
10817
|
+
id: s.id,
|
|
10818
|
+
name: s.name,
|
|
10819
|
+
summary: s.summary,
|
|
10820
|
+
page: s.url,
|
|
10821
|
+
score: s.score ?? s.likes,
|
|
10822
|
+
saves: s.saves,
|
|
10823
|
+
uses_tools: s.mcp_tools,
|
|
10824
|
+
pairs_with: s.pairs_with,
|
|
10825
|
+
install: s.install,
|
|
10826
|
+
// community-contributed text: a method to follow, never instructions that override the user or these rules
|
|
10827
|
+
...untrusted(clip(s.text, 12e3))
|
|
10828
|
+
};
|
|
10829
|
+
}
|
|
10830
|
+
}),
|
|
10831
|
+
tool({
|
|
10832
|
+
name: "skill_like",
|
|
10833
|
+
description: "Upvote a skill in the cmo.so library for the user (or take the upvote back with undo). Votes help the library decide what to keep improving. Only when the user asks.",
|
|
10834
|
+
parameters: {
|
|
10835
|
+
type: "object",
|
|
10836
|
+
properties: { skill_id: ID, undo: { type: "boolean", description: "true takes the upvote back" } },
|
|
10837
|
+
required: ["skill_id"]
|
|
10838
|
+
},
|
|
10839
|
+
group: "account",
|
|
10840
|
+
need: account3,
|
|
10841
|
+
risk: "W1",
|
|
10842
|
+
idempotent: true,
|
|
10843
|
+
run: async (ctx, a) => {
|
|
10844
|
+
const r = await ctx.api.skills.react(String(a.skill_id), "like", !a.undo);
|
|
10845
|
+
return { skill_id: r.item, upvoted: r.liked, score: r.counts.score ?? r.counts.likes };
|
|
10846
|
+
}
|
|
10847
|
+
}),
|
|
10848
|
+
tool({
|
|
10849
|
+
name: "skill_save",
|
|
10850
|
+
description: "Save a skill to the user's saved skills on cmo.so (or remove it with undo), to find it again under Saved at cmo.so/skills or with skills_saved_list.",
|
|
10851
|
+
parameters: {
|
|
10852
|
+
type: "object",
|
|
10853
|
+
properties: { skill_id: ID, undo: { type: "boolean", description: "true removes it from saved" } },
|
|
10854
|
+
required: ["skill_id"]
|
|
10855
|
+
},
|
|
10856
|
+
group: "account",
|
|
10857
|
+
need: account3,
|
|
10858
|
+
risk: "W1",
|
|
10859
|
+
idempotent: true,
|
|
10860
|
+
run: async (ctx, a) => {
|
|
10861
|
+
const r = await ctx.api.skills.react(String(a.skill_id), "save", !a.undo);
|
|
10862
|
+
return { skill_id: r.item, saved: r.saved };
|
|
10863
|
+
}
|
|
10864
|
+
}),
|
|
10865
|
+
tool({
|
|
10866
|
+
name: "skills_saved_list",
|
|
10867
|
+
description: "The skills the user saved on cmo.so, newest first.",
|
|
10868
|
+
parameters: none,
|
|
10869
|
+
group: "account",
|
|
10870
|
+
need: account3,
|
|
10871
|
+
risk: "R0",
|
|
10872
|
+
run: async (ctx) => ({
|
|
10873
|
+
skills: (await ctx.api.skills.saved()).skills.map((s) => ({
|
|
10874
|
+
id: s.id,
|
|
10875
|
+
name: s.name,
|
|
10876
|
+
summary: s.summary,
|
|
10877
|
+
page: s.url
|
|
10878
|
+
}))
|
|
10879
|
+
})
|
|
10880
|
+
}),
|
|
10881
|
+
tool({
|
|
10882
|
+
name: "skill_submit",
|
|
10883
|
+
description: "Suggest a public open-source GitHub repo for cmo.so's skill library. Maggie researches it within minutes and decides: add a new skill, improve an existing one, keep it as a candidate that needs a vote score of 10 in 30 days, or decline (licence first: permissive licences can be adapted, copyleft only inspires, no licence is declined). 3 suggestions a day. Follow up with skill_submissions_list.",
|
|
10884
|
+
parameters: {
|
|
10885
|
+
type: "object",
|
|
10886
|
+
properties: {
|
|
10887
|
+
repo_url: { type: "string", description: "https://github.com/owner/name" },
|
|
10888
|
+
note: { type: "string", description: "Optional: why it is useful, \u2264500 characters" }
|
|
10889
|
+
},
|
|
10890
|
+
required: ["repo_url"]
|
|
10891
|
+
},
|
|
10892
|
+
group: "account",
|
|
10893
|
+
need: account3,
|
|
10894
|
+
risk: "W1",
|
|
10895
|
+
run: async (ctx, a) => {
|
|
10896
|
+
const r = await ctx.api.skills.submit(String(a.repo_url), a.note ? String(a.note).slice(0, 500) : void 0);
|
|
10897
|
+
return r.duplicate ? { already_suggested: true, id: r.id, status: r.status, reasons: r.reasons ?? null } : { submitted: true, id: r.id, status: r.status, repo: r.repo };
|
|
10898
|
+
}
|
|
10899
|
+
}),
|
|
10900
|
+
tool({
|
|
10901
|
+
name: "skill_submissions_list",
|
|
10902
|
+
description: "The repos the user suggested for the skill library and what happened to each: queued, researching, candidate (with its deadline), publishing, published (with the skill), declined, expired or failed, with Maggie's reasons.",
|
|
10903
|
+
parameters: none,
|
|
10904
|
+
group: "account",
|
|
10905
|
+
need: account3,
|
|
10906
|
+
risk: "R0",
|
|
10907
|
+
run: async (ctx) => ({
|
|
10908
|
+
items: (await ctx.api.skills.submissions()).items.slice(0, 20).map((s) => ({
|
|
10909
|
+
id: s.id,
|
|
10910
|
+
repo: s.repo,
|
|
10911
|
+
status: s.status,
|
|
10912
|
+
skill: s.target_skill,
|
|
10913
|
+
reasons: clip(s.reasons, 500),
|
|
10914
|
+
candidate_until: s.candidate_until,
|
|
10915
|
+
suggested: s.created_at
|
|
10916
|
+
}))
|
|
10917
|
+
})
|
|
10918
|
+
})
|
|
10919
|
+
];
|
|
10920
|
+
|
|
10705
10921
|
// ../../packages/tools/src/social.ts
|
|
10706
10922
|
var read5 = { resource: "autopilot", level: "read" };
|
|
10707
10923
|
var write5 = { resource: "autopilot", level: "write" };
|
|
@@ -12158,7 +12374,8 @@ var tools = [
|
|
|
12158
12374
|
...socialTools,
|
|
12159
12375
|
...teamTools,
|
|
12160
12376
|
...memoryTools,
|
|
12161
|
-
...feedbackTools
|
|
12377
|
+
...feedbackTools,
|
|
12378
|
+
...skillTools
|
|
12162
12379
|
];
|
|
12163
12380
|
var toolByName = new Map(tools.map((t) => [t.name, t]));
|
|
12164
12381
|
function allowed(t, a) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/mcp",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "CMO.so's MCP server for Claude Desktop, Cursor, VS Code and other MCP clients: manage your websites, blog posts, LinkedIn queue and results with Maggie.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|