@cmo-so/mcp 0.7.1 → 0.7.3

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.
Files changed (2) hide show
  1. package/dist/cmo-mcp.mjs +119 -3
  2. 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.1",
7202
+ version: "0.7.3",
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",
@@ -7410,6 +7410,14 @@ function createApi({ baseUrl, session: session2, fetch: fetchImpl = globalThis.f
7410
7410
  apps: () => request("/v1/me/apps"),
7411
7411
  revokeApp: (grantId) => request(`/v1/me/apps/${encodeURIComponent(grantId)}`, { method: "DELETE" }),
7412
7412
  invoices: () => request("/v1/me/invoices"),
7413
+ /**
7414
+ * Take a website off your own list (archives your claim; reversible on ai.cmo.so). Nothing changes for
7415
+ * anyone else; a team member also leaves the team.
7416
+ */
7417
+ removeWebsite: (domain) => request(
7418
+ `/v1/me/websites/${encodeURIComponent(domain)}/remove`,
7419
+ { method: "POST" }
7420
+ ),
7413
7421
  /** Delete the account (only from the person's own sign-in). Websites stay, unclaimed; plans stop renewing. */
7414
7422
  delete: () => request("/v1/me/delete", {
7415
7423
  method: "POST",
@@ -7697,6 +7705,11 @@ function domainApi(api2, domain) {
7697
7705
  wordpressPlugin: () => api2.request(`${base}/wordpress-plugin`),
7698
7706
  // Writes (need autopilot write on the domain).
7699
7707
  addIdea: (input) => post(`${base}/ideas`, input),
7708
+ /**
7709
+ * Up to 100 ideas exactly as given (no AI, no generation used): they wait in the pool, not the plan, and count
7710
+ * toward the 100 waiting ideas a person may add. Duplicates (title or page) are skipped and listed.
7711
+ */
7712
+ addIdeas: (ideas) => post(`${base}/ideas/bulk`, { ideas }),
7700
7713
  /** Ideas built on up to 10 photos (base64 JPEG). The server keeps no copy. */
7701
7714
  ideasFromPhotos: (photos, count, brief2 = "") => post(`${base}/ideas/from-photos`, { photos, count, brief: brief2 }),
7702
7715
  generateIdeas: (count, brief2 = "") => post(`${base}/ideas/generate`, { count, brief: brief2 }),
@@ -8146,6 +8159,18 @@ function domainApi(api2, domain) {
8146
8159
  body: JSON.stringify(r)
8147
8160
  }
8148
8161
  ),
8162
+ /** Competitors Maggie found with Google Search, waiting for the user to add or dismiss (docs/25). */
8163
+ competitorSuggestions: () => api2.request(
8164
+ `${base}/competitors/suggestions`
8165
+ ),
8166
+ /** Put a suggestion in the business profile's competitors. */
8167
+ addCompetitorSuggestion: (id) => post(
8168
+ `${base}/competitors/suggestions/${encodeURIComponent(id)}/add`
8169
+ ),
8170
+ /** Not a competitor: never suggested or read for ideas again. */
8171
+ dismissCompetitorSuggestion: (id) => post(`${base}/competitors/suggestions/${encodeURIComponent(id)}/dismiss`),
8172
+ /** Look for new competitors now (once a day; subscribed websites only, else 402). */
8173
+ refreshCompetitorSuggestions: () => post(`${base}/competitors/suggestions/refresh`),
8149
8174
  /** The last time posts delivered by API pull were found in the website's sitemap (gives them their address). */
8150
8175
  sitemapMatch: () => api2.request(`${base}/rewrites/sitemap-match`),
8151
8176
  /** Read the sitemap (found on its own when blank) and match API-pull posts to their live address. */
@@ -9339,6 +9364,41 @@ var blogTools = [
9339
9364
  return ws(ctx).addIdea(url ? { url } : { text: text3 });
9340
9365
  }
9341
9366
  }),
9367
+ tool({
9368
+ name: "ideas_add_list",
9369
+ description: "Add up to 100 ideas exactly as given (a researched list): title, description, primary keyword, up to 5 more keywords, a benchmark URL (read as research, never linked), priority 1-10 and optionally one of the website's topics. No AI rewrites them and no generation is used; they wait in the idea pool, not the plan. Duplicates are skipped and listed; at most 100 of a person's own ideas can wait at once.",
9370
+ parameters: {
9371
+ type: "object",
9372
+ properties: {
9373
+ ideas: {
9374
+ type: "array",
9375
+ items: {
9376
+ type: "object",
9377
+ properties: {
9378
+ title: { type: "string" },
9379
+ description: { type: "string" },
9380
+ keyword: { type: "string", description: "The primary keyword" },
9381
+ keywords: { type: "array", items: { type: "string" } },
9382
+ url: { type: "string", description: "A benchmark page" },
9383
+ priority: { type: "integer", minimum: 1, maximum: 10 },
9384
+ topic: { type: "string", description: "One of topics_list, if it fits" }
9385
+ },
9386
+ required: ["title"]
9387
+ }
9388
+ }
9389
+ },
9390
+ required: ["ideas"]
9391
+ },
9392
+ group: "blog",
9393
+ need: write,
9394
+ risk: "W1",
9395
+ run: async (ctx, { ideas }) => {
9396
+ if (!ideas?.length) throw new Error("Give at least one idea.");
9397
+ if (ideas.length > 100) throw new Error("Up to 100 ideas at a time.");
9398
+ const out = await ws(ctx).addIdeas(ideas);
9399
+ return { added: out.added, skipped: out.skipped, room_left: out.room_left };
9400
+ }
9401
+ }),
9342
9402
  tool({
9343
9403
  name: "ideas_generate",
9344
9404
  description: "Let Maggie come up with new ideas (1\u201310) with AI, optionally about a theme.",
@@ -9410,7 +9470,7 @@ var blogTools = [
9410
9470
  }),
9411
9471
  tool({
9412
9472
  name: "idea_plan",
9413
- description: "Add a waiting idea to the end of the plan (the plan holds at most 10).",
9473
+ description: "Add a waiting idea to the end of the plan (the plan holds up to 100).",
9414
9474
  parameters: {
9415
9475
  type: "object",
9416
9476
  properties: {
@@ -9701,6 +9761,60 @@ var brandTools = [
9701
9761
  return { competitors: out.competitors?.map((x) => x.name) };
9702
9762
  }
9703
9763
  }),
9764
+ tool({
9765
+ name: "competitor_suggestions_list",
9766
+ description: "Competitors Maggie found on the web (each website checked) that the user hasn't added to the profile or dismissed yet: name, website, one line, and how many ideas came from their site. Their sitemaps are already used for blog ideas while they wait.",
9767
+ parameters: none,
9768
+ group: "brand",
9769
+ need: { resource: "overview", level: "read" },
9770
+ risk: "R0",
9771
+ run: async (ctx) => {
9772
+ const out = await ws(ctx).competitorSuggestions();
9773
+ return {
9774
+ searched_at: out.searched_at,
9775
+ suggestions: out.items.map(({ id, name, website, description: description2, ideas_found }) => ({
9776
+ id,
9777
+ name,
9778
+ website,
9779
+ description: description2,
9780
+ ideas_found
9781
+ }))
9782
+ };
9783
+ }
9784
+ }),
9785
+ tool({
9786
+ name: "competitor_suggestion_add",
9787
+ description: "Add one of Maggie's competitor suggestions (id from competitor_suggestions_list) to the business profile.",
9788
+ parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
9789
+ group: "brand",
9790
+ need: write2,
9791
+ risk: "W1",
9792
+ run: async (ctx, { id }) => {
9793
+ const out = await ws(ctx).addCompetitorSuggestion(id);
9794
+ return { competitors: out.competitors.map((c) => c.name) };
9795
+ }
9796
+ }),
9797
+ tool({
9798
+ name: "competitor_suggestion_dismiss",
9799
+ description: "Not a competitor after all: the suggestion is never made again and its site is no longer read for ideas.",
9800
+ parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
9801
+ group: "brand",
9802
+ need: write2,
9803
+ risk: "W1",
9804
+ run: async (ctx, { id }) => ws(ctx).dismissCompetitorSuggestion(id)
9805
+ }),
9806
+ tool({
9807
+ name: "competitor_suggestions_find",
9808
+ description: "Look for new competitors on the web now (once a day per website, subscribed websites only; Maggie also looks on her own once the website and its known competitors have no new pages left). New ones come back as suggestions; nothing is added to the profile.",
9809
+ parameters: none,
9810
+ group: "brand",
9811
+ need: write2,
9812
+ risk: "W1",
9813
+ run: async (ctx) => {
9814
+ const out = await ws(ctx).refreshCompetitorSuggestions();
9815
+ return { found: out.found, suggestions: out.items.map(({ id, name, website }) => ({ id, name, website })) };
9816
+ }
9817
+ }),
9704
9818
  tool({
9705
9819
  name: "brand_research_update",
9706
9820
  description: "Change the profile's market notes: market_research (text), additional_information (anything else Maggie should know) or the SWOT list (each {name: Strengths|Weaknesses|Opportunities|Threats, description}). A list replaces the whole list.",
@@ -22086,12 +22200,14 @@ var OPEN_WORLD = /* @__PURE__ */ new Set([
22086
22200
  "social_video_add",
22087
22201
  "seo_audit_run",
22088
22202
  "ai_visibility_prompt_check",
22089
- "idea_add"
22203
+ "idea_add",
22204
+ "competitor_suggestions_find"
22090
22205
  ]);
22091
22206
  var OVERWRITES = /* @__PURE__ */ new Set([
22092
22207
  "ai_visibility_keywords_set",
22093
22208
  "brand_research_update",
22094
22209
  "brand_update",
22210
+ "competitor_suggestion_dismiss",
22095
22211
  "draft_rewrite",
22096
22212
  "draft_rewrite_save",
22097
22213
  "draft_update",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmo-so/mcp",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
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",