@awesomate/hosting-mcp 0.16.2 → 0.16.4
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
|
@@ -39855,12 +39855,13 @@ var HubApiError = class extends Error {
|
|
|
39855
39855
|
}
|
|
39856
39856
|
};
|
|
39857
39857
|
var REQUEST_TIMEOUT_MS = 15e3;
|
|
39858
|
-
async function hubRequest(config3, method, path, jsonBody) {
|
|
39858
|
+
async function hubRequest(config3, method, path, jsonBody, opts = {}) {
|
|
39859
39859
|
const timeoutMs = method === "GET" ? REQUEST_TIMEOUT_MS : 24e4;
|
|
39860
39860
|
const controller = new AbortController();
|
|
39861
39861
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
39862
39862
|
const headers = { Authorization: `Bearer ${config3.pat}` };
|
|
39863
39863
|
if (jsonBody !== void 0) headers["Content-Type"] = "application/json";
|
|
39864
|
+
if (opts.accept) headers.Accept = opts.accept;
|
|
39864
39865
|
let res;
|
|
39865
39866
|
try {
|
|
39866
39867
|
res = await (0, import_undici.fetch)(`${config3.apiBase}${path}`, {
|
|
@@ -39907,8 +39908,8 @@ async function hubRequest(config3, method, path, jsonBody) {
|
|
|
39907
39908
|
function hubGet(config3, path) {
|
|
39908
39909
|
return hubRequest(config3, "GET", path);
|
|
39909
39910
|
}
|
|
39910
|
-
function hubPost(config3, path, jsonBody = {}) {
|
|
39911
|
-
return hubRequest(config3, "POST", path, jsonBody);
|
|
39911
|
+
function hubPost(config3, path, jsonBody = {}, opts = {}) {
|
|
39912
|
+
return hubRequest(config3, "POST", path, jsonBody, opts);
|
|
39912
39913
|
}
|
|
39913
39914
|
function hubPatch(config3, path, jsonBody = {}) {
|
|
39914
39915
|
return hubRequest(config3, "PATCH", path, jsonBody);
|
|
@@ -40012,6 +40013,13 @@ async function knowledgeStatus(config3) {
|
|
|
40012
40013
|
if (status.upgrade_required) {
|
|
40013
40014
|
return { ...status, upsell: upsellPayload(config3.apiBase, status.plan) };
|
|
40014
40015
|
}
|
|
40016
|
+
const usage = status.usage;
|
|
40017
|
+
if (usage && usage.sources_total_truncated === true) {
|
|
40018
|
+
return {
|
|
40019
|
+
...status,
|
|
40020
|
+
note: `usage.sources_total is a floor: the live count stopped at ${String(usage.sources_total)} sources (paged-count cap). The library holds at least that many \u2014 never quote it as the exact total.`
|
|
40021
|
+
};
|
|
40022
|
+
}
|
|
40015
40023
|
return status;
|
|
40016
40024
|
} catch (err) {
|
|
40017
40025
|
return mapKnowledgeError(err, config3.apiBase);
|
|
@@ -40031,10 +40039,31 @@ async function knowledgeProvision(config3) {
|
|
|
40031
40039
|
return mapKnowledgeError(err, config3.apiBase);
|
|
40032
40040
|
}
|
|
40033
40041
|
}
|
|
40042
|
+
function describeSourcePage(page) {
|
|
40043
|
+
if (!Array.isArray(page.sources)) return page;
|
|
40044
|
+
const kinds = {};
|
|
40045
|
+
for (const s of page.sources) {
|
|
40046
|
+
const k = typeof s.kind === "string" ? s.kind : "unknown";
|
|
40047
|
+
kinds[k] = (kinds[k] ?? 0) + 1;
|
|
40048
|
+
}
|
|
40049
|
+
const hasMore = typeof page.next_cursor === "string" && page.next_cursor.length > 0;
|
|
40050
|
+
return {
|
|
40051
|
+
...page,
|
|
40052
|
+
page: { returned: page.sources.length, kinds_on_this_page: kinds, has_more: hasMore },
|
|
40053
|
+
...hasMore ? {
|
|
40054
|
+
note: 'This is ONE page of the most recently ingested sources, not the whole library \u2014 do not summarise the knowledge base from it. Pass cursor=next_cursor to continue (limit up to 200). For the total, use awesomate_knowledge_status \u2192 usage.sources_total (sources_total_truncated:true means "at least that many").'
|
|
40055
|
+
} : {}
|
|
40056
|
+
};
|
|
40057
|
+
}
|
|
40034
40058
|
async function knowledgeSources(config3, args) {
|
|
40035
40059
|
try {
|
|
40036
40060
|
if (args.action === "list") {
|
|
40037
|
-
|
|
40061
|
+
const q = new URLSearchParams();
|
|
40062
|
+
if (args.cursor) q.set("cursor", args.cursor);
|
|
40063
|
+
if (args.limit !== void 0) q.set("limit", String(args.limit));
|
|
40064
|
+
const qs = q.toString();
|
|
40065
|
+
const page = await hubGet(config3, `/api/knowledge/sources${qs ? `?${qs}` : ""}`);
|
|
40066
|
+
return describeSourcePage(page);
|
|
40038
40067
|
}
|
|
40039
40068
|
if (args.action === "jobs") {
|
|
40040
40069
|
const q = args.status ? `?status=${encodeURIComponent(args.status)}` : "";
|
|
@@ -40072,15 +40101,29 @@ function parseSse(text) {
|
|
|
40072
40101
|
}
|
|
40073
40102
|
return events;
|
|
40074
40103
|
}
|
|
40075
|
-
function renderAnswer(meta, streamedAnswer) {
|
|
40076
|
-
const status = typeof meta.status === "string" ? meta.status : streamedAnswer ? "ok" : "error";
|
|
40104
|
+
function renderAnswer(meta, streamedAnswer, streamError = null) {
|
|
40105
|
+
const status = typeof meta.status === "string" ? meta.status : streamError ? "error" : streamedAnswer ? "ok" : "error";
|
|
40106
|
+
const session = typeof meta.session === "string" && meta.session ? { session: meta.session } : {};
|
|
40107
|
+
const fallback = typeof meta.answer_plain === "string" && meta.answer_plain || typeof meta.no_answer_message === "string" && meta.no_answer_message || null;
|
|
40108
|
+
if (status === "error") {
|
|
40109
|
+
return {
|
|
40110
|
+
status: "error",
|
|
40111
|
+
answer: null,
|
|
40112
|
+
platform_error: true,
|
|
40113
|
+
not_in_verified_content: false,
|
|
40114
|
+
detail: streamError ?? (streamedAnswer || null),
|
|
40115
|
+
configured_fallback: fallback,
|
|
40116
|
+
...session,
|
|
40117
|
+
note: "The knowledge platform failed to answer \u2014 a service problem, NOT a content gap. Do not tell the user their content lacks this. Say the service hit a problem, retry once, and if it persists raise it via awesomate_support. configured_fallback is only what an end customer would have seen meanwhile."
|
|
40118
|
+
};
|
|
40119
|
+
}
|
|
40077
40120
|
if (status !== "ok") {
|
|
40078
|
-
const fallback = typeof meta.answer_plain === "string" && meta.answer_plain || typeof meta.no_answer_message === "string" && meta.no_answer_message || null;
|
|
40079
40121
|
return {
|
|
40080
40122
|
status,
|
|
40081
40123
|
answer: null,
|
|
40082
40124
|
not_in_verified_content: true,
|
|
40083
40125
|
configured_fallback: fallback,
|
|
40126
|
+
...session,
|
|
40084
40127
|
note: "The knowledge base has no verified answer for this \u2014 relay that honestly (use the configured fallback wording if present). Never fill the gap from memory."
|
|
40085
40128
|
};
|
|
40086
40129
|
}
|
|
@@ -40097,20 +40140,25 @@ function renderAnswer(meta, streamedAnswer) {
|
|
|
40097
40140
|
answer: typeof meta.answer_plain === "string" && meta.answer_plain ? meta.answer_plain : streamedAnswer,
|
|
40098
40141
|
sources,
|
|
40099
40142
|
...typeof meta.score === "number" ? { score: meta.score } : {},
|
|
40143
|
+
...session,
|
|
40100
40144
|
note: "Present the answer with its numbered sources \u2014 the citations are the product."
|
|
40101
40145
|
};
|
|
40102
40146
|
}
|
|
40103
40147
|
async function knowledgeAsk(config3, args) {
|
|
40104
40148
|
try {
|
|
40105
|
-
const raw = await hubPost(
|
|
40106
|
-
|
|
40107
|
-
|
|
40108
|
-
|
|
40149
|
+
const raw = await hubPost(
|
|
40150
|
+
config3,
|
|
40151
|
+
"/api/knowledge/chat",
|
|
40152
|
+
{ question: args.question, ...args.session ? { session: args.session } : {} },
|
|
40153
|
+
{ accept: "application/json" }
|
|
40154
|
+
);
|
|
40109
40155
|
if (raw && typeof raw === "object") {
|
|
40110
|
-
|
|
40156
|
+
const envelope = raw;
|
|
40157
|
+
return renderAnswer(envelope, typeof envelope.answer === "string" ? envelope.answer : "");
|
|
40111
40158
|
}
|
|
40112
40159
|
const events = parseSse(String(raw ?? ""));
|
|
40113
40160
|
let streamedAnswer = "";
|
|
40161
|
+
let streamError = null;
|
|
40114
40162
|
let meta = {};
|
|
40115
40163
|
for (const ev of events) {
|
|
40116
40164
|
if (ev.event === "answer") streamedAnswer += ev.data;
|
|
@@ -40119,9 +40167,16 @@ async function knowledgeAsk(config3, args) {
|
|
|
40119
40167
|
meta = { ...meta, ...JSON.parse(ev.data) };
|
|
40120
40168
|
} catch {
|
|
40121
40169
|
}
|
|
40170
|
+
} else if (ev.event === "error" && ev.data) {
|
|
40171
|
+
try {
|
|
40172
|
+
const parsed = JSON.parse(ev.data);
|
|
40173
|
+
streamError = typeof parsed.message === "string" ? parsed.message : ev.data;
|
|
40174
|
+
} catch {
|
|
40175
|
+
streamError = ev.data;
|
|
40176
|
+
}
|
|
40122
40177
|
}
|
|
40123
40178
|
}
|
|
40124
|
-
return renderAnswer(meta, streamedAnswer);
|
|
40179
|
+
return renderAnswer(meta, streamedAnswer, streamError);
|
|
40125
40180
|
} catch (err) {
|
|
40126
40181
|
return mapKnowledgeError(err, config3.apiBase);
|
|
40127
40182
|
}
|
|
@@ -40980,20 +41035,22 @@ server.registerTool(
|
|
|
40980
41035
|
server.registerTool(
|
|
40981
41036
|
"awesomate_knowledge_sources",
|
|
40982
41037
|
{
|
|
40983
|
-
description: "The knowledge base's content sources. action 'list' \u2014
|
|
41038
|
+
description: "The knowledge base's content sources. action 'list' \u2014 ONE page of sources, most recently ingested first (default 50, max 200 via limit): read `page.has_more`/`next_cursor` and pass cursor to continue \u2014 a page is never the whole library, and the total lives in awesomate_knowledge_status \u2192 usage.sources_total. 'jobs' \u2014 ingest job statuses (optional status filter: queued|running|succeeded|failed). 'add' \u2014 ingest a public page {url} or a whole site {sitemap, since?}; ALWAYS get explicit approval first (ingest costs money and counts against quota), and for local FILES send the user to the hub's Knowledge \u2192 Sources upload page \u2014 this tool cannot carry file bytes. A pack_required response means the allowance is exhausted: NOTHING was purchased \u2014 present the pack price (1 credit = $100) and let the user buy from the hub if they want it. 'remove' {sourceId} \u2014 deletes the source AND its indexed content; explicit approval required.",
|
|
40984
41039
|
inputSchema: {
|
|
40985
41040
|
action: external_exports.enum(["list", "add", "remove", "jobs"]),
|
|
40986
41041
|
url: external_exports.string().url().optional().describe("add: one public page / blog post / YouTube link"),
|
|
40987
41042
|
sitemap: external_exports.string().url().optional().describe("add: sitemap.xml URL \u2014 ingests every listed page"),
|
|
40988
41043
|
since: external_exports.string().optional().describe("add+sitemap only: skip entries with lastmod older than this ISO date"),
|
|
40989
41044
|
sourceId: external_exports.string().optional().describe("remove only"),
|
|
40990
|
-
status: external_exports.string().optional().describe("jobs only: queued|running|succeeded|failed")
|
|
41045
|
+
status: external_exports.string().optional().describe("jobs only: queued|running|succeeded|failed"),
|
|
41046
|
+
cursor: external_exports.string().max(512).optional().describe("list only: next_cursor from the previous page"),
|
|
41047
|
+
limit: external_exports.number().int().min(1).max(200).optional().describe("list only: page size (default 50, max 200)")
|
|
40991
41048
|
}
|
|
40992
41049
|
},
|
|
40993
|
-
async ({ action, url, sitemap, since, sourceId, status }) => {
|
|
41050
|
+
async ({ action, url, sitemap, since, sourceId, status, cursor, limit }) => {
|
|
40994
41051
|
try {
|
|
40995
41052
|
return knowledgeResult(
|
|
40996
|
-
await knowledgeSources(requireConfig(), { action, url, sitemap, since, sourceId, status })
|
|
41053
|
+
await knowledgeSources(requireConfig(), { action, url, sitemap, since, sourceId, status, cursor, limit })
|
|
40997
41054
|
);
|
|
40998
41055
|
} catch (err) {
|
|
40999
41056
|
return knowledgeError(err);
|
|
@@ -41003,7 +41060,7 @@ server.registerTool(
|
|
|
41003
41060
|
server.registerTool(
|
|
41004
41061
|
"awesomate_knowledge_ask",
|
|
41005
41062
|
{
|
|
41006
|
-
description: `Ask the account's knowledge base a question and get the VERIFIED answer with numbered sources (title, locator, url) \u2014 the test surface for 'is my content in there and answering well'. status
|
|
41063
|
+
description: `Ask the account's knowledge base a question and get the VERIFIED answer with numbered sources (title, locator, url) \u2014 the test surface for 'is my content in there and answering well'. Read status: ok \u2192 present answer + sources. no_results / failed_validation (not_in_verified_content:true) \u2192 the verified content has no answer: relay that honestly (use configured_fallback), never fill the gap from memory \u2014 an honest "it doesn't know" is the feature working. error (platform_error:true) \u2192 the platform itself failed (model/API/infra): NOT a content gap \u2014 never tell the user their content lacks the answer; retry once, then awesomate_support. Counts against the monthly answers quota.`,
|
|
41007
41064
|
inputSchema: {
|
|
41008
41065
|
question: external_exports.string().min(1).max(2e3),
|
|
41009
41066
|
session: external_exports.string().max(128).optional().describe("Stable id to keep follow-up questions in one conversation thread")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/hosting-mcp",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "Awesomate MCP server \u2014 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",
|
|
@@ -36,9 +36,13 @@ platform's answer beats anything you remember.
|
|
|
36
36
|
content is indexed in Sydney, deletable any time), wait, re-check.
|
|
37
37
|
- `tenant: null` or `status: 'provisioning'` → not enabled yet /
|
|
38
38
|
still building; `usage` → month-to-date vs `usage.included` quota.
|
|
39
|
-
3. Only then design: what content exists, what's already ingested
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
3. Only then design: what content exists, what's already ingested, what the
|
|
40
|
+
user wants the bot to answer. For "what's ingested" use
|
|
41
|
+
`status.usage.sources_total` (with `sources_total_truncated:true` it is a
|
|
42
|
+
floor). `awesomate_knowledge_sources {action:'list'}` returns ONE page —
|
|
43
|
+
the most recently ingested first (default 50, `limit` up to 200) — read
|
|
44
|
+
`page.kinds_on_this_page` / `page.has_more` and follow `next_cursor`;
|
|
45
|
+
never describe the library from a single page.
|
|
42
46
|
|
|
43
47
|
## 1. Tools
|
|
44
48
|
|
|
@@ -17,8 +17,12 @@ and widgets never see a partial or unvalidated answer.
|
|
|
17
17
|
- `status: 'failed_validation'` — the model drafted something that didn't
|
|
18
18
|
survive the citation gate. The user never sees the draft; treat exactly
|
|
19
19
|
like no_results.
|
|
20
|
-
- `status: 'error'`
|
|
21
|
-
`
|
|
20
|
+
- `status: 'error'` (`platform_error: true`, `not_in_verified_content:
|
|
21
|
+
false`) — the platform could not answer at all (model/API/infra outage).
|
|
22
|
+
This says NOTHING about the content: never relay it as "your content
|
|
23
|
+
doesn't cover this". `detail` carries the platform's message when it sent
|
|
24
|
+
one; `configured_fallback` is only what an end customer would have seen
|
|
25
|
+
meanwhile. Retry once; if it persists, `awesomate_support`.
|
|
22
26
|
|
|
23
27
|
## Rendering citations for humans
|
|
24
28
|
|