UNPKG

@awesomate/hosting-mcp

Version:

Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases

237 lines (200 loc) • 14 kB
--- name: awesomate-seo description: Make the user's site findable by Google AND quotable by AI assistants (SEO + AEO). Runs the build gates with awesomate_site_audit, then fixes what fails: title/meta/Open Graph, sitemap.xml, robots.txt, canonical tags, JSON-LD, answer-shaped content structure, and llms.txt. Works for static sites, Node apps, and WordPress. Use when the user says "SEO", "AEO", "GEO", "answer engine optimisation", "get found on Google", "get cited by ChatGPT", "rank higher", "make my site discoverable", "sitemap", "meta tags", "schema", or after building/changing any public page. Companion to awesomate-app-builder. --- # Awesomate SEO — get found on Google and AI Search engines and AI assistants both need machine-readable signals. This skill adds them to any site the user has. Treat SEO as **ongoing**, not one-shot: bake it in when a page is built, and re-run the relevant parts whenever content or structure changes. Be honest about limits: these are the signals that *let* you rank and be cited — they don't *guarantee* placement. Never promise rankings. ## 0. What kind of site is this? - **Static site or Node app** (from awesomate-app-builder) → you write the files directly into the project (below), commit, and deploy. - **WordPress** → drive it through the hosting tools via the awesomate-hosting skill. Install a free SEO plugin + let it generate the sitemap rather than hand-writing files (see §WordPress). **Check the plan gate first.** - **A shop (WooCommerce)** → same WordPress path, plus `Product` JSON-LD on product pages and product-data quality (real titles, descriptions, images, prices). This skill covers the site-level SEO around the shop. **Business facts come from `awesomate_business`.** Organization and LocalBusiness JSON-LD (name, url, logo, address, telephone, `sameAs` from the social links), titles and meta descriptions must use the owner's confirmed details, never guesses. Leave out anything marked *suggestion* until the owner confirms it, and list what's missing rather than inventing it. ### Plan gate — check before promising any WordPress change **Every PAT-authenticated hosting WRITE is Support Plus and above**: `awesomate_run_wp_cli`, `awesomate_wp_post`, `awesomate_wp_media_import`, `awesomate_wp_settings`, plus `awesomate_site_create` and `awesomate_domain_add`. On **Essentials** they all return **403 `upgrade_required`** — the server enforces it, so no retry or rewording gets through. This matters more here than anywhere else: **Essentials is the plan that gets exactly one WordPress site**, so it is the most likely plan for someone asking about SEO. Get `plan` from `awesomate_get_context` at the start and branch honestly. **On Essentials, assume no tool touches their WordPress at all.** Note that `awesomate_run_wp_cli` is gated even for its READS (`option get`, `plugin list`) — the whole route is behind the write gate, so "just reading the options" is not a way round it. The account-level reads do work (`awesomate_get_context`, `awesomate_list_sites`, `awesomate_list_domains`, `awesomate_dns_check`, `awesomate_site_uptime`, and **`awesomate_site_audit`** — the full gate sweep works on every plan, because it reads the public page). **What Essentials CAN do — which is most of the value:** audit and advise from the outside. Start with `awesomate_site_audit` — it runs the whole sweep in one call and is NOT plan-gated, so an Essentials user gets exactly the same findings as anyone else. Then produce the exact changes — the titles and descriptions to paste, the JSON-LD block, the llms.txt content, which plugin to install and where its settings live. They apply them in wp-admin; you verify by fetching the live page again. Say that up front — *"I can audit the site and write every change out for you to paste in; me making them directly needs Support Plus"* — not after a 403. ## 1. Static / Node — write these Follow [references/seo-checklist.md](references/seo-checklist.md) for exact formats + length limits. In short, per site: 1. **`<head>` tags** on every page: unique `<title>` (≤60 chars), meta description (≤155), canonical `<link>`, Open Graph (`og:title/description/ image/url/type`) and `twitter:card`. The static-landing template ships `{{...}}` placeholders — fill them with real values. 2. **`robots.txt`** at the site root — allow crawling, point to the sitemap. 3. **`sitemap.xml`** at the root — list every real URL with `<loc>` (+ `<lastmod>`). 4. **JSON-LD** (`<script type="application/ld+json">`) — the right schema.org type (`Organization` / `WebSite` / `Product` / `Article` / `LocalBusiness`). 5. **Answer-shaped content** — the part that decides whether the page is actually *quoted* rather than merely found: answer-first sections of 120–180 words, no section opening with "it"/"this"/"also", comparisons in a real `<table>`, specific numbers and dates inline, and every schema fact also present in the visible copy. Full discipline: [references/answer-structure.md](references/answer-structure.md). This is the highest-leverage item on the list and the one most often skipped. 6. **`llms.txt`** at the root — cheap, so write it, but keep it in proportion: Google ignores it entirely and one study of 137,210 domains found 97% of published files got zero requests. Generate it, never present it as a pillar, never bill for it. Crawler/rendering gotchas: [references/ai-discoverability.md](references/ai-discoverability.md). Then commit + deploy (awesomate-github). On content changes, update the affected `<head>` tags, `sitemap.xml` `<lastmod>`, and `llms.txt`. ## 2. WordPress **Find the domain, don't ask for it.** `awesomate_list_sites` and `awesomate_list_domains` tell you what sites exist and which domain is attached to which. Ask only when the answer is genuinely ambiguous (more than one site, and the user hasn't said which). **Snapshot before you change a live site.** `awesomate_snapshot_site` first, and tell the user the `snapshotId` — the hosting skill requires this and SEO work is exactly the kind of change that touches the whole site at once (a plugin, a theme option, an indexing flag). `awesomate_rollback_site` is the undo. Then, on Support Plus and above: - **Install + activate an SEO plugin** — `awesomate_run_wp_cli` with args `['plugin','install','wordpress-seo','--activate']` for Yoast, or the user's preference. Slugs only, never a URL or zip. This part works. - **Configuring it does NOT work from here.** The wp-cli gate allows `option update` for exactly ten core options, and `wpseo_titles` and friends are not among them; their values are JSON full of spaces, which the argument charset gate refuses anyway. So: you install and activate, then hand off — *"Yoast is installed. Open Settings → Yoast SEO in wp-admin and I'll talk you through the title template and the social image, or give me the values and I'll write out exactly what to paste."* Don't burn attempts discovering this at runtime. - Confirm the sitemap is live (`/sitemap_index.xml` or `/sitemap.xml`) and `robots.txt` references it — `curl` the live URLs. - **Posts and pages** via `awesomate_wp_post` (drafts first — the user approves publishing). Useful for the content pages that back up `llms.txt` — a services overview, an FAQ, an about page — when the site is thin on machine-readable substance. - **The og:image / logo** goes in via `awesomate_wp_media_import` — one https URL per call, returns an `attachmentId` you can reference from a post or hand to the SEO plugin's social settings. It cannot read a local file: the image has to be reachable on the web first. - **Site title, tagline, timezone, search visibility** → `awesomate_wp_settings` (§4), never wp-cli — those values contain spaces. - WordPress is the recommended stack precisely when SEO/organic reach matters — lean into it here. ### Files at the site root: say what's actually possible §1's `robots.txt` / `sitemap.xml` / `llms.txt` advice is for **static sites and Node apps**, where you write the file into the project and deploy it. **On WordPress there is no tool that writes a file to the site.** `awesomate_run_wp_cli` cannot (no file verbs are allowlisted), `wp_post` writes posts and pages, and `wp_media_import` takes an https URL. Don't promise the file and then discover this. On WordPress those three come from: - **`robots.txt` and `sitemap.xml`** — the SEO plugin generates both (WordPress serves a virtual robots.txt; Yoast and friends add the sitemap and the reference to it). That's why installing the plugin is step one. - **`llms.txt`** — no plugin makes one. Either the user places the file over SSH or cPanel's File Manager (`scripts/ssh-connect.sh` in the hosting skill, Support Plus+), or you publish the same content as a normal page with `awesomate_wp_post` and link it — a real page is crawlable and editable, and gets most of the benefit. **You can always generate the content.** Write the exact `llms.txt` body, the robots rules, the JSON-LD block, and tell them precisely where each goes — that is the useful half, and it works on every plan. ## 3. Verify — run the gates, don't eyeball it **`awesomate_site_audit { domain, path }`** runs the mechanical gates against the live page, fetched *as GPTBot*, and returns pass/fail with specific fixes: content present without JavaScript, all four retrieval bots reachable, no accidental `noindex`/`nosnippet`, canonical pointing at this domain, valid structured data whose facts also appear in the copy, section structure, 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**. Checking in a browser is not equivalent — the browser runs the JavaScript that hides the biggest failure. Two gates come back `skipped` because they need a headless browser (content revealed only on click) or a full crawl (internal 404s). **Skipped means unknown, not passing** — say so rather than reporting a clean sweep. Then confirm by hand what the tool can't judge: - `robots.txt` and `sitemap.xml` (or the WP sitemap) return 200 at the root. - Each key page has a unique title + description and valid JSON-LD (no syntax errors — a broken `application/ld+json` block is worse than none). - `llms.txt` exists and is accurate. - **Content is in the raw HTML** — `curl -s https://DOMAIN/page` shows the actual content, not an empty `<div id="root">`. AI crawlers don't run JavaScript; a client-rendered page is invisible to them. - **AI crawlers aren't blocked at the edge** — a `curl` with a GPTBot / ClaudeBot user-agent returns 200, not a 403/Cloudflare challenge (Cloudflare blocks many AI bots by default; robots.txt can't fix that). Commands + where to fix each case: [references/ai-discoverability.md](references/ai-discoverability.md). Tell the user the next step is submitting the sitemap in Google Search Console (you can't do that for them) — offer a one-paragraph how-to if they want it. ## 4. Ongoing upkeep — the seo-healthcheck SEO decays quietly: a plugin update flips an option, an edge rule starts challenging crawlers, a sitemap stops regenerating. Run this routine whenever the user asks to "check SEO", and after any content change: 1. **Content in the raw HTML** — `curl -s https://DOMAIN/page` and confirm the key content is actually in the response, not rendered later by JavaScript. 2. **Sitemap** — `/sitemap.xml` (WP: `/sitemap_index.xml`) returns 200 and `<lastmod>` is fresh. A months-old lastmod on a site that changed last week means generation is broken, not that nothing changed. 3. **robots.txt + llms.txt** — both exist (on WordPress, `llms.txt` may be the page standing in for it — check whichever they have), and the content still mentions the current offerings. A stale llms.txt misdescribes the business to every AI assistant that reads it. 4. **AI crawlers not blocked at the edge** — `curl -A "GPTBot" -s -o /dev/null -w "%{http_code}" https://DOMAIN/` (repeat with `ClaudeBot`) returns 200, not 403 or a challenge page. Where to fix each case: [references/ai-discoverability.md](references/ai-discoverability.md). 5. **WordPress only: `blog_public` must be 1** — one checkbox ("Discourage search engines") silently de-indexes the whole site. Read it via `awesomate_run_wp_cli` with args `['option','get','blog_public']`. If it's 0, fix it with **`awesomate_wp_settings {domain, searchEngineVisible: true}`** — that path also flushes the object cache, which the wp-cli `option update` does not, so the change actually shows on the live site instead of sitting behind a stale cache. (A page or CDN cache may still need its own refresh.) 6. **"My site vanished from Google" is often not SEO at all.** Before auditing tags, check the two things that take a site off the internet: `awesomate_dns_check` (is the domain still pointing at the hosting?) and `awesomate_site_uptime` (30-day availability and incidents). A domain that stopped resolving, or a site that was down for two days, explains a ranking drop far better than a meta description does. Report pass/fail per check, with the fix for each failure. **Make it automatic:** offer — once — to build a scheduled n8n workflow (via the awesomate-n8n skill) that runs these checks weekly and emails the user the result. A weekly email is what turns "SEO as ongoing" from a good intention into a mechanism. ## Hard rules - Never fabricate content, reviews, or business facts to "help SEO". - Never claim these guarantee a ranking — they make the site *eligible* and *legible*, to search engines and AI both. - Invalid structured data is a bug — validate the JSON before shipping.