@awesomate/hosting-mcp 0.24.0 → 0.26.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
@@ -40083,7 +40083,22 @@ var KNOWLEDGE_GATE_COPY = {
40083
40083
  "Hosted in Sydney, isolated to your account, and gone the moment you delete it"
40084
40084
  ]
40085
40085
  };
40086
- function upsellPayload(apiBase, plan) {
40086
+ function upsellPayload(apiBase, plan, body) {
40087
+ const capability = typeof body?.capability === "string" ? body.capability : null;
40088
+ const requiredPlan = typeof body?.requiredPlan === "string" ? body.requiredPlan : KNOWLEDGE_GATE_COPY.requiredPlan;
40089
+ const message = typeof body?.message === "string" ? body.message : null;
40090
+ if (capability && message) {
40091
+ return {
40092
+ upgrade_required: true,
40093
+ capability,
40094
+ requiredPlan,
40095
+ ...typeof plan === "string" ? { plan } : {},
40096
+ ...typeof body?.dimension === "string" ? { dimension: body.dimension } : {},
40097
+ message,
40098
+ billingUrl: `${apiBase}/billing?upgrade=${encodeURIComponent(requiredPlan)}`,
40099
+ note: capability === "knowledge_packs" ? `The included allowance is used up and this plan cannot buy Ingestion Packs (they start at ${requiredPlan}). NOTHING was added or purchased. Say so plainly, share the billing link, and let the user decide; never retry.` : `This kind of content needs ${requiredPlan} or above. NOTHING was added. Relay the message honestly, share the billing link, and let the user decide; never retry.`
40100
+ };
40101
+ }
40087
40102
  return {
40088
40103
  upgrade_required: true,
40089
40104
  ...typeof plan === "string" ? { plan } : {},
@@ -40124,7 +40139,7 @@ function mapKnowledgeError(err, apiBase) {
40124
40139
  if (!(err instanceof HubApiError)) throw err;
40125
40140
  const body = bodyOf(err);
40126
40141
  if (err.status === 404) return notAvailablePayload(apiBase);
40127
- if (err.status === 403 && body?.upgrade_required) return upsellPayload(apiBase, body.plan);
40142
+ if ((err.status === 403 || err.status === 402) && body?.upgrade_required) return upsellPayload(apiBase, body.plan, body);
40128
40143
  if (err.status === 403 && body?.consent_required) {
40129
40144
  return consentPayload(typeof body.error === "string" ? body.error : "Knowledge Platform consent is off");
40130
40145
  }
@@ -40633,6 +40648,40 @@ async function knowledgeSearch(config3, args) {
40633
40648
  return mapKnowledgeError(err, config3.apiBase);
40634
40649
  }
40635
40650
  }
40651
+ function touchesScope(args) {
40652
+ return Boolean(args.collectionIds || args.kinds || args.sourceIds);
40653
+ }
40654
+ var SCOPE_KEYS = ["source_ids", "tags", "datasets", "kinds", "data_sets", "allow_media", "allow_data"];
40655
+ function agentPatchBody(args, currentScope = {}) {
40656
+ let scope;
40657
+ if (touchesScope(args)) {
40658
+ const kept = {};
40659
+ for (const k of SCOPE_KEYS) if (currentScope[k] !== void 0) kept[k] = currentScope[k];
40660
+ const currentTags = Array.isArray(kept.tags) ? kept.tags.filter((t) => typeof t === "string") : [];
40661
+ scope = {
40662
+ ...kept,
40663
+ ...args.collectionIds ? { tags: [...currentTags.filter((t) => !t.startsWith("collection:")), ...args.collectionIds.map((id) => `collection:${id}`)] } : {},
40664
+ ...args.kinds ? { kinds: args.kinds } : {},
40665
+ ...args.sourceIds ? { source_ids: args.sourceIds } : {}
40666
+ };
40667
+ }
40668
+ return {
40669
+ ...args.name ? { name: args.name } : {},
40670
+ ...args.description !== void 0 ? { description: args.description } : {},
40671
+ ...args.systemMessage !== void 0 ? { system_message: args.systemMessage } : {},
40672
+ ...args.noAnswerMessage !== void 0 ? { no_answer_message: args.noAnswerMessage } : {},
40673
+ ...args.grounding ? { grounding: args.grounding } : {},
40674
+ ...args.audience ? { audience: args.audience } : {},
40675
+ ...args.maxSources !== void 0 ? { max_sources: args.maxSources } : {},
40676
+ ...args.temperature !== void 0 ? { temperature: args.temperature } : {},
40677
+ ...scope ? { scope } : {}
40678
+ };
40679
+ }
40680
+ async function currentAgentScope(config3, agentId) {
40681
+ const got = await hubGet(config3, `/api/knowledge/agents/${encodeURIComponent(agentId)}`);
40682
+ const scope = got.agent?.scope ?? got.scope;
40683
+ return scope && typeof scope === "object" && !Array.isArray(scope) ? scope : {};
40684
+ }
40636
40685
  function mapAgentsError(err, apiBase) {
40637
40686
  if (err instanceof HubApiError && err.status === 404) {
40638
40687
  const body = bodyOf(err);
@@ -40662,6 +40711,23 @@ async function knowledgeAgents(config3, args) {
40662
40711
  if (!args.name) return { error: "name (or goal) is required for create" };
40663
40712
  return await hubPost(config3, "/api/knowledge/agents", { name: args.name, ...args.audience ? { audience: args.audience } : {} });
40664
40713
  }
40714
+ if (args.action === "update") {
40715
+ if (!args.agentId) return { error: "agentId is required for update" };
40716
+ const currentScope = touchesScope(args) ? await currentAgentScope(config3, args.agentId) : {};
40717
+ const body = agentPatchBody(args, currentScope);
40718
+ if (!Object.keys(body).length) {
40719
+ return {
40720
+ error: "invalid_request",
40721
+ note: "update needs at least one of name, description, systemMessage, noAnswerMessage, grounding, audience, collectionIds, kinds, sourceIds, maxSources, temperature"
40722
+ };
40723
+ }
40724
+ const out = await hubPatch(config3, `/api/knowledge/agents/${encodeURIComponent(args.agentId)}`, body);
40725
+ return {
40726
+ ...out,
40727
+ requested: body,
40728
+ status_note: "Draft updated. A published agent keeps serving its last published version until you publish again: test the draft, then publish when the user approves."
40729
+ };
40730
+ }
40665
40731
  if (args.action === "publish") {
40666
40732
  if (!args.agentId) return { error: "agentId is required for publish" };
40667
40733
  const out = await hubPost(config3, `/api/knowledge/agents/${encodeURIComponent(args.agentId)}/publish`, {});
@@ -40885,6 +40951,7 @@ var TITLES = {
40885
40951
  awesomate_skill_update: "Update Awesomate skills",
40886
40952
  awesomate_site_create: "Create WordPress site",
40887
40953
  awesomate_site_audit: "Audit site for SEO and AEO",
40954
+ awesomate_php_extensions: "Check or fix PHP extensions",
40888
40955
  awesomate_uninstall_site: "Delete WordPress site",
40889
40956
  awesomate_snapshot_site: "Snapshot site",
40890
40957
  awesomate_list_snapshots: "List site snapshots",
@@ -41416,6 +41483,26 @@ readTool(
41416
41483
  "cPanel account details: package, server, provisioned-at, masked username.",
41417
41484
  "/api/client-hosting/account"
41418
41485
  );
41486
+ server.registerTool(
41487
+ "awesomate_php_extensions",
41488
+ {
41489
+ description: "Check (and optionally fix) the PHP extensions enabled for the hosting account's PHP runtime. Use this when WordPress fails on a SPECIFIC operation while the rest of the site works: `wp media import` or image uploads dying with \"critical error\" (missing dom), sudden white screens on text handling (missing mbstring), importers or sitemap generation failing (missing xmlreader/xmlwriter), or a plugin that installs fine but cannot connect (missing soap). The CloudLinux alt-php82 default set is much leaner than 7.4's, so accounts on PHP 8.2 often come up without these even though the modules are installed on the server. The account holder CANNOT fix this from a shell \u2014 CageFS blocks selectorctl for jailed accounts \u2014 so do it here rather than talking them through cPanel. Pass fix:true to enable the missing ones. Enabling is additive (nothing already on is removed), needs no PHP restart and causes no downtime.",
41490
+ inputSchema: {
41491
+ fix: external_exports.boolean().optional().describe("Enable the missing extensions. Omit or false to only report what is missing.")
41492
+ },
41493
+ annotations: annotate("awesomate_php_extensions", MUTATING)
41494
+ },
41495
+ async ({ fix }) => {
41496
+ try {
41497
+ const config3 = requireConfig();
41498
+ return textResult(
41499
+ fix ? await hubPost(config3, "/api/client-hosting/php-extensions", {}) : await hubGet(config3, "/api/client-hosting/php-extensions")
41500
+ );
41501
+ } catch (err) {
41502
+ return errorResult(err);
41503
+ }
41504
+ }
41505
+ );
41419
41506
  readTool(
41420
41507
  "awesomate_list_sites",
41421
41508
  "All WordPress sites on the hosting account: canonical domain, URL, title, WP version, SSL state, install date.",
@@ -41906,13 +41993,22 @@ server.registerTool(
41906
41993
  "awesomate_knowledge_agents",
41907
41994
  {
41908
41995
  annotations: annotate("awesomate_knowledge_agents", MUTATING),
41909
- description: "The agent builder (multi-agent; the older awesomate_knowledge_agent tool is the single workspace default). action 'list' \u2014 every agent with status (draft/published vN/suspended). 'get' {agentId} \u2014 full config incl. system message and scope. 'create' {goal} \u2014 AI drafts the whole setup (instructions, scope, tone, test questions) from the account's own content and saves it as a PRIVATE DRAFT (never live, nothing lost); or {name} for a blank draft. 'test' {agentId, message, sessionId?} \u2014 chat with the DRAFT config: free, unmetered, the right way to check behaviour before going live. 'publish' {agentId} \u2014 makes the draft LIVE immediately for every key bound to the agent: get the user's explicit approval first, and read the version back. Editing fields, policies, API keys and the request log live in the hub UI (Knowledge \u2192 Agents); keys are shown once there and never pass through this tool.",
41996
+ description: "The agent builder (multi-agent; the older awesomate_knowledge_agent tool is the single workspace default). action 'list': every agent with status (draft/published vN/suspended). 'get' {agentId}: full config incl. system message and scope. 'create' {goal}: AI drafts the whole setup (instructions, scope, tone, test questions) from the account's own content and saves it as a PRIVATE DRAFT (never live, nothing lost); or {name} for a blank draft. 'update' {agentId, ...fields}: edit the DRAFT config: name, description, systemMessage, noAnswerMessage, grounding, audience, collectionIds (scope to collections from awesomate_knowledge_collections), kinds, sourceIds, maxSources, temperature. Nothing changes for callers until 'publish'. 'test' {agentId, message, sessionId?}: chat with the DRAFT config: free, unmetered, the right way to check behaviour before going live. 'publish' {agentId}: makes the draft LIVE immediately for every key bound to the agent: get the user's explicit approval first, and read the version back. Policies, API keys and the request log live in the hub UI (Knowledge \u2192 Agents); keys are shown once there and never pass through this tool.",
41910
41997
  inputSchema: {
41911
- action: external_exports.enum(["list", "get", "create", "publish", "test"]),
41912
- agentId: external_exports.string().max(64).optional().describe("get/publish/test: agent_id from list"),
41913
- name: external_exports.string().max(80).optional().describe("create: blank draft with this name"),
41998
+ action: external_exports.enum(["list", "get", "create", "update", "publish", "test"]),
41999
+ agentId: external_exports.string().max(64).optional().describe("get/update/publish/test: agent_id from list"),
42000
+ name: external_exports.string().max(80).optional().describe("create: blank draft with this name; update: rename"),
41914
42001
  goal: external_exports.string().max(2e3).optional().describe("create: describe the agent and AI drafts it from the account content"),
41915
- audience: external_exports.enum(["private", "internal", "public"]).optional().describe("create: who the agent serves \u2014 'public' for anything customers or a website will talk to (it then answers from sources marked public ONLY), 'internal' for the team, 'private' (default) for the owner's own tools. Widening later is a publish, so choose now."),
42002
+ audience: external_exports.enum(["private", "internal", "public"]).optional().describe("create/update: who the agent serves: 'public' for anything customers or a website will talk to (it then answers from sources marked public ONLY), 'internal' for the team, 'private' (default) for the owner's own tools. Widening later is a publish, so choose now."),
42003
+ description: external_exports.string().max(300).optional().describe("update: one-line description shown in the hub"),
42004
+ systemMessage: external_exports.string().max(8e3).optional().describe("update: the agent instructions (system message)"),
42005
+ noAnswerMessage: external_exports.string().max(500).optional().describe("update: what the agent says when the grounding gate declines to answer"),
42006
+ grounding: external_exports.enum(["strict", "grounded_chat"]).optional().describe("update: 'strict' refuses anything not in the retrieved content (use it for anything customer-facing); 'grounded_chat' may add general knowledge around the cited content"),
42007
+ collectionIds: external_exports.array(external_exports.string().max(64)).max(16).optional().describe("update: scope the agent to these collections (collection_id from awesomate_knowledge_collections list); replaces the collection scope only, other scope fields and free-form tags are kept"),
42008
+ kinds: external_exports.array(external_exports.string().max(40)).max(16).optional().describe("update: restrict retrieval to source kinds (web, document, video, audio, image, book, dataset); omit for all kinds"),
42009
+ sourceIds: external_exports.array(external_exports.string().max(200)).max(500).optional().describe("update: pin the scope to specific sources"),
42010
+ maxSources: external_exports.number().int().min(1).max(10).optional().describe("update: how many sources one answer may cite (1-10)"),
42011
+ temperature: external_exports.number().min(0).max(1).optional().describe("update: 0 is the most literal"),
41916
42012
  message: external_exports.string().max(4e3).optional().describe("test: the question to ask the draft"),
41917
42013
  sessionId: external_exports.string().max(128).optional().describe("test: keep follow-ups in one thread")
41918
42014
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/hosting-mcp",
3
- "version": "0.24.0",
3
+ "version": "0.26.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",
@@ -64,7 +64,7 @@ platform's answer beats anything you remember.
64
64
  | Instant search with facet counts (find WHAT is in there: moments, pages, datasets; free) | `awesomate_knowledge_search` |
65
65
  | Ask a question → verified answer + numbered sources (accepts the same facet `filters` to ask within a slice) | `awesomate_knowledge_ask` |
66
66
  | Agent persona / fallback message / model tier — get & set (the single workspace default) | `awesomate_knowledge_agent` |
67
- | Agent BUILDER: list / get / create (AI-drafted from their content, saved as a private draft; pass `audience:'public'` for anything customers will talk to it then answers from sources marked public ONLY) / test the draft / publish (explicit approval first) | `awesomate_knowledge_agents` |
67
+ | Agent BUILDER: list / get / create (AI-drafted from their content, saved as a private draft; pass `audience:'public'` for anything customers will talk to; it then answers from sources marked public ONLY) / update (edit the draft's instructions, grounding, no-answer message, audience and collection scope; nothing changes for callers until publish) / test the draft / publish (explicit approval first) | `awesomate_knowledge_agents` |
68
68
  | People, places, topics: list / name / hide / merge / alias suggestions / re-run resolution | `awesomate_knowledge_people` |
69
69
  | Business-data warehouse: `metrics` / `datasets` / `query` / `imports` — answer quantitative questions from their own imported business data (query is free-form but read-only) | `awesomate_knowledge_data` |
70
70
  | Refresh these skills from the latest package | `awesomate_skill_update` |