@cmo-so/mcp 0.12.0 → 0.12.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/dist/cmo-mcp.mjs +135 -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.12.
|
|
7202
|
+
version: "0.12.2",
|
|
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",
|
|
@@ -7722,6 +7722,8 @@ function domainApi(api2, domain) {
|
|
|
7722
7722
|
wpBuilder: () => api2.request(`${base}/wp/builder`),
|
|
7723
7723
|
connectWpBuilder: (input) => post(`${base}/wp/builder`, input),
|
|
7724
7724
|
disconnectWpBuilder: () => api2.request(`${base}/wp/builder`, { method: "DELETE" }),
|
|
7725
|
+
/** Put one picture in the site's media library: a public https link, or a local file as base64 (≤ 10 MB). */
|
|
7726
|
+
wpMedia: (input) => post(`${base}/wp/media`, input),
|
|
7725
7727
|
/** One WordPress REST request, signed by TOPY with the saved login (allowlisted routes only). */
|
|
7726
7728
|
wpRequest: (input) => post(`${base}/wp/request`, input),
|
|
7727
7729
|
/** A new website API key (aicmo_…) for the user's own code, shown once; for the CLI, which writes it to .env. */
|
|
@@ -14806,6 +14808,23 @@ function apiSite(api2, domain) {
|
|
|
14806
14808
|
return {
|
|
14807
14809
|
url: `https://${domain}`,
|
|
14808
14810
|
fetchPage: publicFetch,
|
|
14811
|
+
async uploadMedia(input) {
|
|
14812
|
+
let data_base64;
|
|
14813
|
+
if (input.data) {
|
|
14814
|
+
let bin = "";
|
|
14815
|
+
for (let i = 0; i < input.data.length; i += 32768)
|
|
14816
|
+
bin += String.fromCharCode(...input.data.subarray(i, i + 32768));
|
|
14817
|
+
data_base64 = btoa(bin);
|
|
14818
|
+
}
|
|
14819
|
+
return d.wpMedia({
|
|
14820
|
+
url: input.url,
|
|
14821
|
+
data_base64,
|
|
14822
|
+
filename: input.filename,
|
|
14823
|
+
alt: input.alt,
|
|
14824
|
+
title: input.title,
|
|
14825
|
+
caption: input.caption
|
|
14826
|
+
});
|
|
14827
|
+
},
|
|
14809
14828
|
async request(req) {
|
|
14810
14829
|
let r;
|
|
14811
14830
|
try {
|
|
@@ -14838,6 +14857,12 @@ async function call(site, req) {
|
|
|
14838
14857
|
const r = await site.request(req);
|
|
14839
14858
|
if (r.status >= 200 && r.status < 300) return r.data;
|
|
14840
14859
|
const body = r.data;
|
|
14860
|
+
if (r.status >= 300 && r.status < 400)
|
|
14861
|
+
throw new WpError(
|
|
14862
|
+
`WordPress redirected the request (HTTP ${r.status}): use the site's final address (https, with or without www).`,
|
|
14863
|
+
r.status,
|
|
14864
|
+
"redirect"
|
|
14865
|
+
);
|
|
14841
14866
|
const msg = typeof body === "object" && body?.message ? body.message.replace(/<[^>]+>/g, "") : `HTTP ${r.status}`;
|
|
14842
14867
|
const code = typeof body === "object" ? body?.code : void 0;
|
|
14843
14868
|
if (r.status === 409 && code === "wp_not_connected")
|
|
@@ -16326,6 +16351,8 @@ var pageTools = [
|
|
|
16326
16351
|
meta: meta4
|
|
16327
16352
|
}
|
|
16328
16353
|
});
|
|
16354
|
+
if (!created || typeof created.id !== "number")
|
|
16355
|
+
throw new Error("WordPress didn't create the page (no id came back); nothing was saved.");
|
|
16329
16356
|
let menu = null;
|
|
16330
16357
|
if (typeof a.menu_parent === "string") {
|
|
16331
16358
|
menu = await menuSet(site, {
|
|
@@ -16496,6 +16523,8 @@ var pageTools = [
|
|
|
16496
16523
|
}
|
|
16497
16524
|
}
|
|
16498
16525
|
});
|
|
16526
|
+
if (!created || typeof created.id !== "number")
|
|
16527
|
+
throw new Error("WordPress didn't create the page (no id came back); nothing was saved.");
|
|
16499
16528
|
return {
|
|
16500
16529
|
created: true,
|
|
16501
16530
|
id: created.id,
|
|
@@ -16740,6 +16769,103 @@ var sectionTools = [
|
|
|
16740
16769
|
}
|
|
16741
16770
|
})
|
|
16742
16771
|
];
|
|
16772
|
+
var CHAT_FILE = {
|
|
16773
|
+
type: "object",
|
|
16774
|
+
description: "The picture from this chat (ChatGPT passes it here).",
|
|
16775
|
+
properties: {
|
|
16776
|
+
download_url: { type: "string" },
|
|
16777
|
+
file_id: { type: "string" },
|
|
16778
|
+
mime_type: { type: "string" },
|
|
16779
|
+
file_name: { type: "string" }
|
|
16780
|
+
},
|
|
16781
|
+
required: ["download_url", "file_id"]
|
|
16782
|
+
};
|
|
16783
|
+
var mediaTools = [
|
|
16784
|
+
tool({
|
|
16785
|
+
name: "wp_media_upload",
|
|
16786
|
+
description: "Put a picture in the WordPress site's media library: a picture from this chat (file) or a public https link to an image (url). JPEG, PNG, WebP, GIF or AVIF, up to 15 MB; checked as a real image. Give alt text that says what the picture shows. Returns its id and source_url; then use the url in a section (wp_section_update edits.images, or slots image) or as a page's featured_media. Doesn't change any page by itself.",
|
|
16787
|
+
parameters: {
|
|
16788
|
+
type: "object",
|
|
16789
|
+
properties: {
|
|
16790
|
+
file: CHAT_FILE,
|
|
16791
|
+
url: str2("Public https link to the image file."),
|
|
16792
|
+
filename: str2("File name to save it as (default from the link), e.g. maggie-hero.webp."),
|
|
16793
|
+
alt: str2("Alt text: what the picture shows, in one short sentence."),
|
|
16794
|
+
title: str2("Media title (optional)."),
|
|
16795
|
+
caption: str2("Caption (optional).")
|
|
16796
|
+
}
|
|
16797
|
+
},
|
|
16798
|
+
group: "site",
|
|
16799
|
+
need: WRITE,
|
|
16800
|
+
risk: "W2",
|
|
16801
|
+
gates: [...GATES],
|
|
16802
|
+
fileParams: ["file"],
|
|
16803
|
+
confirm: (a, lang) => {
|
|
16804
|
+
const name = a.file?.file_name ?? (typeof a.url === "string" ? a.url.split("/").pop() : "");
|
|
16805
|
+
return say(
|
|
16806
|
+
lang,
|
|
16807
|
+
`Upload the picture ${q2(name, "")} to your website's media library.`,
|
|
16808
|
+
`\u628A\u5716\u7247 ${q2(name, "")} \u4E0A\u50B3\u5230\u7DB2\u7AD9\u7684\u5A92\u9AD4\u5EAB\u3002`
|
|
16809
|
+
);
|
|
16810
|
+
},
|
|
16811
|
+
run: async (ctx, a) => {
|
|
16812
|
+
const site = siteOf(ctx);
|
|
16813
|
+
if (!site.uploadMedia) throw new Error("This connection can't upload pictures.");
|
|
16814
|
+
const chat = a.file;
|
|
16815
|
+
const url = String(chat?.download_url ?? a.url ?? "").trim();
|
|
16816
|
+
if (!url) throw new Error("Give the picture: a file from this chat, or a public https link (url).");
|
|
16817
|
+
const out = await site.uploadMedia({
|
|
16818
|
+
url,
|
|
16819
|
+
filename: a.filename || chat?.file_name || void 0,
|
|
16820
|
+
alt: a.alt || void 0,
|
|
16821
|
+
title: a.title || void 0,
|
|
16822
|
+
caption: a.caption || void 0
|
|
16823
|
+
});
|
|
16824
|
+
return {
|
|
16825
|
+
uploaded: true,
|
|
16826
|
+
...out,
|
|
16827
|
+
next: "Use source_url in wp_section_update (edits.images from \u2192 to, or slots image), or set it as the page's featured_media with wp_page_update."
|
|
16828
|
+
};
|
|
16829
|
+
}
|
|
16830
|
+
}),
|
|
16831
|
+
tool({
|
|
16832
|
+
name: "wp_media_list",
|
|
16833
|
+
description: "Pictures already in the WordPress media library (newest first), with id, link, alt text and size; search by words in the title or file name.",
|
|
16834
|
+
parameters: {
|
|
16835
|
+
type: "object",
|
|
16836
|
+
properties: {
|
|
16837
|
+
search: str2("Words in the title or file name."),
|
|
16838
|
+
limit: int2("How many (default 30, at most 100).")
|
|
16839
|
+
}
|
|
16840
|
+
},
|
|
16841
|
+
group: "site",
|
|
16842
|
+
need: READ,
|
|
16843
|
+
risk: "R0",
|
|
16844
|
+
gates: ["WP"],
|
|
16845
|
+
run: async (ctx, a) => {
|
|
16846
|
+
const rows = await call(siteOf(ctx), {
|
|
16847
|
+
path: "/wp/v2/media",
|
|
16848
|
+
query: {
|
|
16849
|
+
search: a.search || void 0,
|
|
16850
|
+
per_page: Math.min(100, Math.max(1, Number(a.limit) || 30)),
|
|
16851
|
+
media_type: "image",
|
|
16852
|
+
_fields: "id,source_url,alt_text,mime_type,date,title,media_details"
|
|
16853
|
+
}
|
|
16854
|
+
});
|
|
16855
|
+
return {
|
|
16856
|
+
count: rows.length,
|
|
16857
|
+
items: rows.map((m) => ({
|
|
16858
|
+
id: m.id,
|
|
16859
|
+
url: m.source_url,
|
|
16860
|
+
alt: m.alt_text,
|
|
16861
|
+
type: m.mime_type,
|
|
16862
|
+
size: m.media_details?.width ? `${m.media_details.width}\xD7${m.media_details.height}` : null,
|
|
16863
|
+
date: m.date
|
|
16864
|
+
}))
|
|
16865
|
+
};
|
|
16866
|
+
}
|
|
16867
|
+
})
|
|
16868
|
+
];
|
|
16743
16869
|
var seoFields = {
|
|
16744
16870
|
title: str2("SEO title (\u224860 characters; the site name is added by the theme)."),
|
|
16745
16871
|
description: str2("Meta description (\u2248150-160 characters)."),
|
|
@@ -16995,7 +17121,14 @@ var elementTools = [
|
|
|
16995
17121
|
}
|
|
16996
17122
|
})
|
|
16997
17123
|
];
|
|
16998
|
-
var wordpressTools = [
|
|
17124
|
+
var wordpressTools = [
|
|
17125
|
+
...siteTools,
|
|
17126
|
+
...pageTools,
|
|
17127
|
+
...sectionTools,
|
|
17128
|
+
...mediaTools,
|
|
17129
|
+
...seoTools,
|
|
17130
|
+
...elementTools
|
|
17131
|
+
];
|
|
16999
17132
|
|
|
17000
17133
|
// ../../packages/tools/src/index.ts
|
|
17001
17134
|
var tools = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/mcp",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
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",
|