@awesomate/hosting-mcp 0.88.2 → 0.88.6
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 +45 -5
- package/package.json +1 -1
- package/skill/CHANGELOG.json +25 -0
- package/skill/awesomate-app-builder/SKILL.md +9 -5
- package/skill/awesomate-hosting/SKILL.md +1 -1
- package/skill/awesomate-seo/SKILL.md +15 -8
- package/skill/awesomate-seo/references/ai-discoverability.md +40 -26
package/dist/index.js
CHANGED
|
@@ -41747,6 +41747,7 @@ var TITLES = {
|
|
|
41747
41747
|
awesomate_elementor_mcp_connect: "Connect Elementor MCP",
|
|
41748
41748
|
awesomate_app_create: "Create app",
|
|
41749
41749
|
awesomate_app_get: "Get app details",
|
|
41750
|
+
awesomate_app_remove_failed: "Remove an app whose setup failed",
|
|
41750
41751
|
awesomate_app_scaffold: "Get app scaffold guide",
|
|
41751
41752
|
awesomate_app_deploy_info: "Get app deploy briefing",
|
|
41752
41753
|
awesomate_app_update: "Link repo to app",
|
|
@@ -42048,11 +42049,31 @@ server.registerTool(
|
|
|
42048
42049
|
}
|
|
42049
42050
|
}
|
|
42050
42051
|
);
|
|
42052
|
+
function withCredentialStaleWarning(data) {
|
|
42053
|
+
if (!data || typeof data !== "object") return data;
|
|
42054
|
+
const d = data;
|
|
42055
|
+
if (d.stale !== true) return data;
|
|
42056
|
+
const asOf = d.asOf ? new Date(d.asOf) : null;
|
|
42057
|
+
const when = asOf && !Number.isNaN(asOf.getTime()) ? `as of ${asOf.toLocaleDateString("en-AU", { timeZone: "Australia/Sydney" })} ${asOf.toLocaleTimeString("en-AU", { timeZone: "Australia/Sydney", hour: "2-digit", minute: "2-digit" })} Sydney time (${d.asOf})` : "with no known refresh time";
|
|
42058
|
+
const why = {
|
|
42059
|
+
consent: `the refresh needs the "How your automations are running" privacy setting${d.settingsUrl ? ` (${d.settingsUrl})` : ""}`,
|
|
42060
|
+
refresh_failed: "the hub could not refresh it from the n8n instance just now",
|
|
42061
|
+
n8n_unreachable: "the hub could not reach the n8n instance's database to check it"
|
|
42062
|
+
}[d.staleReason ?? "refresh_failed"];
|
|
42063
|
+
const parts = [`This credential list may be out of date: it is ${when}, because ${why}.`];
|
|
42064
|
+
const added = d.drift?.added ?? [];
|
|
42065
|
+
const removed = d.drift?.removed ?? [];
|
|
42066
|
+
if (added.length) parts.push(`n8n also has: ${added.map((c) => `${c.name} (${c.type}, ${c.credential_id})`).join(", ")}.`);
|
|
42067
|
+
if (removed.length) parts.push(`No longer in n8n: ${removed.join(", ")}.`);
|
|
42068
|
+
parts.push("Tell the user the list may be out of date before relying on it, and check the credential in n8n itself when it matters.");
|
|
42069
|
+
const { stale: _s, ...rest } = d;
|
|
42070
|
+
return { warning: parts.join(" "), stale: true, ...rest };
|
|
42071
|
+
}
|
|
42051
42072
|
server.registerTool(
|
|
42052
42073
|
"awesomate_n8n_inspect",
|
|
42053
42074
|
{
|
|
42054
42075
|
annotations: annotate("awesomate_n8n_inspect", READ_ONLY),
|
|
42055
|
-
description: `Instance inventory reads, one tool: 'nodes' (distinct node types in use, counts, versions, community/AI flags), 'datatables' (tables + columns + row counts), 'datatable_rows' (pass datatableId; limit \u2264 100), 'possibilities' (facts for "what could I automate": connected services with live-usage cross-check, unused connections, top nodes, AI tools [null = unknown, not none], community packages, counts \u2014 YOU turn these into suggestions, grounded only in what's actually there), 'credentials' (names/types/inferred service \u2014 never secrets), 'variables' ($vars keys). All consent-gated server-side; 403 consent_required \u2192 settingsUrl.`,
|
|
42076
|
+
description: `Instance inventory reads, one tool: 'nodes' (distinct node types in use, counts, versions, community/AI flags), 'datatables' (tables + columns + row counts), 'datatable_rows' (pass datatableId; limit \u2264 100), 'possibilities' (facts for "what could I automate": connected services with live-usage cross-check, unused connections, top nodes, AI tools [null = unknown, not none], community packages, counts \u2014 YOU turn these into suggestions, grounded only in what's actually there), 'credentials' (names/types/inferred service \u2014 never secrets; a leading 'warning' means the list may be out of date: say so to the user), 'variables' ($vars keys). All consent-gated server-side; 403 consent_required \u2192 settingsUrl.`,
|
|
42056
42077
|
inputSchema: {
|
|
42057
42078
|
what: external_exports.enum(["nodes", "datatables", "datatable_rows", "possibilities", "credentials", "variables"]),
|
|
42058
42079
|
datatableId: external_exports.string().optional().describe("datatable_rows only"),
|
|
@@ -42074,7 +42095,8 @@ server.registerTool(
|
|
|
42074
42095
|
credentials: "/api/my-n8n/machine/credentials",
|
|
42075
42096
|
variables: "/api/my-n8n/machine/variables"
|
|
42076
42097
|
}[what];
|
|
42077
|
-
|
|
42098
|
+
const data = await hubGet(cfg, path);
|
|
42099
|
+
return textResult(what === "credentials" ? withCredentialStaleWarning(data) : data);
|
|
42078
42100
|
} catch (err) {
|
|
42079
42101
|
return errorResult(err);
|
|
42080
42102
|
}
|
|
@@ -42265,7 +42287,7 @@ server.registerTool(
|
|
|
42265
42287
|
"awesomate_domain_add",
|
|
42266
42288
|
{
|
|
42267
42289
|
annotations: annotate("awesomate_domain_add", MUTATING),
|
|
42268
|
-
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.",
|
|
42290
|
+
description: "Add a custom domain to the user's hosting account. Returns the DNS steps they need to complete at their registrar: `dnsInstructions` (A rows only when there is a public address; CNAME rows always) and `dnsNote`. When `dnsNote` is set, relay it word for word: on that server the records must be Proxied (orange cloud) in Cloudflare and SSL/TLS set to Full, not Flexible (Full (strict) only once HTTPS is on); a DNS-only record will not load. **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.",
|
|
42269
42291
|
inputSchema: { domain: external_exports.string().describe("The domain to add, e.g. example.com") }
|
|
42270
42292
|
},
|
|
42271
42293
|
async ({ domain }) => {
|
|
@@ -42547,7 +42569,7 @@ server.registerTool(
|
|
|
42547
42569
|
"awesomate_app_get",
|
|
42548
42570
|
{
|
|
42549
42571
|
annotations: annotate("awesomate_app_get", READ_ONLY),
|
|
42550
|
-
description: "Get one app plus its environments (subdomains, ports, db engine/name, deploy + health state) and any hostnames of the user's own attached to them. Poll this after awesomate_app_create \u2014 status goes provisioning \u2192 active | failed (read provision_error on failure).",
|
|
42572
|
+
description: "Get one app plus its environments (subdomains, ports, db engine/name, deploy + health state) and any hostnames of the user's own attached to them. Poll this after awesomate_app_create \u2014 status goes provisioning \u2192 active | failed (read provision_error on failure; to retry, call awesomate_app_create again with the same appSlug, or remove it with awesomate_app_remove_failed).",
|
|
42551
42573
|
inputSchema: { appId: external_exports.number().int().positive().describe("The app id from awesomate_app_list / _create") }
|
|
42552
42574
|
},
|
|
42553
42575
|
async ({ appId }) => {
|
|
@@ -42558,6 +42580,24 @@ server.registerTool(
|
|
|
42558
42580
|
}
|
|
42559
42581
|
}
|
|
42560
42582
|
);
|
|
42583
|
+
server.registerTool(
|
|
42584
|
+
"awesomate_app_remove_failed",
|
|
42585
|
+
{
|
|
42586
|
+
annotations: annotate("awesomate_app_remove_failed", DESTRUCTIVE),
|
|
42587
|
+
description: "Remove an app whose setup FAILED (awesomate_app_get shows status 'failed'), clearing whatever the attempt left on the user's hosting (subdomains, databases, folders). Only failed apps: an active, provisioning or suspended app is refused with 409 not_failed, and removing a working app stays a support request. A failed app already holds no plan slot and does not reserve its name, so to RETRY just call awesomate_app_create again with the same appSlug: the hub clears the failed attempt first. Use this when the user wants the failed app gone, not to retry. Tell the user what will be removed and get a yes first; confirm must equal the app's slug.",
|
|
42588
|
+
inputSchema: {
|
|
42589
|
+
appId: external_exports.number().int().positive().describe("The failed app id from awesomate_app_list / _get"),
|
|
42590
|
+
confirm: external_exports.string().describe("Must equal the app's slug exactly, as proof of intent")
|
|
42591
|
+
}
|
|
42592
|
+
},
|
|
42593
|
+
async ({ appId, confirm }) => {
|
|
42594
|
+
try {
|
|
42595
|
+
return textResult(await hubDelete(requireConfig(), `/api/my-apps/apps/${appId}`, { confirm }));
|
|
42596
|
+
} catch (err) {
|
|
42597
|
+
return errorResult(err);
|
|
42598
|
+
}
|
|
42599
|
+
}
|
|
42600
|
+
);
|
|
42561
42601
|
server.registerTool(
|
|
42562
42602
|
"awesomate_app_create",
|
|
42563
42603
|
{
|
|
@@ -44302,7 +44342,7 @@ server.registerTool(
|
|
|
44302
44342
|
server.registerTool(
|
|
44303
44343
|
"awesomate_site_audit",
|
|
44304
44344
|
{
|
|
44305
|
-
description: "Run the SEO + AEO build gates against ONE live page the user owns, fetched AS GPTBot. Returns pass/fail per gate with specific fixes: is the content in the raw HTML at all (a React/Vue site is invisible to ChatGPT, Claude and Perplexity \u2014 only Gemini and Applebot run JavaScript), can the four retrieval bots reach it, is there an accidental noindex/nosnippet, does the canonical point at THIS domain (a leftover pointing at a Replit/Vercel/staging host silently de-indexes the real site), is the structured data valid AND mirrored in visible text, is the content structured so a single section survives being quoted, robots.txt + sitemap, and time-to-first-byte. Run it after building or changing any public page, and before telling the user their site is discoverable \u2014 reads on every plan. Two gates are reported as `skipped` because they need a headless browser or a full crawl; treat skipped as unknown, never as passing.",
|
|
44345
|
+
description: "Run the SEO + AEO build gates against ONE live page the user owns, fetched AS OAI-SearchBot (a retrieval bot, so it sees what ChatGPT search sees; training crawlers like GPTBot are blocked by design on Awesomate-managed domains). Returns pass/fail per gate with specific fixes: is the content in the raw HTML at all (a React/Vue site is invisible to ChatGPT, Claude and Perplexity \u2014 only Gemini and Applebot run JavaScript), can the four retrieval bots reach it, is there an accidental noindex/nosnippet, does the canonical point at THIS domain (a leftover pointing at a Replit/Vercel/staging host silently de-indexes the real site), is the structured data valid AND mirrored in visible text, is the content structured so a single section survives being quoted, robots.txt + sitemap, and time-to-first-byte. Run it after building or changing any public page, and before telling the user their site is discoverable \u2014 reads on every plan. Two gates are reported as `skipped` because they need a headless browser or a full crawl; treat skipped as unknown, never as passing.",
|
|
44306
44346
|
inputSchema: {
|
|
44307
44347
|
domain: external_exports.string().min(3).max(253).describe("a domain on the user's own hosting account"),
|
|
44308
44348
|
path: external_exports.string().max(400).optional().describe("page path to audit, default /")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/hosting-mcp",
|
|
3
|
-
"version": "0.88.
|
|
3
|
+
"version": "0.88.6",
|
|
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,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"versions": [
|
|
3
|
+
{
|
|
4
|
+
"version": "0.88.6",
|
|
5
|
+
"highlights": [
|
|
6
|
+
"An app whose setup failed no longer uses one of your app slots or blocks its name: create it again with the same name to retry, or ask Claude to remove it with the new awesomate_app_remove_failed tool"
|
|
7
|
+
]
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"version": "0.88.5",
|
|
11
|
+
"highlights": [
|
|
12
|
+
"Adding a domain now gives your server's public address, never an internal one, and says the records must be Proxied (orange cloud) in Cloudflare with SSL/TLS set to Full"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"version": "0.88.4",
|
|
17
|
+
"highlights": [
|
|
18
|
+
"The site audit now reads your page the way ChatGPT search does, so a page that turns AI bots away is reported as unreachable instead of being scored on the block message, and the sitemap check no longer reports a sitemap missing when it is there",
|
|
19
|
+
"SEO checks test the AI search bots that decide whether you get cited. AI training bots are blocked on purpose on Awesomate-managed addresses, so Claude no longer reports that as a fault"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"version": "0.88.3",
|
|
24
|
+
"highlights": [
|
|
25
|
+
"When the hub cannot bring your n8n credential list up to date, Claude now says the list may be out of date, as of when, and which credentials n8n has added or removed since"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
3
28
|
{
|
|
4
29
|
"version": "0.88.2",
|
|
5
30
|
"highlights": [
|
|
@@ -126,7 +126,10 @@ target; never touch prod without an explicit ask.**
|
|
|
126
126
|
webhooks/integrations → `node-api-only`; landing page → `static-landing`.
|
|
127
127
|
It returns **202** with an `appId` + subdomain(s); poll `awesomate_app_get`
|
|
128
128
|
until `status` is `active` (or `failed` — read `provision_error`, explain
|
|
129
|
-
plainly).
|
|
129
|
+
plainly). A failed app holds no plan slot and doesn't keep its name: to
|
|
130
|
+
retry, call `awesomate_app_create` again with the same `appSlug` (the hub
|
|
131
|
+
clears the failed attempt first). If the user would rather drop it, offer
|
|
132
|
+
`awesomate_app_remove_failed` (`confirm` = the slug) after their yes.
|
|
130
133
|
4. **Scaffold** — call `awesomate_app_scaffold` and write each returned file
|
|
131
134
|
into a fresh local project folder at its relative path (placeholders are
|
|
132
135
|
already substituted), then `npm install` (Node) and read the bundled
|
|
@@ -257,10 +260,11 @@ keep going on what you can fix.
|
|
|
257
260
|
- A `409` with code `app_limit` = the plan's app allowance is full (Support
|
|
258
261
|
Plus 5, Pro 20 — `awesomate_app_context.limits` has the live numbers).
|
|
259
262
|
Don't retry; tell the user and surface the `recommendedPlan`/`deepLink`
|
|
260
|
-
from the error.
|
|
261
|
-
"delete an old one to free a slot",
|
|
262
|
-
The honest options are an upgrade or
|
|
263
|
-
skill) to remove an app.
|
|
263
|
+
from the error. Failed apps never count toward it. There is no tool to
|
|
264
|
+
delete a WORKING app — don't offer "delete an old one to free a slot",
|
|
265
|
+
because neither you nor the user can. The honest options are an upgrade or
|
|
266
|
+
asking support (awesomate-support skill) to remove an app.
|
|
267
|
+
(`awesomate_app_remove_failed` only removes an app whose setup failed.)
|
|
264
268
|
- Never invent that a capability exists — read `awesomate_app_context` first.
|
|
265
269
|
- Never build on the hosting account, and never raise a support ticket for a
|
|
266
270
|
repo or deploy problem yourself: the hub does both the building (via
|
|
@@ -242,7 +242,7 @@ MCP, so say that rather than stopping.
|
|
|
242
242
|
| `awesomate_domain_add` | Attach a custom domain to a site |
|
|
243
243
|
| `awesomate_dns_check` | Live answer to "where does this domain actually point" — before and after any DNS change |
|
|
244
244
|
| `awesomate_site_uptime` | 30-day availability, incidents, downtime per domain (cached, free) |
|
|
245
|
-
| `awesomate_site_audit` | SEO + AEO build gates for one page, fetched as
|
|
245
|
+
| `awesomate_site_audit` | SEO + AEO build gates for one page, fetched as OAI-SearchBot (what ChatGPT search sees) — content present without JS, retrieval bots reachable, canonical, schema, structure, speed. Not plan-gated. Run it after any public-page change, and see the awesomate-seo skill for the fixes |
|
|
246
246
|
| `awesomate_files` | Files on their automation account (public/, private/, temp/): put an image or download up and hand back its `public_url`, fetch what a workflow wrote, tidy a folder. Ask before make_public, a move into public/, or delete; `trash` shows what was deleted, and `empty_trash` erases it for good (show what goes, get a clear yes). Support Plus+, owner's file-folders switch on (`status` says what's missing). Guide: https://hub.awesomate.ai/docs/mcp/guides/files/ |
|
|
247
247
|
| `awesomate_snapshot_site` | Before ANY change to a live site — files + DB restore point |
|
|
248
248
|
| `awesomate_list_snapshots` | What restore points a site has |
|
|
@@ -159,7 +159,7 @@ the robots rules, the JSON-LD block, and tell them precisely where each goes
|
|
|
159
159
|
## 3. Verify — run the gates, don't eyeball it
|
|
160
160
|
|
|
161
161
|
**`awesomate_site_audit { domain, path }`** runs the mechanical gates against
|
|
162
|
-
the live page, fetched *as
|
|
162
|
+
the live page, fetched *as OAI-SearchBot* (what ChatGPT search sees), and returns pass/fail with specific fixes:
|
|
163
163
|
content present without JavaScript, all four retrieval bots reachable, no
|
|
164
164
|
accidental `noindex`/`nosnippet`, canonical pointing at this domain, valid
|
|
165
165
|
structured data whose facts also appear in the copy, section structure,
|
|
@@ -181,10 +181,14 @@ Then confirm by hand what the tool can't judge:
|
|
|
181
181
|
- **Content is in the raw HTML** — `curl -s https://DOMAIN/page` shows the
|
|
182
182
|
actual content, not an empty `<div id="root">`. AI crawlers don't run
|
|
183
183
|
JavaScript; a client-rendered page is invisible to them.
|
|
184
|
-
- **AI
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
- **AI retrieval bots aren't blocked at the edge** — a `curl` as OAI-SearchBot,
|
|
185
|
+
Claude-SearchBot, PerplexityBot, Perplexity-User, ChatGPT-User and Bingbot
|
|
186
|
+
returns 200, not a 403/Cloudflare challenge (robots.txt can't fix an edge
|
|
187
|
+
block). **Training bots (GPTBot, ClaudeBot, CCBot…) are not the test:** on
|
|
188
|
+
Awesomate-managed domains (`*.awesomate.site`, `*.awesomate.app`) they get a
|
|
189
|
+
403 by design, and on the user's own domain letting them in is the user's
|
|
190
|
+
choice. Commands + where to fix each case:
|
|
191
|
+
[references/ai-discoverability.md](references/ai-discoverability.md).
|
|
188
192
|
Tell the user the next step is submitting the sitemap in Google Search Console
|
|
189
193
|
(you can't do that for them) — offer a one-paragraph how-to if they want it.
|
|
190
194
|
|
|
@@ -203,9 +207,12 @@ the user asks to "check SEO", and after any content change:
|
|
|
203
207
|
the page standing in for it — check whichever they have), and the content
|
|
204
208
|
still mentions the current offerings. A stale llms.txt misdescribes the
|
|
205
209
|
business to every AI assistant that reads it.
|
|
206
|
-
4. **AI
|
|
207
|
-
`curl -A "
|
|
208
|
-
(repeat
|
|
210
|
+
4. **AI retrieval bots not blocked at the edge** —
|
|
211
|
+
`curl -A "Mozilla/5.0 (compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot)" -s -o /dev/null -w "%{http_code}" https://DOMAIN/`
|
|
212
|
+
(repeat as Claude-SearchBot, PerplexityBot, Perplexity-User, ChatGPT-User
|
|
213
|
+
and Bingbot) returns 200, not 403 or a challenge page. Don't test with
|
|
214
|
+
GPTBot or ClaudeBot: those are training bots, blocked by design on
|
|
215
|
+
Awesomate-managed domains and the owner's choice elsewhere.
|
|
209
216
|
Where to fix each case: [references/ai-discoverability.md](references/ai-discoverability.md).
|
|
210
217
|
5. **WordPress only: `blog_public` must be 1** — one checkbox ("Discourage
|
|
211
218
|
search engines") silently de-indexes the whole site. Read it via
|
|
@@ -58,39 +58,53 @@ Always check the live `https://DOMAIN/robots.txt`, not just the file you wrote.
|
|
|
58
58
|
|
|
59
59
|
## robots.txt allows it — but the CDN can still 403 it
|
|
60
60
|
|
|
61
|
-
Cloudflare
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
Cloudflare can block AI crawlers at the edge, and steers new zones into doing
|
|
62
|
+
so. The crawler gets a 403 or a challenge page before it ever reads robots.txt,
|
|
63
|
+
so a perfect robots.txt proves nothing. Always verify from the outside, with the
|
|
64
|
+
**retrieval** bots — the ones whose access decides whether the site is cited:
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
for ua in \
|
|
68
|
+
"Mozilla/5.0 (compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot)" \
|
|
69
|
+
"Mozilla/5.0 (compatible; Claude-SearchBot/1.0; +https://anthropic.com)" \
|
|
70
|
+
"Mozilla/5.0 (compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)" \
|
|
71
|
+
"Mozilla/5.0 (compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)" \
|
|
72
|
+
"Mozilla/5.0 (compatible; ChatGPT-User/1.0; +https://openai.com/bot)" \
|
|
73
|
+
"Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"; do
|
|
74
|
+
printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' -A "$ua" https://DOMAIN/)" "$ua"
|
|
75
|
+
done
|
|
70
76
|
```
|
|
71
77
|
|
|
72
78
|
200 = reachable. 403, 503, or an HTML page mentioning Cloudflare = blocked at
|
|
73
|
-
the edge.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
the edge.
|
|
80
|
+
|
|
81
|
+
**Training bots (GPTBot, ClaudeBot, CCBot, Bytespider, Amazonbot…) are a
|
|
82
|
+
different question.** On Awesomate-managed domains (`*.awesomate.site`,
|
|
83
|
+
`*.awesomate.app`) they get `403 Your request was blocked.` **by design** — that
|
|
84
|
+
is policy, not a fault, and it does not affect citation. Don't report it and
|
|
85
|
+
don't ask for it to be lifted. On the user's own domain, letting training bots
|
|
86
|
+
in is the user's choice.
|
|
87
|
+
|
|
88
|
+
Where to fix a blocked **retrieval** bot:
|
|
89
|
+
|
|
90
|
+
- **Awesomate-managed domain**: the zone is managed by Awesomate — the user
|
|
91
|
+
can't change it. Raise it via `awesomate_support`.
|
|
92
|
+
- **Custom domain on the user's own Cloudflare account**: in **AI Crawl
|
|
93
|
+
Control**, set each blocked retrieval bot (OAI-SearchBot, Claude-SearchBot,
|
|
94
|
+
PerplexityBot, Perplexity-User, ChatGPT-User) to **Allow**; training bots are
|
|
95
|
+
their call. If Cloudflare's **managed robots.txt** is on, check the live
|
|
96
|
+
`/robots.txt` doesn't disallow the retrieval bots either. Don't write a WAF
|
|
97
|
+
skip on `cf.verified_bot_category "AI Crawler"`: that category is the
|
|
98
|
+
training crawlers, and PerplexityBot isn't a verified bot (since Aug 2025),
|
|
99
|
+
so a category rule can't match it anyway.
|
|
89
100
|
|
|
90
101
|
Verified 2026-09-02 across awesomate.ai, hub.awesomate.ai and eight live client
|
|
91
|
-
sites: all four retrieval bots got **200
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
sites: all four retrieval bots got **200**. **That is now stale:** on
|
|
103
|
+
08/10/2026 PerplexityBot was found getting 403 on Awesomate-managed zones
|
|
104
|
+
(OAI-SearchBot, Claude-SearchBot, Perplexity-User, ChatGPT-User and Bingbot were
|
|
105
|
+
fine). It is a known Cloudflare fault being fixed — PerplexityBot should get
|
|
106
|
+
200; if a managed site still shows 403 for it, raise it with support rather
|
|
107
|
+
than treating it as expected. Re-check per site rather than assuming either way.
|
|
94
108
|
|
|
95
109
|
## Most AI crawlers do not run JavaScript
|
|
96
110
|
|