@awesomate/hosting-mcp 0.23.0 → 0.24.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
@@ -41251,17 +41251,32 @@ server.registerTool(
41251
41251
  "awesomate_support",
41252
41252
  {
41253
41253
  annotations: annotate("awesomate_support", MUTATING),
41254
- description: "Help the user with the service itself \u2014 questions, being stuck, or reaching a human. action 'faq' {q} searches the published help library (answer FROM the results; never invent policy or pricing). action 'help_docs' {q} searches the full Help Centre articles live \u2014 use when the FAQ has no good answer, and cite the returned article URLs. action 'create_ticket' {subject, message} opens a support ticket \u2014 draft it in the user's words, SHOW it, and get an explicit yes before sending; it emails the Awesomate team and returns a portal URL. action 'list_tickets' shows their tickets and status. Use the awesomate-support skill for the full flow. Not for building \u2014 route n8n work to awesomate-n8n and hosting to awesomate-hosting.",
41254
+ description: "Help the user with the service itself \u2014 questions, being stuck, or reaching a human. **action 'ask' {q} is the FIRST thing to try for any question about Awesomate** \u2014 it answers from Awesomate's own Knowledge Base with numbered citations, works on every plan, and composes across articles rather than matching titles; relay its answer and cite the source URLs. If it returns no_answer:true the grounding gate declined, so offer a ticket instead of guessing; if degraded:true the Knowledge Base was unavailable and you are looking at keyword matches, so do not present them as a verified answer. action 'faq' {q} searches the published help library (answer FROM the results; never invent policy or pricing). action 'help_docs' {q} searches the full Help Centre articles live \u2014 use when the FAQ has no good answer, and cite the returned article URLs. action 'create_ticket' {subject, message, category} opens a support ticket \u2014 draft it in the user's words, SHOW it, and get an explicit yes before sending; it emails the Awesomate team and returns a portal URL. **`category` is REQUIRED and must name what the ticket is actually about \u2014 'Other' is refused.** Ticket access splits by SUBJECT, not by plan: reporting a problem with AWESOMATE ITSELF ('Infrastructure fault' \u2014 site down, instance unreachable, provisioning or SSL failure; 'Claude/MCP connectivity' \u2014 pairing fails, token rejected, tools erroring) and 'Account/billing' work on EVERY plan. Asking for help USING the products ('Workflow not running', 'Workflow error', 'New automation request', 'How-to question') needs Support Plus or above and returns 403 upgrade_required below it \u2014 when that happens, answer from 'faq'/'help_docs' instead and relay the upgrade honestly; do NOT relabel the ticket as a fault to get through. action 'list_tickets' shows their tickets and status. Use the awesomate-support skill for the full flow. Not for building \u2014 route n8n work to awesomate-n8n and hosting to awesomate-hosting.",
41255
41255
  inputSchema: {
41256
- action: external_exports.enum(["faq", "help_docs", "create_ticket", "list_tickets"]),
41257
- q: external_exports.string().optional().describe("faq and help_docs: the question or topic"),
41256
+ action: external_exports.enum(["ask", "faq", "help_docs", "create_ticket", "list_tickets"]),
41257
+ q: external_exports.string().optional().describe("ask, faq and help_docs: the question or topic"),
41258
41258
  subject: external_exports.string().optional().describe("create_ticket only"),
41259
- message: external_exports.string().optional().describe("create_ticket only: the body, in the user's words")
41259
+ message: external_exports.string().optional().describe("create_ticket only: the body, in the user's words"),
41260
+ category: external_exports.enum([
41261
+ "Infrastructure fault",
41262
+ "Claude/MCP connectivity",
41263
+ "Workflow not running",
41264
+ "Workflow error",
41265
+ "New automation request",
41266
+ "Account/billing",
41267
+ "How-to question"
41268
+ ]).optional().describe(
41269
+ "create_ticket: REQUIRED. What the ticket is about. The first two and Account/billing work on every plan; the rest need Support Plus or above."
41270
+ )
41260
41271
  }
41261
41272
  },
41262
- async ({ action, q, subject, message }) => {
41273
+ async ({ action, q, subject, message, category }) => {
41263
41274
  try {
41264
41275
  const cfg = requireConfig();
41276
+ if (action === "ask") {
41277
+ if (!q) return errorResult(new Error("ask needs q"));
41278
+ return textResult(await hubGet(cfg, `/api/help/ask?q=${encodeURIComponent(q)}`));
41279
+ }
41265
41280
  if (action === "faq") {
41266
41281
  return textResult(await hubGet(cfg, `/api/help/faq${q ? `?q=${encodeURIComponent(q)}` : ""}`));
41267
41282
  }
@@ -41273,7 +41288,14 @@ server.registerTool(
41273
41288
  return textResult(await hubGet(cfg, "/api/support/tickets"));
41274
41289
  }
41275
41290
  if (!subject || !message) return errorResult(new Error("create_ticket needs subject and message"));
41276
- return textResult(await hubPost(cfg, "/api/support/tickets", { subject, body_text: message }));
41291
+ if (!category) {
41292
+ return errorResult(
41293
+ new Error(
41294
+ 'create_ticket needs a category naming what the ticket is about. Use "Infrastructure fault" or "Claude/MCP connectivity" when the problem is with Awesomate itself, "Account/billing" for money, and the workflow/how-to categories (Support Plus and above) for help using the products.'
41295
+ )
41296
+ );
41297
+ }
41298
+ return textResult(await hubPost(cfg, "/api/support/tickets", { subject, body_text: message, category }));
41277
41299
  } catch (err) {
41278
41300
  return errorResult(err);
41279
41301
  }
@@ -41303,7 +41325,7 @@ server.registerTool(
41303
41325
  "awesomate_site_create",
41304
41326
  {
41305
41327
  annotations: annotate("awesomate_site_create", MUTATING),
41306
- description: "Create a WordPress site on the user's hosting. Plan limits are enforced server-side (429/403 with an upgrade hint if they're at their cap \u2014 relay it; 409 means WordPress already exists at that domain). Ask 'live or dev?' first per the awesomate-hosting skill. Omit `domain` and the next free siteN.{primary} subdomain is chosen for you. ASYNC and returns only {success:true} \u2014 no domain, no admin details: poll awesomate_list_sites to learn the name, and expect HTTPS to refuse connections for a minute or two while AutoSSL issues even though the site is already serving over http. See 'After creating a site' in the skill.",
41328
+ description: "Create a WordPress site on the user's hosting. **Needs Support Plus or above from Claude** \u2014 on Essentials this returns 403 `upgrade_required` ALWAYS, not only at a cap, because building hosting from a machine token is a Support Plus capability; the Essentials site itself is real and is created by the user in the hub at hub.awesomate.ai/sites, so offer that path first rather than leading with the upgrade. Plan COUNT limits are enforced separately (403 with an upgrade hint at the cap; 409 means WordPress already exists at that domain). Ask 'live or dev?' first per the awesomate-hosting skill. Omit `domain` and the next free siteN.{primary} subdomain is chosen for you. ASYNC and returns only {success:true} \u2014 no domain, no admin details: poll awesomate_list_sites to learn the name, and expect HTTPS to refuse connections for a minute or two while AutoSSL issues even though the site is already serving over http. See 'After creating a site' in the skill.",
41307
41329
  inputSchema: {
41308
41330
  domain: external_exports.string().optional().describe("Custom domain if they have one; omit for a default *.awesomate.site subdomain"),
41309
41331
  siteTitle: external_exports.string().optional(),
@@ -41322,7 +41344,7 @@ server.registerTool(
41322
41344
  "awesomate_domain_add",
41323
41345
  {
41324
41346
  annotations: annotate("awesomate_domain_add", MUTATING),
41325
- description: "Add a custom domain to the user's hosting account. Returns the DNS steps they need to complete at their registrar. Plan-gated (some plans allow zero custom domains \u2014 relay the upgrade hint on 403).",
41347
+ description: "Add a custom domain to the user's hosting account. Returns the DNS steps they need to complete at their registrar. **Needs Support Plus or above from Claude** \u2014 Essentials gets 403 `upgrade_required` even though its plan DOES include one custom domain, because adding it from a machine token is Support Plus; tell them it takes two clicks at hub.awesomate.ai/sites/domains instead. Plan COUNT limits are enforced separately on top.",
41326
41348
  inputSchema: { domain: external_exports.string().describe("The domain to add, e.g. example.com") }
41327
41349
  },
41328
41350
  async ({ domain }) => {
@@ -41337,7 +41359,7 @@ server.registerTool(
41337
41359
  "awesomate_run_wp_cli",
41338
41360
  {
41339
41361
  annotations: annotate("awesomate_run_wp_cli", DESTRUCTIVE),
41340
- description: "Run an allowlisted WP-CLI command on one of the user's WordPress sites (plugin/theme list+activate+update, cache flush, option get/update, post/media/menu/comment/user list). ARGUMENTS CANNOT CONTAIN SPACES (letters, digits and -_./=:@+, only) \u2014 so a site title, tagline or any multi-word value is impossible here: use awesomate_wp_settings for those, and awesomate_wp_post for post/page content. Installs accept wp.org SLUGS only \u2014 never URLs. args is the command as an array, e.g. ['plugin','list'] or ['plugin','install','wordpress-seo','--activate']. A 400 wp_cli_not_allowed means that command isn't permitted; a 502 wp_cli_unavailable is a temporary server-side issue, not your command.",
41362
+ description: "Run an allowlisted WP-CLI command on one of the user's WordPress sites (plugin/theme list+activate+update, cache flush, option get/update, post/media/menu/comment/user list). **Needs Support Plus or above** \u2014 the whole route is behind the write gate, so even the READS (option get, plugin list) return 403 `upgrade_required` on Essentials. ARGUMENTS CANNOT CONTAIN SPACES (letters, digits and -_./=:@+, only) \u2014 so a site title, tagline or any multi-word value is impossible here: use awesomate_wp_settings for those, and awesomate_wp_post for post/page content. Installs accept wp.org SLUGS only \u2014 never URLs. args is the command as an array, e.g. ['plugin','list'] or ['plugin','install','wordpress-seo','--activate']. A 400 wp_cli_not_allowed means that command isn't permitted; a 502 wp_cli_unavailable is a temporary server-side issue, not your command.",
41341
41363
  inputSchema: {
41342
41364
  domain: external_exports.string().describe("The site domain"),
41343
41365
  args: external_exports.array(external_exports.string()).describe("WP-CLI args, e.g. ['plugin','list']")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/hosting-mcp",
3
- "version": "0.23.0",
3
+ "version": "0.24.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",
@@ -28,36 +28,61 @@ what's actually spendable once credits promised to builds in flight are
28
28
  set aside — rather than the raw balance.) Never quote a plan, price, or
29
29
  balance from memory.
30
30
 
31
- ## 1. FAQ first, then help docs
31
+ ## 1. Ask the Knowledge Base first
32
32
 
33
33
  For any "how do I", "why does", "what is" question about the service:
34
34
 
35
- 1. Call `awesomate_support {action:'faq', q:'<their question>'}`.
36
- 2. Answer FROM the returned entries, in your own plain words. Cite nothing
37
- the FAQ and tools didn't say no invented policy, no guessed pricing.
38
- 3. If the FAQ misses or only partially answers, call
39
- `awesomate_support {action:'help_docs', q:'<topic>'}` a live search of
40
- the full Help Centre articles. Answer from the excerpts and give the
41
- article's URL so the user can read the full steps.
42
- 4. If neither answers it: "I don't have a confirmed answer for that. Want
43
- me to ask the Awesomate team? I'll draft a support ticket for you to
44
- approve first." Then go to §2 if they say yes. (An empty help_docs
45
- result can also mean the search is temporarily down — the response's
46
- help_centre_url is always safe to offer for browsing.)
35
+ 1. Call `awesomate_support {action:'ask', q:'<their question>'}`. This is
36
+ Awesomate's own Knowledge Base answering from Awesomate's own content,
37
+ with numbered citations. It works on every plan.
38
+ 2. Read the response's `source` and `degraded` fields before you answer —
39
+ they are the difference between three very different situations:
40
+
41
+ - `source:'knowledge_base'`, `no_answer:false` a grounded answer.
42
+ Relay it in your own plain words and give the citation URLs.
43
+ - `source:'knowledge_base'`, `no_answer:true` the grounding gate
44
+ declined, because the answer is not in our content. **Do not fill the
45
+ gap yourself.** Offer a ticket (§2).
46
+ - `degraded:true` the Knowledge Base was unavailable or is not
47
+ switched on, and you are looking at keyword matches from `faq` and
48
+ `docs` instead. Useful, but **never present them as a verified
49
+ answer**, and say the search was limited if it matters.
50
+
51
+ 3. Only if `ask` came back thin do you need `faq` or `help_docs` directly.
52
+ Both remain available and behave as before, and `help_centre_url` in
53
+ any response is always safe to offer for browsing.
54
+ 4. Cite nothing the tools didn't say. No invented policy, no guessed
55
+ pricing, no remembered plan limits.
47
56
 
48
57
  ## 2. Ticket flow — talking to a human
49
58
 
50
59
  When the user wants a human, or §1 came up empty:
51
60
 
61
+ **First, what is this ticket about?** Access splits by SUBJECT, not by
62
+ plan, and you must pass a `category` naming it. `Other` is refused.
63
+
64
+ | The problem is | category | Who can raise it |
65
+ |---|---|---|
66
+ | Our platform is broken: site down, n8n unreachable, provisioning or SSL failed, the hub is erroring | `Infrastructure fault` | **every plan** |
67
+ | They cannot connect or use Claude: pairing fails, the token is rejected, tools error | `Claude/MCP connectivity` | **every plan** |
68
+ | Money: invoices, plans, credits, refunds | `Account/billing` | **every plan** |
69
+ | Help USING n8n, their website, or the Knowledge Base | `Workflow not running`, `Workflow error`, `New automation request`, `How-to question` | **Support Plus and above** |
70
+
71
+ Choose the category that is actually true. If a product-help ticket comes
72
+ back `403 upgrade_required`, answer from §1 instead and relay the upgrade
73
+ honestly — **never relabel a workflow question as an outage to get it
74
+ through.** That is lying to your own support team about the state of the
75
+ platform, and it puts a false fault report in front of an engineer.
76
+
52
77
  1. Draft the ticket in the USER'S words — their description of the problem,
53
78
  what they were trying to do, what happened. Add context you observed
54
79
  (which site/app, what you already tried) in one short paragraph. No
55
80
  stack traces, no jargon dumps.
56
81
  2. Show the full draft (subject + message) and ask plainly: "Send this to
57
82
  the Awesomate team?" NEVER call `create_ticket` without an explicit yes.
58
- 3. On yes: `awesomate_support {action:'create_ticket', subject, message}`.
59
- Confirm: "Sent. The team replies by email, usually within a business
60
- day."
83
+ 3. On yes: `awesomate_support {action:'create_ticket', subject, message,
84
+ category}`. Confirm: "Sent. The team replies by email, usually within a
85
+ business day."
61
86
  4. Later, "any update on my ticket?" →
62
87
  `awesomate_support {action:'list_tickets'}` and report each ticket's
63
88
  status in one line.