{
  "name": "Luola",
  "version": "0.2.0",
  "description": "Build, edit, import, and publish complete websites from a prompt. Sites go live on *.luola.site in seconds.",
  "vendor": {
    "name": "Luola",
    "url": "https://luola.ai"
  },
  "support_email": "support@luola.ai",
  "security_email": "security@luola.ai",
  "privacy_url": "https://luola.ai/legal/privacy",
  "terms_url": "https://luola.ai/legal/terms",
  "docs_url": "https://luola.ai/docs/mcp",
  "icon_url": "https://luola.ai/icon.svg",
  "mcp_endpoint": "https://mcp-dev.luola.ai/mcp",
  "transports": [
    {
      "type": "http",
      "url": "https://mcp-dev.luola.ai/mcp"
    }
  ],
  "oauth": {
    "authorization_endpoint": "https://mcp-dev.luola.ai/authorize",
    "token_endpoint": "https://mcp-dev.luola.ai/token",
    "registration_endpoint": "https://mcp-dev.luola.ai/register",
    "metadata_url": "https://mcp-dev.luola.ai/.well-known/oauth-authorization-server",
    "legacy_bearer_prefix": "sb_live_"
  },
  "tools": [
    {
      "name": "list_projects",
      "title": "List Projects",
      "description": "List every website, landing page, and portfolio the user has built on Luola. Use when: user asks to show, list, or find their existing sites; \"what sites have I made\", \"näytä sivustot\", \"listaa kotisivut\", \"mitä sivuja mulla on\". Don't use when: user references one specific project — call get_project (status of one) or get_project_context (rich snapshot incl. domains/data-model/activity) instead. Returns each project's name, id, and live URL."
    },
    {
      "name": "get_project",
      "title": "Get Project",
      "description": "Fetch the current status, files, and live URL of one Luola website project. Use when: user asks to check, inspect, or get status of a specific site; \"tarkista sivuston tila\", \"onko sivusto valmis\", \"what's the URL of my site\". After create_website / edit_website to confirm generation finished before publishing. Don't use when: user wants a rich snapshot with domains + data-model + activity → use get_project_context. Discovering project IDs → use list_projects first. Pre-reqs: project must exist (use list_projects to find IDs)."
    },
    {
      "name": "create_website",
      "title": "Create Website",
      "description": "Build a complete website from a text prompt and publish it to a real URL on luola.site. Use when: user asks to make, create, or build a website / landing page / portfolio / business site / homepage / online store / marketing page / blog; \"kotisivut\", \"verkkosivut\", \"nettisivut\", \"kotisivut yritykselle\", \"sivusto\". Don't use when: user has HTML already → create_website_from_html. User has a sketch/mockup image → create_website_from_sketch. User has an existing URL to migrate → import_website. User wants to edit an existing site → edit_website (creative) or patch_site (mechanical). Initial generation produces up to 3 pages for speed (~2-3 min); add more later with edit_website. Set publish: true to go live automatically on *.luola.site."
    },
    {
      "name": "create_website_from_html",
      "title": "Publish an HTML artifact as a live Luola site",
      "description": "Publish raw HTML (e.g. a Claude HTML artifact or any hand-written page) as a live website on *.luola.site in one call. Use when: user already has HTML — usually an artifact produced earlier in this chat — and asks to publish, deploy, host, put it online, make it a real website; \"julkaise tämä\", \"vie nettiin\", \"tee tästä oikea sivusto\". Don't use when: user has only a prompt → create_website. User has a sketch image → create_website_from_sketch. HTML is meant as a NEW page in an existing project → add_file_to_site. User wants edits to existing site → edit_website / patch_site. Accepts CSS and JS separately (auto-linked into <head>/<body>) and binary assets (images, videos, fonts) as base64. Returns project_id, preview URL, and live https URL. Total payload cap 2 MB; non-HTTPS external refs rejected to avoid mixed content."
    },
    {
      "name": "create_website_from_sketch",
      "title": "Create Website From Sketch",
      "description": "Build a website from a sketch, drawing, whiteboard photo, screenshot, or mockup image (PNG/JPG/WebP). Use when: user has a visual design they want turned into a real live site; \"tee sivusto luonnoksesta\", \"kuvasta\", \"mockupista\", \"piirustuksesta\", \"Figma-kuvakaappauksesta\". Don't use when: user has no image, only a text idea → create_website. User has HTML output → create_website_from_html. User wants to migrate an existing live site → import_website. The sketch drives layout; optional text refines brand/tone; if name is omitted the AI derives one. Returns project_id + plan within seconds; background code generation finishes in ~1-2 minutes."
    },
    {
      "name": "import_website",
      "title": "Import Website",
      "description": "Migrate an existing website to Luola while keeping its current domain. Scrapes the source site, analyzes design, rebuilds it as a Luola project; pairs with add_custom_domain so the user keeps acme.fi (and its SEO) on the new build. Use when: user wants to switch hosts, replace WordPress, leave Squarespace / Wix / GoDaddy / Shopify, redesign without losing domain or rankings, modernise an old site; \"tuo vanha verkkosivusto Luolaan\", \"säilytä oma domain\", \"vaihda hosting\", \"korvaa WordPress\", \"modernisoi sivut\". Don't use when: building from scratch with no source URL → create_website / create_website_from_sketch. User already exported HTML → create_website_from_html. Source is already a Luola project → edit_website / patch_site. Returns project_id; publishes to *.luola.site when publish: true. Combine with add_custom_domain afterwards to keep the original URL pointing at the new site. Note: heavyweight AI regeneration; expect 2-5 min per site."
    },
    {
      "name": "edit_website",
      "title": "Edit Website",
      "description": "Modify an existing Luola website with natural-language instructions — add sections, rewrite copy, change layout, swap images, update styling, fix issues. Use when: user says change, update, modify, rewrite, add, remove, fix referring to an existing site; \"muokkaa\", \"päivitä\", \"lisää\", \"vaihda\", \"korjaa\". Creative edits where you can't precisely describe before/after text. Don't use when: change is a mechanical string/class swap with known before/after → patch_site (faster, no AI, ~1s vs 1-2min). Adding an entirely new file/page → add_file_to_site. Changing theme/colors/fonts only → configure_theme. Adding analytics/tracking → configure_integrations. Pre-reqs: project must already have generated files. Changes save automatically."
    },
    {
      "name": "patch_site",
      "title": "Patch site files (find-replace)",
      "description": "Apply deterministic find-replace (string or regex) edits across a Luola site's HTML/CSS/JS. No AI call, runs in ~1s, never times out. Use when: user wants a mechanical change you can precisely describe as before/after text — colour class swaps, image src swaps, class renames, snippet removal or insertion, string substitutions; \"korvaa teksti\", \"vaihda väri\", \"swap string\". Don't use when: change is creative (new sections, layout changes, rewritten copy) → edit_website. Adding a NEW file/page → add_file_to_site. Changing theme tokens (colors/fonts) → configure_theme. Pre-reqs: target strings must exist in the site's files (no-op if no match). Changes write to D1 and re-upload to the live site immediately."
    },
    {
      "name": "upload_media",
      "title": "Upload Media (image or video) to a site",
      "description": "Upload an image, photo, logo, banner, or video to a Luola site so it can be referenced as `./img/<filename>` in HTML. Use when: user asks to add, upload, or attach a picture, photo, logo, hero image, background, or video; \"lisää kuva\", \"lataa kuva\", \"lisää logo\", \"lisää video\", \"vaihda kuva\". Don't use when: file is HTML/CSS/JS/text → add_file_to_site. Changing existing image references in code → patch_site. Changing visual theme tokens (not actual files) → configure_theme. Pre-reqs: project must exist. Pass sourceUrl for files already on the web (preferred for >1 MB: Dropbox, S3, Imgur, GDrive) or dataBase64 for small inline bytes. Max 25 MB. Returns sitePath to reference in HTML."
    },
    {
      "name": "optimize_tailwind",
      "title": "Optimize Tailwind (replace CDN with static CSS)",
      "description": "Speed up a Luola site by replacing the Tailwind runtime CDN (~124 KiB render-blocking script) with a pre-compiled /styles.css hashed to the classes actually used. Use when: user asks to improve PageSpeed, Lighthouse, Core Web Vitals, LCP, site speed, or page load; \"nopeuta sivustoa\", \"parempi suorituskyky\", \"PageSpeed-optimointi\", \"Lighthouse-pisteet\". Don't use when: user wants accessibility / contrast / build-error fixes → apply_quality_fixes. User wants a full performance audit before changing anything → audit_my_site. Pre-reqs: project must use Tailwind CDN (idempotent no-op otherwise). Safe to run repeatedly."
    },
    {
      "name": "publish_website",
      "title": "Publish Website",
      "description": "Make a Luola website live at a public URL, or take it offline. Use when: user says publish, deploy, ship, go live, put it online; \"julkaise\", \"vie tuotantoon\", \"laita nettiin\", \"julkaise sivusto\". After create_website / edit_website / patch_site / configure_* when user wants changes visible to the public. Don't use when: site is still generating — poll get_project until generation_status=\"done\" first. Just-applied audit fixes the user hasn't reviewed — show them first. Pre-reqs: project must have generated files. Returns the live https URL on *.luola.site (or connected custom domain). Pass action: \"unpublish\" to take offline. If the API responds that a custom domain is not yet DNS/SSL-ready, surface the warning; only retry with overrideDomainWarnings: true after the user explicitly says publish anyway."
    },
    {
      "name": "configure_integrations",
      "title": "Configure Tracking Integrations",
      "description": "Set up analytics and tracking on a Luola site — Google Tag Manager (GTM), Google Analytics 4 (GA4), Facebook Pixel — plus optional custom <head> or pre-</body> HTML snippets. Use when: user asks to add analytics, tracking, GTM, GA4, Facebook Pixel, conversion pixel; \"seuranta\", \"analytiikka\", \"lisää analytics\", or inject a custom <script>. Don't use when: user wants a cookie consent banner → configure_consent (which gates these integrations). User wants to view collected data — analytics live in GA4 etc., not in Luola. Pre-reqs: project must exist. Takes effect on next publish."
    },
    {
      "name": "configure_consent",
      "title": "Configure Cookie Consent Banner",
      "description": "Enable and configure a GDPR cookie-consent banner (Google Consent Mode v2) on a Luola site. Use when: user asks about a cookie banner, consent banner, GDPR, privacy notice, Consent Mode, tracking opt-in, cookie law compliance; \"evästebanneri\", \"evästeet\", \"suostumus\". Don't use when: user wants to ADD analytics scripts directly → configure_integrations (this tool only gates them via consent). User wants a privacy policy page itself — not yet a dedicated MCP verb; use add_file_to_site or edit_website. Pre-reqs: project must exist. Modes: \"opt-in\" (EU compliance, blocks tracking scripts until accept) or \"notice-only\". Categories gate analytics, marketing, and preference scripts."
    },
    {
      "name": "configure_theme",
      "title": "Configure Design & Theme",
      "description": "Change the visual theme of a Luola site — colors, typography, buttons, shadows, density, radius — without regenerating code. Use when: user asks to change colours, brand colors, fonts, theme, look and feel, button style, corner radius, or re-style the site; \"vaihda värit\", \"vaihda fontit\", \"muuta tyyliä\", \"brändivärit\", \"säädä ulkoasua\". Don't use when: user wants to change CONTENT, structure, or specific sections → edit_website. User wants a one-off style override on a single element → patch_site. Pre-reqs: project must exist. Colors are 6-digit hex; shades derive automatically. Partial patches merge into existing settings; pass reset: true to clear overrides and restore AI defaults. Takes effect on next publish/stage."
    },
    {
      "name": "add_custom_domain",
      "title": "Connect a custom domain to a Luola site",
      "description": "Connect an existing user-owned domain (acme.fi, mybiz.com, anything.io) to a published Luola site and return the exact DNS records to paste into the registrar. Use when: user says connect domain, attach domain, custom domain, my own domain, point a domain at; \"kytke oma domain\", \"lisää oma verkkotunnus\", \"oma osoite\". Don't use when: user wants to BUY a new domain through Luola → start_domain_purchase (auto-connects after payment). Checking status of an already-connected domain → verify_domain. Listing what's connected → list_domains. Pre-reqs: domain must already be owned by the user (registered elsewhere) and project must be publishable. Default method \"cname\" — simpler, recommended; \"zone\" only when user wants to move all DNS to Cloudflare/Luola. Returns domain_id, DNS records, verification + SSL status, and next-check ETA."
    },
    {
      "name": "verify_domain",
      "title": "Check the status of a connected custom domain",
      "description": "Check whether a custom domain previously connected via add_custom_domain is now verified and has SSL active. Use when: user reports they added the DNS records, or asks \"onko domain valmis\", \"is the domain ready\", \"did SSL come through\", \"tarkista domainin tila\", \"verify my domain\". Don't use when: checking a domain purchase order (Stripe Checkout flow) → check_domain_purchase_status. Listing all connected domains → list_domains. Pre-reqs: domain_id must come from add_custom_domain. Returns status (pending / nameservers_pending / active / error), SSL status, and next_check_eta_seconds hint so the LLM paces follow-ups instead of spin-polling."
    },
    {
      "name": "list_domains",
      "title": "List custom domains attached to a Luola project",
      "description": "List every custom domain connected to a Luola project, with each domain's status, SSL state, primary flag, and connection method. Use when: user asks which domains are connected, list domains, show domains; \"mitkä domainit\", \"näytä verkkotunnukset\". Don't use when: checking ONE domain's verification state → verify_domain. Checking a purchase order → check_domain_purchase_status. Pre-reqs: project must exist. Returns the primary domain first, then secondaries by creation order."
    },
    {
      "name": "set_primary_domain",
      "title": "Choose the primary (canonical) custom domain for a Luola project",
      "description": "Mark one connected custom domain as the project's primary (canonical) URL — used in OG tags, sitemap, canonical links, and as redirect target for other domains attached to the same project. Use when: project has multiple domains attached (e.g. acme.fi + acme.com, or apex + www) and user asks to make one the main one; \"set canonical\", \"set primary\", \"ensisijainen\", \"päädomain\". Don't use when: only one domain connected (no-op). Adding a new domain → add_custom_domain. Pre-reqs: at least 2 domains connected via add_custom_domain (use list_domains to confirm + get domainId). The previous primary is automatically demoted to secondary."
    },
    {
      "name": "audit_site",
      "title": "Audit a Luola site for quality, accessibility, and build issues",
      "description": "Run cheap local quality validators against a Luola site's draft without publishing — WCAG AA contrast, vague link text, color consistency, import typos, syntax errors, placeholder URLs, missing meta, unused CSS. Use when: user asks to audit, check, validate, lint, accessibility check, contrast check; \"tarkista sivu\", \"lint sivusto\", \"saavutettavuusarviointi\", or just \"is the site OK\". For pre-publish sanity checks. Don't use when: user wants the deep 126-check external audit of the LIVE published site → audit_my_site. Auditing competitor / external URL → audit_external_website. Side-by-side competitor compare → compare_to_competitor. Pre-reqs: project must have generated files. Returns issues with severity (error / warning / info), source (design / build / css), message, file, and auto_fixable flag. Pair with apply_quality_fixes to fix everything machine-fixable in one shot."
    },
    {
      "name": "apply_quality_fixes",
      "title": "Apply auto-fixable quality / accessibility / build fixes",
      "description": "Apply every auto-fixable issue from a Luola site's audit (contrast tweaks, import typos, unused CSS, deduped Tailwind classes) to the project draft. Use when: user says fix the issues, auto-fix, clean up; \"korjaa virheet\", \"optimoi sivu\"; after audit_site reports fixable issues. Don't use when: issues are not auto-fixable (need creative edit) → edit_website. Issue is a known mechanical string swap → patch_site. Speed optimization (Tailwind CDN) → optimize_tailwind. Pre-reqs: run audit_site first to see what's fixable. Persists fixed files but does NOT publish — call publish_website afterwards to ship the changes."
    },
    {
      "name": "define_data_model",
      "title": "Define or extend a Luola site's data model",
      "description": "Define the database tables for a Luola site (contact_messages, bookings, products catalog, etc.). Use when: user wants to add data storage, save form submissions to a database, build a CRUD app; \"lisää tietokanta\", \"tallenna lomakedata tietokantaan\", \"tee asiakasrekisteri\". Don't use when: user just wants a basic contact form whose submissions go to email — that needs no data model. Reading rows back → query_site_data or list_form_submissions. Plain blog content → create_blog_posts (uses its own tables). Pre-reqs: project must exist. Idempotent — re-posting the same schema is a no-op; adding new tables or columns is safe. Refuses to drop existing columns or tables (returns migration_required envelope) so user data is never silently destroyed. After defining, call publish_website to provision D1 and run migrations."
    },
    {
      "name": "query_site_data",
      "title": "Read rows from a Luola site's database",
      "description": "Query rows from a Luola site's D1 database — list bookings, list products, view contact-form submissions, count signups, etc. Read-only. Use when: user asks to show / read / list / view database rows; \"hae kannasta\", \"näytä ilmoittautumiset\", \"listaa varaukset\", \"view submissions\". Don't use when: reading specifically form-submission tables → list_form_submissions (purpose-built, always PII-gated, friendlier output). Defining/changing schema → define_data_model. Pre-reqs: table must be declared via define_data_model. Filter by exact column-value match, sort, paginate. For tables with PII columns (email, phone, name, message, address) the caller MUST set acknowledge_pii_export: true — every PII read is audit-logged."
    },
    {
      "name": "list_form_submissions",
      "title": "List form submissions for a Luola site",
      "description": "Read user-submitted form data (contact-form messages, newsletter signups, registration entries, booking enquiries) from a Luola site. Use when: user asks to show form submissions, view contact messages, list signups, view leads; \"näytä viestit\", \"lue lomake-vastaukset\", \"tarkista asiakaskyselyt\". Don't use when: querying arbitrary database tables → query_site_data. Pre-reqs: project must have at least one form. PII-by-default: form submissions always contain personal data (name, email, message), so acknowledge_pii_export: true is required and every read is audit-logged."
    },
    {
      "name": "create_blog_posts",
      "title": "Bulk-create blog posts (drafts by default)",
      "description": "Bulk-create blog posts on a Luola site — multiple posts in one call. Default status is \"draft\" so the user can review before publishing; pass status: \"published\" to publish immediately. Use when: user asks for several blog posts at once, programmatic SEO, content scaling, blog series; \"lisää blogikirjoituksia\", \"tee artikkeleita\", \"sisältötuotantoa\". Don't use when: editing existing posts — not yet exposed as MCP verb (use edit_website for content edits). Listing what's already published → list_blog_posts. Refreshing listing pages → regenerate_blog_index. Pre-reqs: project must have a blog template (published at least once). Daily quota: 50 posts per project per 24h. Posts sharing an existing slug get a 6-char suffix. After creation, call regenerate_blog_index (or wait for next publish) to refresh listing pages and RSS."
    },
    {
      "name": "regenerate_blog_index",
      "title": "Regenerate blog listing pages, post pages, and RSS without a full publish",
      "description": "Re-render blog listing pages, individual post pages, category pages, and RSS feed for a Luola site, then push to R2. Does NOT re-run the full publish pipeline. Use when: user asks to refresh the blog index, regenerate listings, update RSS; \"päivitä blogi\", \"refresh sitemap\"; after changing post statuses or bulk-creating posts via create_blog_posts with status:\"published\". Don't use when: full site republish needed (theme/integrations changed) → publish_website. Pre-reqs: site must have been published at least once (no-op if no blog template found). Cheap — runs in seconds vs full publish."
    },
    {
      "name": "list_blog_posts",
      "title": "List blog posts on a Luola site",
      "description": "List blog posts on a Luola site, with title, slug, status (draft / published / scheduled), category, and reading time. Use when: user asks to show blog posts, list articles, \"what's on the blog\"; \"näytä blogikirjoitukset\", \"listaa artikkelit\". Don't use when: counting form submissions or other DB data → query_site_data or list_form_submissions. Creating new posts → create_blog_posts. Pre-reqs: project must have a blog. Filter by status or category. Defaults to published posts only."
    },
    {
      "name": "get_project_context",
      "title": "Get a complete one-shot context snapshot for a Luola project",
      "description": "Fetch a comprehensive snapshot of a Luola project — metadata, connected custom domains + SSL status, defined database tables, form submissions count (last 7d), total blog posts, last 5 version snapshots. Use when: user references a previously-created project (\"the cottage rental site I worked on\", \"tee muutos siihen suomalaisten kotisivuun\") and you need full context before editing. Don't use when: you only need basic status → get_project is cheaper. Discovering IDs → use list_projects first. Pre-reqs: project must exist. Cheaper than calling get_project + list_domains + list_blog_posts separately — same info in one call."
    },
    {
      "name": "suggest_domain_names",
      "title": "Suggest available domain names for a new Luola site",
      "description": "Check a batch of LLM-generated domain candidates for availability + price. The caller (Claude) generates candidate names from the user's business context; the tool verifies each against the registrar and filters premium / brand-suggestive / unsupported entries. Use when: user asks for domain suggestions or brainstorms a name; \"ehdota verkkotunnusta\", \"brainstormaa nimeä\", \"what should I call my site\", \"find me a domain\". Don't use when: user already names specific domains to evaluate → check_domain_availability. User picked one and wants to buy → start_domain_purchase. Pre-reqs: caller must generate candidates fitting the user's business context (industry, location, brand vibe). Cap of 15 candidates per call. Returns each with availability, price USD/year, registrar, and reason when filtered out."
    },
    {
      "name": "check_domain_availability",
      "title": "Check whether one or more domains can be registered through Luola",
      "description": "Check availability + price for a list of domains the user wants to register. Returns one record per domain: available (yes/no), price USD/year, and a `reason` string when blocked (premium, brand-suggestive, unsupported TLD). Use when: user names specific domains to evaluate (acme.com, acme.fi, acme.io). Don't use when: free-form name brainstorming → suggest_domain_names (generates AND checks in one shot). User picked one and confirmed → start_domain_purchase. Checking SSL state of already-connected domain → verify_domain. Pre-reqs: domains must be specific candidates, not patterns. Premium / aftermarket pricing is filtered out — never returns a $5,000 surprise quote. Cap of 20 domains per call."
    },
    {
      "name": "start_domain_purchase",
      "title": "Initiate a domain purchase via Stripe Checkout",
      "description": "Initiate a domain registration: lock the price, create a Stripe Checkout Session, and return the payment URL. Use when: user picked an available domain (from check_domain_availability or suggest_domain_names) and confirms they want to buy; \"osta domain\", \"rekisteröi domain\", \"hanki verkkotunnus\". Don't use when: connecting a domain the user ALREADY owns at another registrar → add_custom_domain. Checking purchase progress → check_domain_purchase_status. Transferring out → request_domain_transfer_out. Pre-reqs: domain must pass availability + premium checks first. The tool returns a checkout URL the user must click to pay. Registration / nameserver setup / DNS / SSL / project binding run automatically after payment — poll check_domain_purchase_status every 20-30s; response includes next_check_eta_seconds. Once-registered domains are NON-REFUNDABLE (ICANN registry rule). The tool surfaces this in the Stripe Checkout description."
    },
    {
      "name": "check_domain_purchase_status",
      "title": "Check the status of a domain purchase order",
      "description": "Poll the post-payment pipeline for a domain order. Returns one of: awaiting_payment, paid_provisioning, registered_connecting, live, expired, failed_refunded, failed_manual_review — plus a human-readable status_message and next_check_eta_seconds for pacing. Use when: after start_domain_purchase to follow progress, or user asks \"onko domain valmis\", \"is the registration done\", \"did my domain go through\". Don't use when: verifying DNS/SSL state of an already-connected domain → verify_domain. Listing which domains are connected → list_domains. Pre-reqs: order_id must come from start_domain_purchase. When status reaches `live`, domain is registered, bound to project, DNS configured, and SSL provisioning continues at Cloudflare — call verify_domain afterwards to track SSL state."
    },
    {
      "name": "request_domain_transfer_out",
      "title": "Request transfer-out of a domain registered through Luola",
      "description": "Initiate transfer-out of a domain originally registered through Luola — unlocks the 60-day-post-registration registrar lock and returns the EPP auth code the user pastes into their next registrar. Use when: user wants to leave Luola, transfer their domain elsewhere, move to another registrar; \"siirrä domain pois\", \"transfer my domain\". Don't use when: domain was NOT registered through Luola (only connected via add_custom_domain) — there's nothing for us to release. Disconnecting a connected domain — that's a separate flow not covered by this verb. Pre-reqs: domain must have been registered through Luola via start_domain_purchase. Returns auth code immediately. Available from day 1 across all supported TLDs — Luola does not lock customers in."
    },
    {
      "name": "audit_my_site",
      "title": "Run a full 126-check external audit on a Luola site",
      "description": "Run a full Luola Audit (126 checks across 13 categories — performance, accessibility, security, GDPR, AI readiness, AI visual analysis) on the LIVE published URL of a Luola project. Use when: user wants a deep audit of their published site, full audit, GDPR-tarkistus, AI-readiness check, before-and-after comparison around a publish. Don't use when: pre-publish draft validation → audit_site (faster, local, cheaper). Auditing competitor / external URL → audit_external_website. Side-by-side vs competitor → compare_to_competitor. Pre-reqs: project must already be published (deployed_url required). Returns overall score + 13 category scores + screenshot + audit_id. Combine with apply_quality_fixes to fix issues, then re-run for before/after."
    },
    {
      "name": "audit_external_website",
      "title": "Audit any website (Luola Audit — 126 checks)",
      "description": "Audit any website on the internet against 126 checks across 13 categories — same Luola Audit engine that powers audit.luola.ai, exposed through the Luola MCP. Use when: user asks to audit a competitor, check a prospect site, audit any URL that isn't their own Luola project; \"tarkista kilpailijan sivu\", \"audit my old wordpress site\". Don't use when: auditing a Luola project specifically → audit_my_site (also returns project context). Side-by-side vs the user's own → compare_to_competitor. Pre-publish draft validation on a Luola project → audit_site. Pre-reqs: URL must be https://. Public URL — anyone's site. Returns overall score + 13 category scores + screenshot + audit_id."
    },
    {
      "name": "compare_to_competitor",
      "title": "Compare a Luola site against a competitor URL — side-by-side audit",
      "description": "Audit the user's Luola site AND a competitor URL in parallel and return a side-by-side comparison across 126 checks. Highlights largest gaps and which side leads each category. Use when: user asks to compare to a competitor, \"are we better than X\"; \"vertaa kilpailijaan\", \"vertaa luolasivua johonkin\". Don't use when: auditing only own site → audit_my_site. Auditing only competitor → audit_external_website. Pre-reqs: Luola project must be published (deployed_url required); competitor URL can be any https:// URL. Returns overall delta + per-category delta + losing-gap suggestions."
    }
  ]
}