@awesomate/hosting-mcp 0.34.0 → 0.35.0
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/index.js
CHANGED
|
@@ -40790,6 +40790,107 @@ async function knowledgeCollections(config3, args) {
|
|
|
40790
40790
|
return mapKnowledgeError(err, config3.apiBase);
|
|
40791
40791
|
}
|
|
40792
40792
|
}
|
|
40793
|
+
var faqEntryBody = (e) => ({
|
|
40794
|
+
question: e.question,
|
|
40795
|
+
answer: e.answer,
|
|
40796
|
+
...e.altQuestions?.length ? { alt_questions: e.altQuestions } : {},
|
|
40797
|
+
...e.category ? { category: e.category } : {},
|
|
40798
|
+
...e.sourceUrl ? { source_url: e.sourceUrl } : {},
|
|
40799
|
+
...e.externalKey ? { external_key: e.externalKey } : {}
|
|
40800
|
+
});
|
|
40801
|
+
async function knowledgeFaq(config3, args) {
|
|
40802
|
+
try {
|
|
40803
|
+
if (args.action === "sets") return await hubGet(config3, "/api/knowledge/faq/sets");
|
|
40804
|
+
if (args.action === "create_set") {
|
|
40805
|
+
if (!args.setTitle) return { error: "invalid_request", note: 'create_set needs setTitle, e.g. "Bayside Garden FAQ"' };
|
|
40806
|
+
return await hubPost(config3, "/api/knowledge/faq/sets", {
|
|
40807
|
+
title: args.setTitle,
|
|
40808
|
+
...args.visibility ? { visibility: args.visibility } : {},
|
|
40809
|
+
...args.collectionIds?.length ? { collection_ids: args.collectionIds } : {}
|
|
40810
|
+
});
|
|
40811
|
+
}
|
|
40812
|
+
if (args.action === "import") {
|
|
40813
|
+
if (!args.entries?.length) return { error: "invalid_request", note: "import needs entries [{question, answer}], at most 200 per call" };
|
|
40814
|
+
let setId = args.setId;
|
|
40815
|
+
if (!setId) {
|
|
40816
|
+
if (!args.setTitle) return { error: "invalid_request", note: "import needs setId, or setTitle to create or reuse the set by name" };
|
|
40817
|
+
const created = await hubPost(config3, "/api/knowledge/faq/sets", {
|
|
40818
|
+
title: args.setTitle,
|
|
40819
|
+
...args.visibility ? { visibility: args.visibility } : {},
|
|
40820
|
+
...args.collectionIds?.length ? { collection_ids: args.collectionIds } : {}
|
|
40821
|
+
});
|
|
40822
|
+
setId = created.set?.set_id;
|
|
40823
|
+
if (!setId) return { error: "unavailable", note: "The FAQ set could not be created; nothing was imported." };
|
|
40824
|
+
}
|
|
40825
|
+
const status = args.status === "published" ? "published" : "draft";
|
|
40826
|
+
const r = await hubPost(config3, `/api/knowledge/faq/sets/${encodeURIComponent(setId)}/entries`, {
|
|
40827
|
+
entries: args.entries.map(faqEntryBody),
|
|
40828
|
+
status,
|
|
40829
|
+
origin: "import",
|
|
40830
|
+
...args.confirm ? { confirm: args.confirm } : {}
|
|
40831
|
+
});
|
|
40832
|
+
return {
|
|
40833
|
+
...r,
|
|
40834
|
+
set_id: setId,
|
|
40835
|
+
note: status === "draft" ? "Imported as DRAFTS: nothing is live yet. Show the owner the count and a few samples, then ask ONE question: publish these to their assistant? On yes, call action publish {setId} (a public set also needs confirm: the account slug)." : "Published. The index job makes them searchable within a minute or two; then prove it with awesomate_knowledge_ask using a reworded question."
|
|
40836
|
+
};
|
|
40837
|
+
}
|
|
40838
|
+
if (args.action === "publish") {
|
|
40839
|
+
if (!args.setId) return { error: "invalid_request", note: "publish needs setId (from sets or the import result)" };
|
|
40840
|
+
return await hubPost(config3, `/api/knowledge/faq/sets/${encodeURIComponent(args.setId)}/publish`, {
|
|
40841
|
+
...args.entryIds?.length ? { entry_ids: args.entryIds } : {},
|
|
40842
|
+
...args.confirm ? { confirm: args.confirm } : {}
|
|
40843
|
+
});
|
|
40844
|
+
}
|
|
40845
|
+
if (args.action === "list") {
|
|
40846
|
+
if (!args.setId) return { error: "invalid_request", note: "list needs setId (from sets)" };
|
|
40847
|
+
const params = new URLSearchParams();
|
|
40848
|
+
if (args.status) params.set("status", args.status);
|
|
40849
|
+
if (args.q) params.set("q", args.q);
|
|
40850
|
+
if (args.cursor) params.set("cursor", args.cursor);
|
|
40851
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
40852
|
+
const qs = params.toString();
|
|
40853
|
+
return await hubGet(config3, `/api/knowledge/faq/sets/${encodeURIComponent(args.setId)}/entries${qs ? `?${qs}` : ""}`);
|
|
40854
|
+
}
|
|
40855
|
+
if (!args.entryId) return { error: "invalid_request", note: `${args.action} needs entryId (from list)` };
|
|
40856
|
+
const entryPath = `/api/knowledge/faq/entries/${encodeURIComponent(args.entryId)}`;
|
|
40857
|
+
if (args.action === "delete") {
|
|
40858
|
+
await hubDelete(config3, entryPath);
|
|
40859
|
+
return { deleted: true, entry_id: args.entryId };
|
|
40860
|
+
}
|
|
40861
|
+
const patch = args.action === "archive" ? { status: "archived" } : {
|
|
40862
|
+
...args.question !== void 0 ? { question: args.question } : {},
|
|
40863
|
+
...args.answer !== void 0 ? { answer: args.answer } : {},
|
|
40864
|
+
...args.altQuestions !== void 0 ? { alt_questions: args.altQuestions } : {},
|
|
40865
|
+
...args.category !== void 0 ? { category: args.category } : {},
|
|
40866
|
+
...args.sourceUrl !== void 0 ? { source_url: args.sourceUrl } : {},
|
|
40867
|
+
...args.reviewBy !== void 0 ? { review_by: args.reviewBy } : {},
|
|
40868
|
+
...args.status !== void 0 ? { status: args.status } : {}
|
|
40869
|
+
};
|
|
40870
|
+
if (!Object.keys(patch).length) return { error: "invalid_request", note: "update needs at least one of question, answer, altQuestions, category, sourceUrl, reviewBy, status" };
|
|
40871
|
+
return await hubPatch(config3, entryPath, { ...patch, ...args.confirm ? { confirm: args.confirm } : {} });
|
|
40872
|
+
} catch (err) {
|
|
40873
|
+
if (err instanceof HubApiError) {
|
|
40874
|
+
const body = bodyOf(err);
|
|
40875
|
+
const code = typeof body?.error === "string" ? body.error : "";
|
|
40876
|
+
const message = typeof body?.message === "string" ? body.message : void 0;
|
|
40877
|
+
if (err.status === 409 && code === "confirm_required") {
|
|
40878
|
+
return {
|
|
40879
|
+
confirm_required: true,
|
|
40880
|
+
confirm_with: body?.confirm_with,
|
|
40881
|
+
note: `${message ?? "This set is public."} Nothing was written. Ask the owner, in plain words, whether to make these answers live on their website assistant; only on a clear yes, repeat the call with confirm set to the account slug.`
|
|
40882
|
+
};
|
|
40883
|
+
}
|
|
40884
|
+
if (err.status === 409 && code === "quota_exceeded") return { error: "quota_exceeded", note: message ?? "This workspace is at its FAQ entry limit." };
|
|
40885
|
+
if (err.status === 503 && code === "faq_unavailable") {
|
|
40886
|
+
return { error: "faq_unavailable", note: "FAQ sets are not live on this account yet. Use the Markdown file method in the awesomate-knowledge skill (references/faqs.md) instead." };
|
|
40887
|
+
}
|
|
40888
|
+
if (err.status === 404 && code === "not_found") return { error: "not_found", note: message ?? "No such FAQ set or entry in this workspace." };
|
|
40889
|
+
if (err.status === 400) return { error: "invalid_request", note: message ?? "The hub refused the request as malformed." };
|
|
40890
|
+
}
|
|
40891
|
+
return mapKnowledgeError(err, config3.apiBase);
|
|
40892
|
+
}
|
|
40893
|
+
}
|
|
40793
40894
|
|
|
40794
40895
|
// src/index.ts
|
|
40795
40896
|
var config2 = null;
|
|
@@ -41008,6 +41109,7 @@ var TITLES = {
|
|
|
41008
41109
|
awesomate_knowledge_agent: "Configure knowledge agent",
|
|
41009
41110
|
awesomate_knowledge_agents: "Manage knowledge agents",
|
|
41010
41111
|
awesomate_knowledge_collections: "Manage knowledge collections",
|
|
41112
|
+
awesomate_knowledge_faq: "Manage FAQs",
|
|
41011
41113
|
awesomate_knowledge_people: "Manage knowledge entities",
|
|
41012
41114
|
awesomate_knowledge_data: "Query knowledge data warehouse"
|
|
41013
41115
|
};
|
|
@@ -42284,6 +42386,50 @@ server.registerTool(
|
|
|
42284
42386
|
}
|
|
42285
42387
|
}
|
|
42286
42388
|
);
|
|
42389
|
+
server.registerTool(
|
|
42390
|
+
"awesomate_knowledge_faq",
|
|
42391
|
+
{
|
|
42392
|
+
annotations: annotate("awesomate_knowledge_faq", MUTATING),
|
|
42393
|
+
description: "The business's FAQs as a first-class part of its Knowledge Base: every entry is one question and its answer, edited one at a time, cited as 'FAQ: <question>'. Use for 'import the FAQs from my website', 'add this to our FAQ', 'fix that answer'. The owner makes ONE decision per import: whether to publish. action 'sets': every FAQ set with draft/published/archived counts. 'create_set' {setTitle, visibility?, collectionIds?}: idempotent by title; creating a public set asks nothing, since a new set holds nothing live. 'import' {setId | setTitle, entries[{question, answer, altQuestions?, category?, sourceUrl?, externalKey?}] (max 200 per call; call again for more), status?}: upserts on the question itself, so re-running an import UPDATES in place and never duplicates. Default status draft: nothing goes live. Copy answers WORD FOR WORD from the source; never rewrite, shorten or merge them. 'publish' {setId, entryIds?}: every draft (or the listed ones) goes live. 'list' {setId, status?, q?, cursor?, limit?}. 'update' {entryId, question?|answer?|altQuestions?|category?|sourceUrl?|reviewBy?|status?}. 'archive' {entryId}: takes it out of every answer. 'delete' {entryId}. PUBLIC sets: anything that would make an answer live to customers (publish, import as published, editing a published answer) answers confirm_required until you pass confirm: the account slug. Ask the owner in plain words first; never pass the slug on your own initiative. After publishing, answers are searchable within a minute or two; prove it with awesomate_knowledge_ask using a reworded question. faq_unavailable means this account does not have FAQ sets yet: fall back to the Markdown method in the awesomate-knowledge skill.",
|
|
42394
|
+
inputSchema: {
|
|
42395
|
+
action: external_exports.enum(["sets", "create_set", "list", "import", "publish", "update", "archive", "delete"]),
|
|
42396
|
+
setId: external_exports.string().max(200).optional().describe("the set_id from sets or an import result"),
|
|
42397
|
+
setTitle: external_exports.string().min(1).max(200).optional().describe("create_set, or import without a setId: the set is created or reused by this name"),
|
|
42398
|
+
visibility: external_exports.enum(["private", "internal", "public"]).optional().describe("create_set / import-with-setTitle, NEW sets only: 'public' for a website assistant"),
|
|
42399
|
+
collectionIds: external_exports.array(external_exports.string().max(64)).max(16).optional().describe("create_set: put the set in these collections"),
|
|
42400
|
+
entries: external_exports.array(
|
|
42401
|
+
external_exports.object({
|
|
42402
|
+
question: external_exports.string().min(1).max(500),
|
|
42403
|
+
answer: external_exports.string().min(1).max(4e3),
|
|
42404
|
+
altQuestions: external_exports.array(external_exports.string().max(500)).max(20).optional().describe("other ways customers ask it"),
|
|
42405
|
+
category: external_exports.string().max(80).optional(),
|
|
42406
|
+
sourceUrl: external_exports.string().max(2048).optional().describe("the page the pair was copied from"),
|
|
42407
|
+
externalKey: external_exports.string().max(128).optional().describe("only when the source has its own stable id; the question is the default key")
|
|
42408
|
+
})
|
|
42409
|
+
).max(200).optional().describe("import: the pairs, word for word"),
|
|
42410
|
+
status: external_exports.enum(["draft", "published", "archived"]).optional().describe("import: draft (default) or published; list: filter; update: set it"),
|
|
42411
|
+
q: external_exports.string().max(200).optional().describe("list: substring over question, answer and alternates"),
|
|
42412
|
+
cursor: external_exports.string().max(20).optional().describe("list: next_cursor from the previous page"),
|
|
42413
|
+
limit: external_exports.number().int().min(1).max(500).optional().describe("list: page size (default 100)"),
|
|
42414
|
+
entryId: external_exports.string().max(64).optional().describe("update/archive/delete: entry_id from list"),
|
|
42415
|
+
entryIds: external_exports.array(external_exports.string().max(64)).max(1e4).optional().describe("publish: only these drafts"),
|
|
42416
|
+
question: external_exports.string().min(1).max(500).optional().describe("update"),
|
|
42417
|
+
answer: external_exports.string().min(1).max(4e3).optional().describe("update"),
|
|
42418
|
+
altQuestions: external_exports.array(external_exports.string().max(500)).max(20).optional().describe("update: REPLACES the list"),
|
|
42419
|
+
category: external_exports.string().max(80).optional().describe("update"),
|
|
42420
|
+
sourceUrl: external_exports.string().max(2048).optional().describe("update"),
|
|
42421
|
+
reviewBy: external_exports.string().max(10).optional().describe("update: YYYY-MM-DD, a date to check this answer is still right"),
|
|
42422
|
+
confirm: external_exports.string().max(64).optional().describe("the account slug, ONLY after the owner said yes to making answers live on a public set")
|
|
42423
|
+
}
|
|
42424
|
+
},
|
|
42425
|
+
async (args) => {
|
|
42426
|
+
try {
|
|
42427
|
+
return knowledgeResult(await knowledgeFaq(requireConfig(), args));
|
|
42428
|
+
} catch (err) {
|
|
42429
|
+
return knowledgeError(err);
|
|
42430
|
+
}
|
|
42431
|
+
}
|
|
42432
|
+
);
|
|
42287
42433
|
server.registerTool(
|
|
42288
42434
|
"awesomate_knowledge_people",
|
|
42289
42435
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/hosting-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
package/skill/CHANGELOG.json
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"versions": [
|
|
3
|
+
{
|
|
4
|
+
"version": "0.35.0",
|
|
5
|
+
"highlights": [
|
|
6
|
+
"Your FAQs now live as real FAQ entries: Claude imports them as drafts, asks you one question (publish?), and later fixes a single answer without re-uploading anything (awesomate_knowledge_faq)",
|
|
7
|
+
"Every answer your website assistant gives from an FAQ cites the exact question it came from",
|
|
8
|
+
"Nothing goes live on a public assistant without your yes: publishing or editing a live public answer always asks first"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
3
11
|
{
|
|
4
12
|
"version": "0.34.0",
|
|
5
13
|
"highlights": [
|
|
@@ -60,6 +60,7 @@ platform's answer beats anything you remember.
|
|
|
60
60
|
| Enable the knowledge base (idempotent; 202 = keep polling status) | `awesomate_knowledge_provision` |
|
|
61
61
|
| The LIBRARY: search by title/tag/collection/visibility, list, add url·sitemap (with visibility, tags, collections), tag, set visibility (public needs the slug typed), move between collections, remove, ingest jobs | `awesomate_knowledge_sources` |
|
|
62
62
|
| Collections — named sets of sources a chatbot is scoped to: list / create / update / delete / add / remove members | `awesomate_knowledge_collections` |
|
|
63
|
+
| FAQs: sets of question-and-answer entries, imported as drafts, published with ONE owner yes, edited one answer at a time ([faqs.md](references/faqs.md)) | `awesomate_knowledge_faq` |
|
|
63
64
|
| Keep a File Manager folder (their n8n file system) synced into the knowledge base: `sync_rules` / `sync_rule_create` / `sync_rule_delete` / `sync_run` / `sync_state` on the sources tool; one file at a time via `awesomate_knowledge_upload {fromFilesPath}` | `awesomate_knowledge_sources`, `awesomate_knowledge_upload` |
|
|
64
65
|
| Instant search with facet counts (find WHAT is in there: moments, pages, datasets; free) | `awesomate_knowledge_search` |
|
|
65
66
|
| Ask a question → verified answer + numbered sources (accepts the same facet `filters` to ask within a slice) | `awesomate_knowledge_ask` |
|
|
@@ -97,9 +97,29 @@ one citable section per question, and needs nobody to pick the right option.
|
|
|
97
97
|
Add the new `##` entries to the same file and upload it with the same title. If the owner
|
|
98
98
|
has no file yet, start one.
|
|
99
99
|
|
|
100
|
-
##
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
## With the FAQ tool (use this first)
|
|
101
|
+
|
|
102
|
+
`awesomate_knowledge_faq` stores every question and answer as its own entry, so an owner can
|
|
103
|
+
fix one answer without re-uploading a file, and every citation names the exact entry. Use it
|
|
104
|
+
whenever it is in your tools. The Markdown method above is the fallback, for when the tool
|
|
105
|
+
answers `faq_unavailable`.
|
|
106
|
+
|
|
107
|
+
1. Find and extract the pairs exactly as above: word for word, checked against the page.
|
|
108
|
+
2. `import {setTitle: "<Business> FAQ", visibility: "public", entries: [...]}` in batches of
|
|
109
|
+
200. Entries land as **drafts**, so nothing is live yet. Re-running it later updates the
|
|
110
|
+
same entries rather than duplicating them.
|
|
111
|
+
3. Show the count, a few samples and anything you dropped, then ask the one question:
|
|
112
|
+
*"Publish these 42 answers to your website assistant?"*
|
|
113
|
+
4. On yes, `publish {setId}`. A public set answers `confirm_required` the first time; repeat
|
|
114
|
+
it with `confirm` set to the account slug, which is only allowed because the owner just
|
|
115
|
+
said yes. Never pass the slug on your own initiative.
|
|
116
|
+
On no, first `awesomate_knowledge_sources {action:'set_visibility', sourceId: setId,
|
|
117
|
+
visibility:'internal'}` (lowering visibility needs no confirm), then `publish {setId}`:
|
|
118
|
+
the team's assistants and the owner's own use the answers, the website assistant does
|
|
119
|
+
not. Leaving them as drafts would hide them from everyone.
|
|
120
|
+
5. Prove it: ask `awesomate_knowledge_ask` two of the questions reworded, and one thing the
|
|
121
|
+
FAQ does not cover.
|
|
122
|
+
|
|
123
|
+
Fixing one answer later is `list {setId, q: "<words from the question>"}` to find it, then
|
|
124
|
+
`update {entryId, answer}` (a live public answer needs the owner's yes again). `archive` takes
|
|
125
|
+
an entry out of every answer without deleting it.
|