@hostinger/mcp 3.1.0 → 3.2.1
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/CHANGELOG.md +33 -0
- package/README.md +47 -301
- package/gemini-extension.json +1 -1
- package/package.json +2 -1
- package/server.json +2 -2
- package/skills/audit-hosting/SKILL.md +1 -1
- package/skills/deploy-to-hosting/SKILL.md +32 -15
- package/skills/headless/references/DATABASE.md +3 -3
- package/skills/headless/references/DEPLOYMENT.md +10 -12
- package/skills/migrate-to-hosting/SKILL.md +3 -3
- package/skills/troubleshoot-website/SKILL.md +2 -2
- package/src/core/catalog.js +4 -0
- package/src/core/catalog.ts +6 -1
- package/src/core/instructions.agency-hosting.js +2 -0
- package/src/core/instructions.agency-hosting.ts +3 -0
- package/src/core/instructions.js +1 -1
- package/src/core/instructions.ts +1 -1
- package/src/core/runtime.js +1925 -1228
- package/src/core/runtime.ts +1891 -1193
- package/src/core/skills.js +18 -18
- package/src/core/skills.ts +18 -18
- package/src/core/tools/agency-hosting.ts +2 -0
- package/src/core/tools/agent-readiness.ts +2 -0
- package/src/core/tools/all.js +223 -30
- package/src/core/tools/all.ts +225 -30
- package/src/core/tools/billing.ts +2 -0
- package/src/core/tools/dns.ts +2 -0
- package/src/core/tools/domains.ts +2 -0
- package/src/core/tools/ecommerce.ts +2 -0
- package/src/core/tools/horizons.ts +2 -0
- package/src/core/tools/hosting.js +207 -25
- package/src/core/tools/hosting.ts +209 -25
- package/src/core/tools/mail.ts +2 -0
- package/src/core/tools/reach.ts +2 -0
- package/src/core/tools/vps.ts +2 -0
- package/src/core/tools/wordpress.js +10 -2
- package/src/core/tools/wordpress.ts +12 -2
- package/src/servers/agency-hosting.js +2 -2
- package/src/servers/agency-hosting.ts +2 -2
- package/src/servers/agent-readiness.js +1 -1
- package/src/servers/agent-readiness.ts +1 -1
- package/src/servers/all.js +1 -1
- package/src/servers/all.ts +1 -1
- package/src/servers/billing.js +1 -1
- package/src/servers/billing.ts +1 -1
- package/src/servers/dns.js +1 -1
- package/src/servers/dns.ts +1 -1
- package/src/servers/domains.js +1 -1
- package/src/servers/domains.ts +1 -1
- package/src/servers/ecommerce.js +1 -1
- package/src/servers/ecommerce.ts +1 -1
- package/src/servers/horizons.js +1 -1
- package/src/servers/horizons.ts +1 -1
- package/src/servers/hosting.js +1 -1
- package/src/servers/hosting.ts +1 -1
- package/src/servers/mail.js +1 -1
- package/src/servers/mail.ts +1 -1
- package/src/servers/reach.js +1 -1
- package/src/servers/reach.ts +1 -1
- package/src/servers/vps.js +1 -1
- package/src/servers/vps.ts +1 -1
- package/src/servers/wordpress.js +1 -1
- package/src/servers/wordpress.ts +1 -1
- package/types.d.ts +131 -22
package/src/core/skills.js
CHANGED
|
@@ -9,10 +9,10 @@ export default [
|
|
|
9
9
|
"resources": [
|
|
10
10
|
{
|
|
11
11
|
"uri": "skill://audit-hosting/SKILL.md",
|
|
12
|
-
"digest": "sha256:
|
|
13
|
-
"size":
|
|
12
|
+
"digest": "sha256:7220be5f12f2df2fbe3de85a6fa33fb19086b3878244e978b6be62f3b45803f3",
|
|
13
|
+
"size": 5546,
|
|
14
14
|
"mimeType": "text/markdown",
|
|
15
|
-
"text": "---\nname: audit-hosting\ndescription: \"Audit a Hostinger web hosting account (Shared, Cloud and Agency plans) and report what needs attention: every plan and website, SSL problems, broken or vulnerable WordPress installs, failed Node.js builds and vulnerable npm packages, databases and Agency Plan orders near their limits, and hosting plans about to lapse. Read-only; produces a prioritised to-do list and names the skill that fixes each item. Triggers: what do I have on Hostinger, audit my hosting, check all my websites, what needs attention, health check my sites, are any of my sites broken, which of my sites are insecure.\"\n---\n\n# Audit hosting\n\nRead-only from start to finish. The output is a report; every fix is a separate, confirmed step through another skill.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute`, up to 20 steps a batch. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting` and `billing` as separate servers. When a product group is switched off, skip its checks and say which were skipped.\n- Page every list until `meta.total` is covered.\n- Leave `hosting_php_get` out — it is large and says nothing about account health.\n\n## 1. Inventory\n\nOne batch per server:\n\n- `hosting_orders_list` with `statuses: [\"active\", \"suspended\"]`. `cloud_*` plan names are Cloud; the rest (`hostinger_premium_*`, `hostinger_business_*`, …) are Shared.\n- `hosting_websites_list` — every Shared and Cloud website with `website_type`, `username`, `order_id` and `is_enabled` (false means suspended).\n- `wordpress_installations_list` with `ownership: \"all\"` — `id`, `is_valid`, `validation_error`.\n- `agency-hosting_orders_list` and `agency-hosting_websites_list-plan` — Agency orders and sites (`details.uid`, `details.type`, `details.domains`, `details.state`).\n\nTell the user the size (plans, websites, WordPress installs) before the checks. For large accounts offer to scope the audit to one order or domain.\n\n## 2. Checks\n\nPer Shared and Cloud website (skip `builder` and `horizons`):\n\n- `hosting_ssl_status` — flag `failed` (with `last_error`), `expired`, `not_installed` on a custom domain, `is_https_redirect_enabled: false`, and `expires_at` within 30 days when `is_lifetime` is false. Lifetime certificates renew on their own.\n- Node.js sites: `hosting_nodejs_list-builds` with `per_page: 1`
|
|
15
|
+
"text": "---\nname: audit-hosting\ndescription: \"Audit a Hostinger web hosting account (Shared, Cloud and Agency plans) and report what needs attention: every plan and website, SSL problems, broken or vulnerable WordPress installs, failed Node.js builds and vulnerable npm packages, databases and Agency Plan orders near their limits, and hosting plans about to lapse. Read-only; produces a prioritised to-do list and names the skill that fixes each item. Triggers: what do I have on Hostinger, audit my hosting, check all my websites, what needs attention, health check my sites, are any of my sites broken, which of my sites are insecure.\"\n---\n\n# Audit hosting\n\nRead-only from start to finish. The output is a report; every fix is a separate, confirmed step through another skill.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute`, up to 20 steps a batch. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting` and `billing` as separate servers. When a product group is switched off, skip its checks and say which were skipped.\n- Page every list until `meta.total` is covered.\n- Leave `hosting_php_get` out — it is large and says nothing about account health.\n\n## 1. Inventory\n\nOne batch per server:\n\n- `hosting_orders_list` with `statuses: [\"active\", \"suspended\"]`. `cloud_*` plan names are Cloud; the rest (`hostinger_premium_*`, `hostinger_business_*`, …) are Shared.\n- `hosting_websites_list` — every Shared and Cloud website with `website_type`, `username`, `order_id` and `is_enabled` (false means suspended).\n- `wordpress_installations_list` with `ownership: \"all\"` — `id`, `is_valid`, `validation_error`.\n- `agency-hosting_orders_list` and `agency-hosting_websites_list-plan` — Agency orders and sites (`details.uid`, `details.type`, `details.domains`, `details.state`).\n\nTell the user the size (plans, websites, WordPress installs) before the checks. For large accounts offer to scope the audit to one order or domain.\n\n## 2. Checks\n\nPer Shared and Cloud website (skip `builder` and `horizons`):\n\n- `hosting_ssl_status` — flag `failed` (with `last_error`), `expired`, `not_installed` on a custom domain, `is_https_redirect_enabled: false`, and `expires_at` within 30 days when `is_lifetime` is false. Lifetime certificates renew on their own.\n- Node.js sites: `hosting_get-deployment` (latest build failed? `build.state`; on the hosted server use `hosting_nodejs_list-builds` with `per_page: 1`) and `hosting_nodejs_list-vulnerabilities` with `severities: [\"critical\", \"high\"]`.\n\nPer hosting account (`username`): `hosting_databases_list` — flag `disk_usage_mb` above 80% of `max_size_mb`.\n\nPer WordPress install: `wordpress_installations_show-core-version` (core vulnerabilities) and `wordpress_plugins_list-installed` (vulnerable plugins and pending updates).\n\nPer Agency order: `agency-hosting_metrics_list-order-resource-usage` with `time_frame_hours: 168` and `agency-hosting_metrics_list-plan-order-disk-usage` with `time_frame_days: 7` — flag usage above 80% of the plan quota and name the heaviest websites.\n\nPer Agency site: `agency-hosting_ssl_website-status` for each custom domain in `details.domains`; flag `details.state` other than `active`.\n\nPlans about to lapse (billing product): `billing_subscriptions_list`, joined to hosting orders on `subscription_id` — flag `not_renewing`, or `is_auto_renewed: false` with `expires_at` within 30 days. Every site on that plan goes down with it.\n\nFrom outside, for each custom domain:\n\n```bash\ncurl -sS -o /dev/null -w \"%{http_code}\\n\" --max-time 15 https://DOMAIN/\ncurl -sSI --max-time 15 https://DOMAIN/ | grep -i \"^platform\"\n```\n\nNo `platform: hostinger` header means the domain does not reach this hosting.\n\n## 3. Report\n\n```\n# Hosting audit\n3 plans (2 Shared, 1 Cloud) + 1 Agency · 14 websites (6 WordPress, 3 Node.js, 5 other) · 4 Agency sites\n\n## Fix now\n- shop.example.com — latest Node.js build failed 2 days ago → troubleshoot-website\n- blog.example.com — contact-form-x 5.2 has a known vulnerability, fixed in 5.3 → maintain-wordpress\n\n## Soon\n- example.org — Business plan expires in 12 days, auto-renew off → renew in hPanel\n- Agency order 1000000001 — 86% of disk quota, mostly client-a.com\n\n## Worth knowing\n- 4 WordPress installs have pending plugin updates → maintain-wordpress\n\n## Healthy\ndocs.example.com, portfolio.example.com, …\n```\n\n- **Fix now:** site down or not reaching Hostinger, failed latest build, invalid WordPress install, SSL `failed` or `expired`, critical vulnerabilities, suspended website.\n- **Soon:** high vulnerabilities, a plan lapsing within 30 days, usage above 80% of a quota, HTTPS redirect off, non-lifetime certificates expiring.\n- **Worth knowing:** pending updates, inactive plugins with vulnerabilities.\n\nEach item names the evidence and the skill that fixes it: `troubleshoot-website`, `maintain-wordpress`, `connect-domain` or `deploy-to-hosting`. Patchable npm vulnerabilities on GitHub-deployed sites can be fixed with `hosting_nodejs_patch-vulnerabilities`, which opens a pull request — offer it, do not run it as part of the audit.\n\n## Not available through the API\n\nCPU and memory usage for Shared and Cloud plans, website backup status, and PHP error logs. Mention them once at the end so the user knows what the audit could not see.\n"
|
|
16
16
|
}
|
|
17
17
|
]
|
|
18
18
|
},
|
|
@@ -41,10 +41,10 @@ export default [
|
|
|
41
41
|
"resources": [
|
|
42
42
|
{
|
|
43
43
|
"uri": "skill://deploy-to-hosting/SKILL.md",
|
|
44
|
-
"digest": "sha256:
|
|
45
|
-
"size":
|
|
44
|
+
"digest": "sha256:a493669430a2c1c20c6cd965620f89ae60dd1204f7d414574202c6d392d8bad8",
|
|
45
|
+
"size": 15008,
|
|
46
46
|
"mimeType": "text/markdown",
|
|
47
|
-
"text": "---\nname: deploy-to-hosting\ndescription: \"Deploy an existing project to a website on Hostinger web hosting (Shared, Cloud or Agency plans) and keep it deployed: picks the right deploy for static sites, Node.js apps (Next.js, Nuxt, Express, Vite and similar), PHP apps and WordPress plugins or themes, sets up auto-deploy from GitHub or GitLab, manages Node.js environment variables and MySQL databases, and verifies the live site. Triggers: deploy this project, deploy to Hostinger, push my app live, redeploy, set up auto-deploy, connect my GitHub repo, add environment variables, my app needs a database, deploy my WordPress plugin or theme.\"\n---\n\n# Deploy to hosting\n\nShip a project that already exists — on disk or in a Git repository — to a Hostinger website. Building a new site from a prompt (design, store, blog) is the `hostinger-headless` skill; this one takes code as it is.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"deploy static\").\n- Batch reads with `multi-execute`; values pass between steps as `$steps.<i>.<path>`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress` and `agency-hosting` as separate servers.\n- Every deploy overwrites the website's current contents. Confirm the target domain with the user before the first deploy to a site that already has content.\n\n## 1. Pick the target website\n\n- `.hostinger/site.json` in the project: reuse its `domain` and `username` (or `website_uid`).\n- Otherwise look the domain up with `hosting_websites_list` (Shared and Cloud; substring match — take the exact entry) and `agency-hosting_websites_list-plan` (Agency; keep `details.uid`).\n- No website yet:\n - Shared and Cloud: take a domain (the user's own, or `hosting_domains_generate-free-subdomain`) and an `order_id` from `hosting_orders_list`, then `hosting_websites_create`. `datacenter_code` is needed only for the first website on a new plan (first entry of `hosting_datacenters_list`). Poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed` — uploads and deploys return 404 or 409 before that.\n - Agency: `agency-hosting_website-setups_create` with `flavor: \"php-fpm\"` (plus `type: \"node-static\"` for built frontends), `settings.php.version` from `agency-hosting_php_list-versions-for-order` and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed`; it returns the `website_uid`.\n- Node.js apps run on Business and Cloud plans (`hostinger_business_*`, `cloud_*` in `hosting_orders_list`). On other plans, build locally and deploy the output as a static site.\n\n## 2. Choose the deploy\n\nWrong method is the most common failure. Decide from the project on disk:\n\n| Project | Shared / Cloud |\n| --- | --- |\n| Plain HTML/CSS/JS, or a framework's static build output | `hosting_deploy-static-website` |\n| `package.json` with a build or a server (Next.js, Nuxt, Express, Vite…) | `hosting_deploy-js-application` |\n| PHP code, no build step | `hosting_deploy-static-website` (extracts the archive as-is) |\n| WordPress plugin or theme folder | `hosting_deploy-wordpress-plugin` / `hosting_deploy-wordpress-theme` (`activate` optional) |\n| A whole WordPress site from elsewhere | the `migrate-to-hosting` skill |\n\nOn Agency the website's type decides (`agency-hosting_websites_get`): sites created as `node-static` take `agency-hosting_deploy-node-static-website`, which runs the build when the project has one; every other site takes `agency-hosting_deploy-php-application`, which extracts the archive as-is. WordPress plugins and themes on Agency sites are installed from wp-admin.\n\nArchive rules (name archives `name_YYYYMMDD_HHMMSS.zip`):\n\n- **Static:** build locally first. `index.html` must be at the archive root, not inside a folder: `cd dist && zip -r ../site_20260101_120000.zip .`\n- **Node.js source:** no `node_modules/`, no build output (`dist/`, `.next/`, `build/`), no `.env*`, nothing matched by `.gitignore`; 50 MB at most. `git archive --format=zip -o app_20260101_120000.zip HEAD` produces exactly the committed files — mention that uncommitted changes are left out.\n- Agency deploys are synchronous: the site is live when the call returns.\n\nThe operations in the table read the archive from this machine, so only the local `hostinger-api-mcp` server has them. On the hosted server (`mcp.hostinger.com`) `search` does not find them — upload the files yourself as below.\n\n### Without the local deploy operations\n\n1. Get upload credentials: `hosting_files_generate-upload-url` (`username`, `domain`); Agency: `agency-hosting_files_generate-upload-url` (`website_uid`). Both return `url`, `auth_key` and `rest_auth_key`, which authenticate the upload instead of the API token.\n2. Upload each file with TUS, where `DEST` is its path in the website's storage:\n\n```bash\nSIZE=$(wc -c < \"$FILE\" | tr -d ' ')\ncurl -sS -X POST \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Upload-Length: $SIZE\" -H \"Upload-Offset: 0\"\ncurl -sS -X PATCH \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Content-Type: application/offset+octet-stream\" -H \"Upload-Offset: 0\" --data-binary \"@$FILE\"\n```\n\n The first call returns `201`, the second `204` with an `Upload-Offset` header equal to the file size. `override=true` makes a retry safe.\n3. Deploy from the uploaded files (`RANDOM8` is any fresh 8-character string, e.g. `$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8)`):\n\n| Project | `DEST` | Then |\n| --- | --- | --- |\n| Static or PHP | `site.zip` | `hosting_websites_deploy-static-site-archive` with `archive_path: \"site.zip\"` |\n| Node.js | `app.zip` | `hosting_nodejs_build-settings-from-archive` with `archive_path: \"app.zip\"`, then `hosting_nodejs_start-build` with those settings, `source_type: \"archive\"` and `source_options.archive_path: \"app.zip\"` |\n| WordPress plugin | every file, as `wp-content/plugins/SLUG-RANDOM8/<path in the plugin>` | `wordpress_plugins_deploy` with `slug` and `plugin_path: \"SLUG-RANDOM8\"` |\n| WordPress theme | every file, as `wp-content/themes/SLUG-RANDOM8/<path in the theme>` | `wordpress_themes_deploy` with `slug`, `theme_path: \"SLUG-RANDOM8\"` and optional `is_activated` |\n| Agency, extracted as-is | `.h5g/site.zip` | `agency-hosting_files_import-website-from-archive` with `archive_name: \"site.zip\"` |\n| Agency `node-static` | `.h5g/RANDOM8/app.zip` | `agency-hosting_websites_build-nodejs-assets` with `archive_path: \".h5g/RANDOM8\"` — the directory, not the file |\n\n## 3. Node.js builds\n\n`hosting_deploy-js-application` uploads the archive to the document root, detects settings from `package.json` and starts a build. Track it with `hosting_nodejs_list-builds` and `hosting_nodejs_build` (by `uuid`), polling every 10–20 s — builds take minutes.\n\n- Failed build: `hosting_nodejs_analyse-failed-build` once per build (5 calls a minute), then `hosting_nodejs_build-logs` if the analysis is empty.\n- Wrong detection (framework, `output_directory`, or a missing `entry_file` for express, fastify, nest, nuxt and hono): run `hosting_nodejs_start-build` with explicit values, `source_type: \"archive\"` and `source_options.archive_path` set to the archive's file name in the document root (check it is there with `hosting_files_list-website-and-directories`). Store the same values with `hosting_nodejs_update-build-settings`.\n- To review detected settings before any build: upload the archive with `hosting_files_generate-upload-url` (the TUS steps are in its description), then `hosting_nodejs_build-settings-from-archive`.\n\n## 4. Auto-deploy from Git\n\n1. `hosting_git_list-installations`. With no `active` installation (check `status: \"pending\"` and `\"suspended\"` too), the user connects GitHub or GitLab once in hPanel under Websites → Manage → Advanced → Git; there is no API for that step.\n2. `hosting_git_list-installation-repositories` with the installation `uuid` gives `owner`, `name` and `default_branch` (10 calls a minute).\n3. `hosting_git_update-auto-deployment-settings` with `installation_uuid`, `owner`, `repository`, `branch` and optional `directory`.\n - PHP and static sites deploy the branch immediately and again on every push.\n - Node.js sites clone nothing on save: start the first build with `hosting_nodejs_start-build`, `source_type: \"git\"` and the same `source_options`. Later pushes build with the stored settings, so keep `hosting_nodejs_update-build-settings` correct.\n4. Confirm with `hosting_git_auto-deployment-settings`.\n\nAgency Plan sites have no Git operations; deploy archives.\n\n## 5. Environment variables (Node.js)\n\n`hosting_nodejs_replace-environment-variables` replaces the whole set — anything not sent is deleted.\n\n1. `hosting_nodejs_list-environment-variables` for the current keys. Values come back as `********`; never send those back.\n2. Build the full set: every current key plus the new ones, with real values from the project's `.env` or the user. When the real value of an existing key is unknown, ask — do not drop it.\n3. Send it once; the app restarts. Values baked in at build time (Next.js `NEXT_PUBLIC_*`, Vite `VITE_*`) need a new `hosting_nodejs_start-build`.\n\nKeys use uppercase letters, digits and underscores. Never commit `.env` files or repeat secret values back to the user.\n\n## 6. Database\n\n- **Node.js:** `hosting_databases_setup-website` creates a MySQL database and writes `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` and `DATABASE_URL` into the environment, then restarts the app. The password is generated and never returned. It fails with 422 when any of those keys exists — remove them first with the step 5 replace.\n- **PHP:** `hosting_databases_create` with `name`, `user`, a strong generated `password` and `website_domain`; read the prefixed full name back from `hosting_databases_list`. The app reads credentials from a config file on the server that stays out of Git, and connects to `localhost` or `127.0.0.1`.\n- **Agency:** `agency-hosting_databases_create-website`; the app connects to `localhost`.\n- The `srvNNNN.hstgr.io` host from `hosting_databases_list` is only for connections from outside Hostinger — never put it in the deployed app.\n\n## 7. Verify and record\n\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/\ncurl -s https://DOMAIN/ | grep -o \"TEXT THE PROJECT RENDERS\"\n```\n\nA `200` alone can be a placeholder page; match real copy. A new site may serve a default page briefly — clear it with `hosting_cache_clear-website` and retry before calling the deploy failed.\n\nWrite `.hostinger/site.json` in the project so later runs reuse the target: `{ \"domain\", \"username\" or \"website_uid\", \"type\": \"static\" | \"nodejs\" | \"php\" }`, keeping any fields already there.\n"
|
|
47
|
+
"text": "---\nname: deploy-to-hosting\ndescription: \"Deploy an existing project to a website on Hostinger web hosting (Shared, Cloud or Agency plans) and keep it deployed: picks the right deploy for static sites, Node.js apps (Next.js, Nuxt, Express, Vite and similar), PHP apps and WordPress plugins or themes, sets up auto-deploy from GitHub or GitLab, manages Node.js environment variables and MySQL databases, and verifies the live site. Triggers: deploy this project, deploy to Hostinger, push my app live, redeploy, set up auto-deploy, connect my GitHub repo, add environment variables, my app needs a database, deploy my WordPress plugin or theme.\"\n---\n\n# Deploy to hosting\n\nShip a project that already exists — on disk or in a Git repository — to a Hostinger website. Building a new site from a prompt (design, store, blog) is the `hostinger-headless` skill; this one takes code as it is.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"deploy static\").\n- Batch reads with `multi-execute`; values pass between steps as `$steps.<i>.<path>`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress` and `agency-hosting` as separate servers.\n- Every deploy overwrites the website's current contents. Confirm the target domain with the user before the first deploy to a site that already has content.\n\n## 1. Pick the target website\n\n- `.hostinger/site.json` in the project: reuse its `domain` and `username` (or `website_uid`).\n- Otherwise look the domain up with `hosting_websites_list` (Shared and Cloud; substring match — take the exact entry) and `agency-hosting_websites_list-plan` (Agency; keep `details.uid`).\n- No website yet:\n - Shared and Cloud: take a domain (the user's own, or `hosting_domains_generate-free-subdomain`) and an `order_id` from `hosting_orders_list`, then `hosting_websites_create`. `datacenter_code` is needed only for the first website on a new plan (first entry of `hosting_datacenters_list`). Poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed` — uploads and deploys return 404 or 409 before that.\n - Agency: `agency-hosting_website-setups_create` with `flavor: \"php-fpm\"` (plus `type: \"node-static\"` for built frontends), `settings.php.version` from `agency-hosting_php_list-versions-for-order` and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed`; it returns the `website_uid`.\n- Node.js apps run on Business and Cloud plans (`hostinger_business_*`, `cloud_*` in `hosting_orders_list`). On other plans, build locally and deploy the output as a static site.\n\n## 2. Choose the deploy\n\n**Shared and Cloud, on the local `hostinger-api-mcp` server:** one operation does every deploy — `hosting_deploy` with `domain` and either `path` (a directory on this machine) or `git: { repository: \"owner/name\", branch }`. Given a directory it detects what the project is, packs it itself (it skips `node_modules`, `.git` and `.env` files, listing the `.env` ones as `skippedFiles` so you can set their values with `hosting_nodejs_replace-environment-variables`; it does not read `.gitignore`, so keep build output out of the directory) and does the upload, build and Git setup. Do not archive the directory or call upload and build operations by hand.\n\n| Project | `hosting_deploy` treats it as |\n| --- | --- |\n| Plain HTML/CSS/JS, or a framework's static build output | `static` — extracts as-is |\n| `package.json` with a build script, a start script or a server dependency (Next.js, Nuxt, Express, Vite…) | `nodejs` — starts a build, returns `buildUuid` |\n| PHP code, no build step | `static` |\n| WordPress plugin folder (a `Plugin Name:` header) or theme folder (`Theme Name:` in `style.css`) | `wordpress-plugin` / `wordpress-theme`; `activate: true` activates a theme |\n| A whole WordPress site from elsewhere | `wordpress-site`, with `databaseDump` — see the `migrate-to-hosting` skill |\n\n- Pass `type` to override detection. It is required for an archive (an archive cannot be inspected) and when a directory matches more than one WordPress type, which `hosting_deploy` rejects as ambiguous.\n- Node.js build settings come from the project; detection covers the framework and the build script. Set `appType`, `outputDirectory`, `buildScript`, `entryFile`, `nodeVersion` (default 22), `rootDirectory` or `packageManager` when it is wrong. A TypeScript or other compiled server app always needs `entryFile` set to the built file (for example `dist/server.js`): detection only guesses a root-level file, and the build fails with \"Entry file not found\". The entry file is relative to the root directory for express, fastify, hono, react-router and other, and to the output directory for nest, nuxt, nitro, astro and svelte-kit (`main.js`, not `dist/main.js`); Next.js ignores it. Per-framework values are in the Hostinger docs under Node.js (Supported Frameworks, Build Settings).\n- Static, PHP, plugin and theme deploys are live when the call returns. A WordPress site import only starts (`status: import_started`) and finishes extracting a few minutes later; do not report it complete or verify it before then. Node.js builds run on the server: see step 3.\n\n**Agency:** the website's type decides (`agency-hosting_websites_get`): sites created as `node-static` take `agency-hosting_deploy-node-static-website`, which runs the build when the project has one; every other site takes `agency-hosting_deploy-php-application`, which extracts the archive as-is. They deploy archives, synchronously: the site is live when the call returns. WordPress plugins and themes on Agency sites are installed from wp-admin.\n\nArchive rules for Agency (name archives `name_YYYYMMDD_HHMMSS.zip`) and for archives you build yourself:\n\n- **Static:** build locally first. `index.html` must be at the archive root, not inside a folder: `cd dist && zip -r ../site_20260101_120000.zip .`\n- **Node.js source:** no `node_modules/`, no build output (`dist/`, `.next/`, `build/`), no `.env*`, nothing matched by `.gitignore`; 50 MB at most. `git archive --format=zip -o app_20260101_120000.zip HEAD` produces exactly the committed files — mention that uncommitted changes are left out.\n\n`hosting_deploy` and the `agency-hosting_deploy-*` operations read files from this machine, so only the local server has them. On the hosted server (`mcp.hostinger.com`) `search` does not find them — upload the files yourself as below.\n\n### Without the local deploy operations (hosted server; on the local server only for Agency)\n\n1. Get upload credentials: `hosting_files_generate-upload-url` (`username`, `domain`); Agency: `agency-hosting_files_generate-upload-url` (`website_uid`). Both return `url`, `auth_key` and `rest_auth_key`, which authenticate the upload instead of the API token.\n2. Upload each file with TUS, where `DEST` is its path in the website's storage:\n\n```bash\nSIZE=$(wc -c < \"$FILE\" | tr -d ' ')\ncurl -sS -X POST \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Upload-Length: $SIZE\" -H \"Upload-Offset: 0\"\ncurl -sS -X PATCH \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Content-Type: application/offset+octet-stream\" -H \"Upload-Offset: 0\" --data-binary \"@$FILE\"\n```\n\n The first call returns `201`, the second `204` with an `Upload-Offset` header equal to the file size. `override=true` makes a retry safe.\n3. Deploy from the uploaded files (`RANDOM8` is any fresh 8-character string, e.g. `$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8)`):\n\n| Project | `DEST` | Then |\n| --- | --- | --- |\n| Static or PHP | `site.zip` | `hosting_websites_deploy-static-site-archive` with `archive_path: \"site.zip\"` |\n| Node.js | `app.zip` | `hosting_nodejs_build-settings-from-archive` with `archive_path: \"app.zip\"`, then `hosting_nodejs_start-build` with those settings, `source_type: \"archive\"` and `source_options.archive_path: \"app.zip\"` |\n| WordPress plugin | every file, as `wp-content/plugins/SLUG-RANDOM8/<path in the plugin>` | `wordpress_plugins_deploy` with `slug` and `plugin_path: \"SLUG-RANDOM8\"` |\n| WordPress theme | every file, as `wp-content/themes/SLUG-RANDOM8/<path in the theme>` | `wordpress_themes_deploy` with `slug`, `theme_path: \"SLUG-RANDOM8\"` and optional `is_activated` |\n| Agency, extracted as-is | `.h5g/site.zip` | `agency-hosting_files_import-website-from-archive` with `archive_name: \"site.zip\"` |\n| Agency `node-static` | `.h5g/RANDOM8/app.zip` | `agency-hosting_websites_build-nodejs-assets` with `archive_path: \".h5g/RANDOM8\"` — the directory, not the file |\n\n## 3. Node.js builds\n\n`hosting_deploy` returns a `buildUuid` at once; the build runs on the server and takes minutes. Track it with `hosting_get-deployment` (`domain`, optionally `buildUuid`; the latest build by default), polling every 10–20 s until `build.state` is `completed` or `failed`. It returns the build, its log and the stored build settings; pass the previous `logs.lines` as `fromLine` to read only new output.\n\n- Failed build: the response already carries `analysis` (fetched once per build; the API allows 5 a minute).\n- Wrong detection (framework, `output_directory`, or an entry file inside the build output, such as `dist/server.js` for a compiled app): deploy again with `appType`, `outputDirectory`, `buildScript` or `entryFile` set. An archive deploy sends its settings with the request and leaves the stored ones alone; a Git deploy also stores these values, so later pushes build with them.\n\nOn the hosted server, which has no `hosting_deploy` or `hosting_get-deployment`:\n\n- After the upload steps below, start the build and track it with `hosting_nodejs_list-builds` and `hosting_nodejs_build` (by `uuid`), polling every 10–20 s.\n- Failed build: `hosting_nodejs_analyse-failed-build` once per build (5 calls a minute), then `hosting_nodejs_build-logs` if the analysis is empty.\n- Wrong detection: run `hosting_nodejs_start-build` with explicit values, `source_type: \"archive\"` and `source_options.archive_path` set to the archive's file name in the document root (check it is there with `hosting_files_list-website-and-directories`). Store the same values with `hosting_nodejs_update-build-settings`.\n- To review detected settings before any build: upload the archive with `hosting_files_generate-upload-url` (the TUS steps are in its description), then `hosting_nodejs_build-settings-from-archive`.\n\n## 4. Auto-deploy from Git\n\nOn the local server, `hosting_deploy` with `git: { repository: \"owner/name\", branch }` does all of it: it finds the Git installation that can reach the repository and deploys it as the `type` you give. Always pass `type: \"static\"` or `\"nodejs\"` unless the site already runs a Node.js app (or you pass Node.js settings such as `appType`): a new site is not detected as Node.js, and a Node.js repository deployed as static would publish its source. Then:\n- **PHP and static sites:** saves the auto-deployment settings, which deploys the branch immediately and again on every push;\n- **Node.js sites:** starts a build of the branch with the stored build settings; later pushes build the same way. A Git deploy has nothing to detect from, so when none are stored pass `appType` and `nodeVersion` (from `engines` in `package.json`), plus `outputDirectory` and `buildScript` if the app has a build step; they are stored for those pushes.\n\nWith no active installation it stops and says so: the user connects GitHub or GitLab once in hPanel under Websites → Manage → Advanced → Git; there is no API for that step. Confirm with `hosting_get-deployment`, which returns the stored `gitAutoDeployment`.\n\nOn the hosted server, by hand:\n\n1. `hosting_git_list-installations`. With no `active` installation (check `status: \"pending\"` and `\"suspended\"` too), the user connects GitHub or GitLab once in hPanel, as above.\n2. `hosting_git_list-installation-repositories` with the installation `uuid` gives `owner`, `name` and `default_branch` (10 calls a minute).\n3. `hosting_git_update-auto-deployment-settings` with `installation_uuid`, `owner`, `repository`, `branch` and optional `directory`.\n - PHP and static sites deploy the branch immediately and again on every push.\n - Node.js sites clone nothing on save: start the first build with `hosting_nodejs_start-build`, `source_type: \"git\"` and the same `source_options`. Later pushes build with the stored settings, so keep `hosting_nodejs_update-build-settings` correct.\n4. Confirm with `hosting_git_auto-deployment-settings`.\n\nAgency Plan sites have no Git operations; deploy archives.\n\n## 5. Environment variables (Node.js)\n\n`hosting_nodejs_replace-environment-variables` replaces the whole set — anything not sent is deleted.\n\n1. `hosting_nodejs_list-environment-variables` for the current keys. Values come back as `********`; never send those back.\n2. Build the full set: every current key plus the new ones, with real values from the project's `.env` or the user. When the real value of an existing key is unknown, ask — do not drop it.\n3. Send it once; the app restarts. Values baked in at build time (Next.js `NEXT_PUBLIC_*`, Vite `VITE_*`) need a new `hosting_nodejs_start-build`.\n\nKeys use uppercase letters, digits and underscores. Never commit `.env` files or repeat secret values back to the user.\n\n## 6. Database\n\n- **Node.js:** `hosting_databases_setup-website` creates a MySQL database and writes `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` and `DATABASE_URL` into the environment, then restarts the app. The password is generated and never returned. It fails with 422 when any of those keys exists — remove them first with the step 5 replace.\n- **PHP:** `hosting_databases_create` with `name`, `user`, a strong generated `password` and `website_domain`; read the prefixed full name back from `hosting_databases_list`. The app reads credentials from a config file on the server that stays out of Git, and connects to `localhost` or `127.0.0.1`.\n- **Agency:** `agency-hosting_databases_create-website`; the app connects to `localhost`.\n- The `srvNNNN.hstgr.io` host from `hosting_databases_list` is only for connections from outside Hostinger — never put it in the deployed app.\n\n## 7. Verify and record\n\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/\ncurl -s https://DOMAIN/ | grep -o \"TEXT THE PROJECT RENDERS\"\n```\n\nA `200` alone can be a placeholder page; match real copy. A new site may serve a default page briefly — clear it with `hosting_cache_clear-website` and retry before calling the deploy failed.\n\nWrite `.hostinger/site.json` in the project so later runs reuse the target: `{ \"domain\", \"username\" or \"website_uid\", \"type\": \"static\" | \"nodejs\" | \"php\" }`, keeping any fields already there.\n"
|
|
48
48
|
}
|
|
49
49
|
]
|
|
50
50
|
},
|
|
@@ -64,17 +64,17 @@ export default [
|
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"uri": "skill://hostinger-headless/references/DATABASE.md",
|
|
67
|
-
"digest": "sha256:
|
|
68
|
-
"size":
|
|
67
|
+
"digest": "sha256:b0d2d0a893d2f483e9bd961839397fe6dd6011c1b7149bed747bef8ae703b65a",
|
|
68
|
+
"size": 4476,
|
|
69
69
|
"mimeType": "text/markdown",
|
|
70
|
-
"text": "# Database and runtime — MySQL hosts, env vars, and what to poll\n\nUse this when the app needs MySQL, or when a deploy \"succeeded\" but the app cannot reach its database. Everything here uses the **hosting** MCP operations; Agency Plan differences are at the end.\n\n## 1. Create the database\n\n1. `hosting_databases_create` on the site's `username` with a database name, a user and a password you generate — name and user are prefixed with the account username automatically.\n2. Read the full, prefixed `name` and `user` back from `hosting_databases_list`; every other database operation wants the full name.\n3. Do not print the password to the user once it is stored, and never commit it.\n\n## 2. Which host the app connects to\n\n| Where the code runs | Host | Port | Why |\n| --- | --- | --- | --- |\n| PHP on the website | `localhost` or `127.0.0.1` | 3306 | `localhost` uses the MySQL socket; both are granted |\n| Node.js on the website | `127.0.0.1` | 3306 | `localhost` may resolve to IPv6 `::1`, and not every database user has that grant |\n| Outside Hostinger (a laptop, another server) | the `host` from `hosting_databases_list` (`srvNNNN.hstgr.io`) | 3306 | needs `hosting_databases_create-remote-connection` for that client's IP first — never `%`, it opens the database to every address on the internet |\n\nDo not put the remote `host` into the deployed app — it has no grant for connections that come from the server itself.\n\n## 3. Hand credentials to the app\n\n- **Node.js:** environment variables via `hosting_nodejs_replace-environment-variables`. Conventional keys: `DB_HOST=127.0.0.1`, `DB_PORT=3306`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, plus `DATABASE_URL=mysql://USER:PASSWORD@127.0.0.1:3306/NAME` for ORMs that want one string — URL-encode `USER` and `PASSWORD` there (`encodeURIComponent`), or a password containing `@`, `:`, `/` or `#` breaks the URL. The call is a **full replace**: list the current keys with `hosting_nodejs_list-environment-variables` (values come back masked as `********` — never copy those), then send the complete set with real values. Saving restarts the process; frameworks that bake variables into the build (Next.js, `NEXT_PUBLIC_*`) need a new `hosting_nodejs_start-build` afterwards.\n- **PHP:** a config file on the server that the app reads (its own `config.php`, WordPress's `wp-config.php`). Ship it with the deploy, keep it out of git.\n- **Never** in client-side JavaScript, in a committed `.env`, or in chat replies.\n\n## 4. What is asynchronous, and what to poll\n\n| You called | Poll this until | Typical wait |\n| --- | --- | --- |\n| `hosting_websites_create` | `hosting_websites_list-setups` with the domain reports `status: completed` | up to a few minutes |\n| `hosting_deploy
|
|
70
|
+
"text": "# Database and runtime — MySQL hosts, env vars, and what to poll\n\nUse this when the app needs MySQL, or when a deploy \"succeeded\" but the app cannot reach its database. Everything here uses the **hosting** MCP operations; Agency Plan differences are at the end.\n\n## 1. Create the database\n\n1. `hosting_databases_create` on the site's `username` with a database name, a user and a password you generate — name and user are prefixed with the account username automatically.\n2. Read the full, prefixed `name` and `user` back from `hosting_databases_list`; every other database operation wants the full name.\n3. Do not print the password to the user once it is stored, and never commit it.\n\n## 2. Which host the app connects to\n\n| Where the code runs | Host | Port | Why |\n| --- | --- | --- | --- |\n| PHP on the website | `localhost` or `127.0.0.1` | 3306 | `localhost` uses the MySQL socket; both are granted |\n| Node.js on the website | `127.0.0.1` | 3306 | `localhost` may resolve to IPv6 `::1`, and not every database user has that grant |\n| Outside Hostinger (a laptop, another server) | the `host` from `hosting_databases_list` (`srvNNNN.hstgr.io`) | 3306 | needs `hosting_databases_create-remote-connection` for that client's IP first — never `%`, it opens the database to every address on the internet |\n\nDo not put the remote `host` into the deployed app — it has no grant for connections that come from the server itself.\n\n## 3. Hand credentials to the app\n\n- **Node.js:** environment variables via `hosting_nodejs_replace-environment-variables`. Conventional keys: `DB_HOST=127.0.0.1`, `DB_PORT=3306`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, plus `DATABASE_URL=mysql://USER:PASSWORD@127.0.0.1:3306/NAME` for ORMs that want one string — URL-encode `USER` and `PASSWORD` there (`encodeURIComponent`), or a password containing `@`, `:`, `/` or `#` breaks the URL. The call is a **full replace**: list the current keys with `hosting_nodejs_list-environment-variables` (values come back masked as `********` — never copy those), then send the complete set with real values. Saving restarts the process; frameworks that bake variables into the build (Next.js, `NEXT_PUBLIC_*`) need a new `hosting_nodejs_start-build` afterwards.\n- **PHP:** a config file on the server that the app reads (its own `config.php`, WordPress's `wp-config.php`). Ship it with the deploy, keep it out of git.\n- **Never** in client-side JavaScript, in a committed `.env`, or in chat replies.\n\n## 4. What is asynchronous, and what to poll\n\n| You called | Poll this until | Typical wait |\n| --- | --- | --- |\n| `hosting_websites_create` | `hosting_websites_list-setups` with the domain reports `status: completed` | up to a few minutes |\n| `hosting_deploy` of a Node.js app | `hosting_get-deployment` reports a `completed` or `failed` build | minutes |\n| `hosting_nodejs_start-build` (hosted server, which has no `hosting_deploy`) | `hosting_nodejs_build` state is `completed` or `failed` | minutes |\n| `wordpress_installations_install`, plugin/theme/core jobs | `wordpress_installations_list` lists the install | 1–2 minutes |\n| `hosting_databases_repair`, `hosting_websites_delete` | nothing to poll — runs in the background | minutes |\n| `agency-hosting_website-setups_create` | `agency-hosting_website-setups_status` with `setup_uuid` is `completed` | minutes |\n\nPoll with backoff (a few seconds, then tens of seconds). A queued response is not a failure, and re-sending the write does not speed it up.\n\n## 5. When the app is up but broken\n\n- Build failed: `hosting_get-deployment` returns the logs and a diagnosis together (hosted server: `hosting_nodejs_build-logs` for the raw log, `hosting_nodejs_analyse-failed-build` for a diagnosis).\n- Build passed, app errors: `hosting_nodejs_runtime-logs` with a `period` such as `1h`; entries before `last_deployed_at` belong to the previous deploy.\n- `Access denied for user 'x'@'::1'`: the app used `localhost` from Node.js — set `DB_HOST` to `127.0.0.1`.\n- PHP limits (memory, upload size): `hosting_php_get`, then `hosting_php_update-options`.\n\n## Agency Plan websites (`agency-hosting_*`)\n\n`agency-hosting_databases_create-website` creates the database and its single user; the user is granted on `localhost`, so the PHP app connects to `localhost`. Deploys are synchronous there — `agency-hosting_deploy-php-application` returns when the site is live. Other jobs (SSL, backups) show up in `agency-hosting_websites_list-processes`.\n"
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"uri": "skill://hostinger-headless/references/DEPLOYMENT.md",
|
|
74
|
-
"digest": "sha256:
|
|
75
|
-
"size":
|
|
74
|
+
"digest": "sha256:65a47de1a56ed42d1821169330237b9d715505adfb7bf312342918181d889a9f",
|
|
75
|
+
"size": 3384,
|
|
76
76
|
"mimeType": "text/markdown",
|
|
77
|
-
"text": "# Deployment — getting the build live\n\nMatch the deploy method to what the project actually is — this is the single most common failure point.\n\
|
|
77
|
+
"text": "# Deployment — getting the build live\n\nMatch the deploy method to what the project actually is — this is the single most common failure point.\n\nOn the local `hostinger-api-mcp` server one operation does every deploy: `hosting_deploy` with `domain` and `path` (the project directory; it detects the type, packs the files itself; it skips `node_modules`, `.git` and `.env` files, reporting the `.env` ones as `skippedFiles` (set their values with `hosting_nodejs_replace-environment-variables`); it does not read `.gitignore`, so keep build output out of the directory) or `git: { repository, branch }` with `type: \"static\"` or `\"nodejs\"` (a new site is not yet detected as Node.js). It reads files from this machine, so the hosted server (`mcp.hostinger.com`) does not have it: there, upload the files and deploy from the upload as described in the `deploy-to-hosting` skill (\"Without the local deploy operations\"). Agency Plan sites deploy through the Agency operations listed there as well.\n\n## Static site → `hosting_deploy` (detected as `static`)\n\nFor pre-built files only: plain HTML/CSS/JS, or the **build output** of a framework (run the build locally first, then pass the output directory as `path`).\n\n- `index.html` must be at the **root** of that directory — not nested inside a folder.\n- Deployment is effectively immediate — verify right after.\n\n## Node.js app → `hosting_deploy` (detected as `nodejs`)\n\nFor anything that needs a server or a server-side build (Express, Next.js, NestJS, SSR frameworks). Pass the project's **source** directory, not the output: the install and build run on Hostinger.\n\n- The call returns a `buildUuid` and the build runs on the server. Track it with `hosting_get-deployment` (`domain`) until `build.state` is `completed` or `failed`; on failure the response carries the logs and an analysis — fix, and deploy again. Poll with backoff: builds take minutes, not seconds.\n- When the framework, output directory or entry file is detected wrong, pass `appType`, `outputDirectory`, `buildScript` or `entryFile` to `hosting_deploy`. A TypeScript or other compiled server app always needs `entryFile` set to the built file (for example `dist/server.js`).\n\n## WordPress → `hosting_deploy` with `type: \"wordpress-site\"` / plugin & theme directories\n\nOnly when the user explicitly wants a WordPress *site* migrated or themed. A site import takes the site directory plus `databaseDump` (a `.sql` file) and can run for several minutes; a plugin or theme directory is detected from its header (`activate: true` activates a theme). (WordPress as a headless content backend behind an agent-built frontend is a different flow — that's `WORDPRESS.md`, installed fresh via the API, not imported here.)\n\n## Verify (every deploy)\n\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" https://YOURDOMAIN/\ncurl -s https://YOURDOMAIN/ | grep -o \"SOME_REAL_HEADLINE_TEXT\"\n```\n\nReplace the grep target with copy you actually rendered — a 200 alone can be a placeholder page. A freshly created site may serve a default page for a short while; if content doesn't match, clear the cache (`hosting_cache_clear-website`) and retry before assuming the deploy failed. For store runs, also run the checkout verification in `STORE.md`.\n\nWhen the site is live, report the URL and remind the user the site is managed from hPanel (https://hpanel.hostinger.com).\n"
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"uri": "skill://hostinger-headless/references/SETUP.md",
|
|
@@ -124,10 +124,10 @@ export default [
|
|
|
124
124
|
"resources": [
|
|
125
125
|
{
|
|
126
126
|
"uri": "skill://migrate-to-hosting/SKILL.md",
|
|
127
|
-
"digest": "sha256:
|
|
128
|
-
"size":
|
|
127
|
+
"digest": "sha256:b0074ad1de43e13d30306d67952000cd518b704e0c8e2be0384b9f4b15fbf485",
|
|
128
|
+
"size": 7399,
|
|
129
129
|
"mimeType": "text/markdown",
|
|
130
|
-
"text": "---\nname: migrate-to-hosting\ndescription: \"Move an existing website from another host to Hostinger web hosting (Shared, Cloud or Agency plans) without downtime: WordPress sites from a files archive and SQL dump, static and PHP sites from an archive, Node.js apps from source. Creates the website on the real domain, imports files and database, tests the copy before any DNS change, then switches the domain and SSL. Triggers: migrate my site to Hostinger, move my website from another host, transfer my WordPress site, import my website, switch hosting to Hostinger.\"\n---\n\n# Migrate to hosting\n\nThe old host keeps serving the site until the copy on Hostinger is proven to work. DNS moves last.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"import wordpress\").\n- Batch reads with `multi-execute`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting`, `domains` and `dns` as separate servers.\n- Imports and deploys overwrite the target website's contents; confirm the target before each one.\n\n## 1. What is being moved\n\nEstablish, asking only for what cannot be inferred:\n\n- **Site type:** WordPress, static, PHP (with or without MySQL), or Node.js.\n- **The export:**\n - WordPress — an archive of the whole WordPress root (including `wp-content` and `wp-config.php`) and a `.sql` dump.\n - PHP — a files archive, plus a `.sql` dump when the app has a database.\n - Static — the files. Node.js — the source or its Git repository.\n - Without one, the user exports it from the old host's panel, or over SSH: `tar -czf site.tar.gz -C /path/to/site .` and `mysqldump --single-transaction -u USER -p DBNAME > db.sql`.\n- **The exact home URL** (`https`, with or without `www`) — WordPress keeps it in the database, so the new site must answer on the same one.\n- **Current DNS**, to preserve what already works:\n\n```bash\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short MX DOMAIN; dig +short TXT DOMAIN\n```\n\n- **Cron jobs** on the old host — they do not move with the files.\n\n## 2. Create the website on the real domain\n\nCreate the Hostinger website on the domain being migrated, not on a free subdomain: step 4 tests it by pointing only this machine at Hostinger, so nothing changes for visitors yet.\n\n- Shared and Cloud: `hosting_domains_verify-ownership` first. When `is_accessible` is false, the user adds the returned `TXT` record at their current DNS provider, next to the existing ones, and verification is repeated. Then `hosting_websites_create` with `domain` and `order_id` (from `hosting_orders_list`), and poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed`.\n- Agency: `agency-hosting_website-setups_create` with the `domain`, `flavor: \"php-fpm\"`, a `settings.php.version` matching the old host (options in `agency-hosting_php_list-versions-for-order`) and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed` for the `website_uid`.\n\n## 3. Import\n\n`
|
|
130
|
+
"text": "---\nname: migrate-to-hosting\ndescription: \"Move an existing website from another host to Hostinger web hosting (Shared, Cloud or Agency plans) without downtime: WordPress sites from a files archive and SQL dump, static and PHP sites from an archive, Node.js apps from source. Creates the website on the real domain, imports files and database, tests the copy before any DNS change, then switches the domain and SSL. Triggers: migrate my site to Hostinger, move my website from another host, transfer my WordPress site, import my website, switch hosting to Hostinger.\"\n---\n\n# Migrate to hosting\n\nThe old host keeps serving the site until the copy on Hostinger is proven to work. DNS moves last.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"import wordpress\").\n- Batch reads with `multi-execute`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting`, `domains` and `dns` as separate servers.\n- Imports and deploys overwrite the target website's contents; confirm the target before each one.\n\n## 1. What is being moved\n\nEstablish, asking only for what cannot be inferred:\n\n- **Site type:** WordPress, static, PHP (with or without MySQL), or Node.js.\n- **The export:**\n - WordPress — an archive of the whole WordPress root (including `wp-content` and `wp-config.php`) and a `.sql` dump.\n - PHP — a files archive, plus a `.sql` dump when the app has a database.\n - Static — the files. Node.js — the source or its Git repository.\n - Without one, the user exports it from the old host's panel, or over SSH: `tar -czf site.tar.gz -C /path/to/site .` and `mysqldump --single-transaction -u USER -p DBNAME > db.sql`.\n- **The exact home URL** (`https`, with or without `www`) — WordPress keeps it in the database, so the new site must answer on the same one.\n- **Current DNS**, to preserve what already works:\n\n```bash\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short MX DOMAIN; dig +short TXT DOMAIN\n```\n\n- **Cron jobs** on the old host — they do not move with the files.\n\n## 2. Create the website on the real domain\n\nCreate the Hostinger website on the domain being migrated, not on a free subdomain: step 4 tests it by pointing only this machine at Hostinger, so nothing changes for visitors yet.\n\n- Shared and Cloud: `hosting_domains_verify-ownership` first. When `is_accessible` is false, the user adds the returned `TXT` record at their current DNS provider, next to the existing ones, and verification is repeated. Then `hosting_websites_create` with `domain` and `order_id` (from `hosting_orders_list`), and poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed`.\n- Agency: `agency-hosting_website-setups_create` with the `domain`, `flavor: \"php-fpm\"`, a `settings.php.version` matching the old host (options in `agency-hosting_php_list-versions-for-order`) and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed` for the `website_uid`.\n\n## 3. Import\n\n`hosting_deploy` and `agency-hosting_deploy-php-application` read files from this machine and exist only in the local `hostinger-api-mcp` server. On the hosted server (`mcp.hostinger.com`), upload the files first as described in the `deploy-to-hosting` skill (\"Without the local deploy operations\") and use the operation named in brackets below.\n\n**WordPress, Shared and Cloud:** `hosting_deploy` with `domain`, `path` (the site directory or its archive), `databaseDump` and `type: \"wordpress-site\"` uploads both, extracts the files and imports the database; large sites take several minutes. Always pass `type`: left to detection, a directory without `wp-config.php` or `wp-content` at its top level is taken for a plain site and the dump is not imported. [Upload `site.zip` and `dump.sql`, then `wordpress_installations_import-website` with `archive_path` and `sql_path`.] Then `wordpress_installations_detect` with `username` and poll `wordpress_installations_list` with `domain` until the install appears with `is_valid: true`.\n\n**Static, or PHP without a database:** `hosting_deploy` with `domain` and `path` [upload, then `hosting_websites_deploy-static-site-archive`]; Agency: `agency-hosting_deploy-php-application` [upload to `.h5g/`, then `agency-hosting_files_import-website-from-archive`].\n\n**PHP with a database, Shared and Cloud:**\n\n1. `hosting_databases_create` with a strong generated password; read the full name, user and `host` back from `hosting_databases_list`.\n2. Import the dump from this machine: allow only its public IP (`curl -s https://api.ipify.org`) with `hosting_databases_create-remote-connection`, run `mysql -h HOST -u USER -p NAME < db.sql`, then remove the rule with `hosting_databases_delete-remote-connection`. Without a MySQL client, use `hosting_databases_phpmyadmin-link` and import there.\n3. Put the new name, user and password into the app's config file, with host `localhost`, before archiving; then deploy as above. Never ship the `srvNNNN.hstgr.io` host inside the app.\n\n**Node.js:** deploy with the `deploy-to-hosting` skill. When a dump must be imported, create the database with `hosting_databases_create` rather than `hosting_databases_setup-website` — the latter never reveals the password needed for the import — and pass the credentials through environment variables.\n\n**Agency:** files with `agency-hosting_deploy-php-application` [or upload plus `agency-hosting_files_import-website-from-archive`]; the database with `agency-hosting_databases_create-website`, imported through phpMyAdmin in hPanel (no import operation exists). For WordPress, set the new credentials in `wp-config.php` before archiving.\n\n## 4. Test before DNS moves\n\nFind the server address: `details.ipv4` for Agency; for Shared and Cloud, the `A` record for `@` in the Hostinger zone (`dns_records_list` on the domain) or the IP hPanel shows for the website. Then point only this machine at it:\n\n```bash\ncurl -sSk --resolve DOMAIN:443:IP -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/\ncurl -sSk --resolve DOMAIN:443:IP https://DOMAIN/ | grep -o \"TEXT FROM THE LIVE SITE\"\ncurl -sSk --resolve DOMAIN:443:IP -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/wp-login.php\n```\n\n`-k` is expected here: the certificate for the domain can only be issued after DNS moves. Check the home page, an inner page and, for WordPress, the login page. For a look in the browser, the user adds `IP DOMAIN www.DOMAIN` to their hosts file and removes it afterwards. Fix anything broken now, while visitors still see the old site.\n\n## 5. Switch DNS and SSL\n\nFollow the `connect-domain` skill from its DNS step: keep every `MX` and `TXT` record from step 1, then install SSL once the domain resolves to Hostinger. When the user controls the old DNS, lowering the TTL of the `A` records to 300 a day ahead shortens the switch.\n\n## 6. After the switch\n\n- Verify without `--resolve`: `curl -sSI https://DOMAIN/` shows `platform: hostinger`.\n- Recreate the old host's cron jobs with `hosting_cron-jobs_create` (Agency: `agency-hosting_cron-jobs_create-website`).\n- Keep the old hosting running for a few days — some resolvers still cache the old address, and email hosted there must be moved separately.\n"
|
|
131
131
|
}
|
|
132
132
|
]
|
|
133
133
|
},
|
|
@@ -140,10 +140,10 @@ export default [
|
|
|
140
140
|
"resources": [
|
|
141
141
|
{
|
|
142
142
|
"uri": "skill://troubleshoot-website/SKILL.md",
|
|
143
|
-
"digest": "sha256:
|
|
144
|
-
"size":
|
|
143
|
+
"digest": "sha256:bd75940c8fd84f9b67d392063203761a2903108be0117602588e92051a87ea56",
|
|
144
|
+
"size": 9790,
|
|
145
145
|
"mimeType": "text/markdown",
|
|
146
|
-
"text": "---\nname: troubleshoot-website\ndescription: \"Diagnose and fix a website on Hostinger web hosting (Shared, Cloud or Agency plans) that is down, slow, erroring, insecure or failing to build. Checks the site from outside, reads builds, runtime logs, WordPress health, SSL, cache and PHP settings through the Hostinger MCP, names the cause with evidence, and applies the fix once the user agrees. Triggers: my site is down, site not loading, 500 / 502 / 503 error, white screen, error establishing a database connection, site is slow, SSL or certificate warning, not secure, changes not showing, Node.js build failed, app keeps crashing.\"\n---\n\n# Troubleshoot a website\n\nOne website and one symptom in; a named cause, the evidence for it, and a fix out. Stay read-only until the cause is stated and the user agrees to the fix.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute` and pass values between steps with `$steps.<i>.<path>`, e.g. `\"$steps.0.data.0.username\"`. A batch stops at its first failure.\n- The Hostinger Connector runs each product as its own MCP server (`hosting`, `wordpress`, `agency-hosting`, `domains`, `dns`), so a batch can only chain operations from one server. When `search` cannot find an operation, that product group is switched off in the Connector — ask the user to enable it.\n\n## 1. Find the website\n\nRun both lookups, and keep the result for every later call:\n\n- `hosting_websites_list` with `domain` — Shared and Cloud plans. The filter is a substring match, so take the entry whose `domain` is exactly the one asked about. Keep `username`, `order_id` and `website_type`; every `hosting_*` and `wordpress_*` call is keyed on `username` + `domain`.\n- `agency-hosting_websites_list-plan` with `domain` — Agency Plan. Keep `details.uid` (the `website_uid` of every `agency-hosting_*` call), `details.type`, `details.ipv4` and `details.domains`.\n\nNeither finds it: the domain is not a website on this account — say so and show where it points (step 2).\n\n## 2. Look at it from outside\n\nRun these alongside step 1:\n\n```bash\ncurl -sS -o /dev/null -w \"%{http_code} ttfb=%{time_starttransfer}s %{redirect_url}\\n\" https://DOMAIN/\ncurl -sSI https://DOMAIN/\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short CAA DOMAIN\n```\n\n- Hostinger responses carry `platform: hostinger` and `panel: hpanel`. Without them, or with DNS pointing elsewhere, traffic is not reaching this hosting — hand over to the `connect-domain` skill.\n- Certificate or TLS errors → [SSL](#ssl).\n- `5xx`, a blank page or an error page → [By website type](#3-by-website-type).\n- `200` with old content → cache: `hosting_cache_clear-website` (also purges the Hostinger CDN; pass `directory` for WordPress in a subfolder), plus `wordpress_litespeed-cache_purge-lite-speed` for WordPress; Agency: `agency-hosting_cache_clear-website`.\n- Slow first byte → [Slow site](#slow-site). Behind the Hostinger CDN, `x-hcdn-upstream-rt` is the origin's own response time in seconds; a small value there means the server is not the bottleneck.\n\n## 3. By website type\n\n`website_type` (Shared/Cloud) or `details.type` (Agency) picks the branch. `builder` and `horizons` sites are not managed by these operations — send the user to hPanel.\n\n### Node.js (`nodejs`)\n\nBatch `
|
|
146
|
+
"text": "---\nname: troubleshoot-website\ndescription: \"Diagnose and fix a website on Hostinger web hosting (Shared, Cloud or Agency plans) that is down, slow, erroring, insecure or failing to build. Checks the site from outside, reads builds, runtime logs, WordPress health, SSL, cache and PHP settings through the Hostinger MCP, names the cause with evidence, and applies the fix once the user agrees. Triggers: my site is down, site not loading, 500 / 502 / 503 error, white screen, error establishing a database connection, site is slow, SSL or certificate warning, not secure, changes not showing, Node.js build failed, app keeps crashing.\"\n---\n\n# Troubleshoot a website\n\nOne website and one symptom in; a named cause, the evidence for it, and a fix out. Stay read-only until the cause is stated and the user agrees to the fix.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute` and pass values between steps with `$steps.<i>.<path>`, e.g. `\"$steps.0.data.0.username\"`. A batch stops at its first failure.\n- The Hostinger Connector runs each product as its own MCP server (`hosting`, `wordpress`, `agency-hosting`, `domains`, `dns`), so a batch can only chain operations from one server. When `search` cannot find an operation, that product group is switched off in the Connector — ask the user to enable it.\n\n## 1. Find the website\n\nRun both lookups, and keep the result for every later call:\n\n- `hosting_websites_list` with `domain` — Shared and Cloud plans. The filter is a substring match, so take the entry whose `domain` is exactly the one asked about. Keep `username`, `order_id` and `website_type`; every `hosting_*` and `wordpress_*` call is keyed on `username` + `domain`.\n- `agency-hosting_websites_list-plan` with `domain` — Agency Plan. Keep `details.uid` (the `website_uid` of every `agency-hosting_*` call), `details.type`, `details.ipv4` and `details.domains`.\n\nNeither finds it: the domain is not a website on this account — say so and show where it points (step 2).\n\n## 2. Look at it from outside\n\nRun these alongside step 1:\n\n```bash\ncurl -sS -o /dev/null -w \"%{http_code} ttfb=%{time_starttransfer}s %{redirect_url}\\n\" https://DOMAIN/\ncurl -sSI https://DOMAIN/\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short CAA DOMAIN\n```\n\n- Hostinger responses carry `platform: hostinger` and `panel: hpanel`. Without them, or with DNS pointing elsewhere, traffic is not reaching this hosting — hand over to the `connect-domain` skill.\n- Certificate or TLS errors → [SSL](#ssl).\n- `5xx`, a blank page or an error page → [By website type](#3-by-website-type).\n- `200` with old content → cache: `hosting_cache_clear-website` (also purges the Hostinger CDN; pass `directory` for WordPress in a subfolder), plus `wordpress_litespeed-cache_purge-lite-speed` for WordPress; Agency: `agency-hosting_cache_clear-website`.\n- Slow first byte → [Slow site](#slow-site). Behind the Hostinger CDN, `x-hcdn-upstream-rt` is the origin's own response time in seconds; a small value there means the server is not the bottleneck.\n\n## 3. By website type\n\n`website_type` (Shared/Cloud) or `details.type` (Agency) picks the branch. `builder` and `horizons` sites are not managed by these operations — send the user to hPanel.\n\n### Node.js (`nodejs`)\n\nBatch `hosting_get-deployment` (the latest build with its log, failure analysis and stored settings), `hosting_nodejs_runtime-logs` (`period: \"1h\"`, `levels: [\"ERROR\", \"WARN\"]`) and `hosting_nodejs_list-environment-variables` (keys only; values always come back masked). On the hosted server, which has no `hosting_get-deployment`, use `hosting_nodejs_list-builds` (`per_page: 3`) in its place.\n\n- Latest build `failed`: `hosting_get-deployment` already holds the `analysis` (fetched once per build — the API re-runs it on every call and allows 5 a minute). A wrongly detected framework, output directory or missing `entry_file` is the usual cause: compare the returned `buildSettings` with the project and deploy again with corrected `appType`, `outputDirectory`, `buildScript` or `entryFile`; a Git deploy stores them, so pushes build correctly too. On the hosted server: `hosting_nodejs_analyse-failed-build` once for that build, then `hosting_nodejs_build-logs`; compare `hosting_nodejs_build-settings`, rebuild through `hosting_nodejs_start-build` and store the values with `hosting_nodejs_update-build-settings`.\n- Build `completed` but the app errors: read the runtime logs; entries older than `last_deployed_at` belong to the previous deploy. A variable the code reads but the key list lacks is fixed with the `deploy-to-hosting` skill's environment step. `Access denied for user '…'@'::1'` means the app connects to `localhost` — `DB_HOST` must be `127.0.0.1`.\n- Hung process: `hosting_nodejs_restart-application` (restarts without rebuilding).\n\n### WordPress (`wordpress`)\n\n`wordpress_installations_list` with `username` and `domain` gives the install `id` — the `software` parameter of every `wordpress_*` call. Batch `wordpress_installations_check-if-are-valid` (`software_ids: [id]`, `force: true`), `wordpress_plugins_list-installed` and `wordpress_maintenance_show-status`.\n\n- Invalid install: `validation_error` names the problem.\n- Broken after a plugin or theme change: deactivate suspects one at a time with `wordpress_plugins_deactivate` (queued — allow a few seconds), re-run the step 2 check after each, and reactivate with `wordpress_plugins_activate` any that were not the cause.\n- Maintenance page stuck: `wordpress_maintenance_toggle` with `enabled: false`.\n- \"Error establishing a database connection\": `hosting_databases_list` with `domain`; corrupted tables are fixed by `hosting_databases_repair` (runs in the background). `wp-config.php` cannot be read through the API because files with secrets are refused — for credential checks hand the user `hosting_databases_phpmyadmin-link`.\n- Memory or upload-size errors → [PHP](#php).\n\n### Static or PHP (`other`)\n\n- `403` or `404` at `/`: `hosting_files_list-website-and-directories` with `max_depth: 1`. `index.html` or `index.php` must sit at the document root; finding it one folder down means the archive was packed a level too deep — redeploy it flat with the `deploy-to-hosting` skill.\n- Read `.htaccess` or other config with `hosting_files_website-content`.\n- PHP errors → [PHP](#php).\n\n### PHP\n\n`hosting_php_get` returns every extension and option (around 25 KB), so call it only for PHP problems. `hosting_php_update-version` switches versions. `hosting_php_update-options` silently caps values at the plan maximum (`max` in `hosting_php_get`), so read the applied value back. Agency: `agency-hosting_php_list-options-for-website`, then `agency-hosting_php_replace-website-options` — a full replace, so send every custom option that should stay.\n\n### Agency Plan sites\n\n`agency-hosting_websites_get` shows state and quotas, `agency-hosting_websites_list-processes` shows failed jobs (SSL setup, backups), and `agency-hosting_wordpress_settings` shows core version, LiteSpeed, object cache and maintenance mode. When `wordpress_installations_list` does not return the site, plugins are managed from wp-admin.\n\n## SSL\n\nShared and Cloud, `hosting_ssl_status`:\n\n- `not_installed` or `failed` (`last_error` says why): the domain must resolve to Hostinger, and any CAA record must allow `letsencrypt.org`, before `hosting_ssl_install` can succeed. Poll the status until `active` or `failed`.\n- `installing` or `waiting_for_retry`: wait — another install request returns 422.\n- Free `*.hostingersite.com` subdomains use a platform certificate; installing returns 422 by design.\n- Browser still warns while the certificate is `active`: turn on the redirect with `hosting_ssl_toggle-https-redirect` when `is_https_redirect_enabled` is false, otherwise the page loads `http://` assets (mixed content) that the app has to change.\n\nAgency, `agency-hosting_ssl_website-status` for each domain: every domain allows three certificate setups per seven days and one request a minute. Check `agency-hosting_websites_list-processes` before `agency-hosting_ssl_install-website` or `agency-hosting_ssl_reinstall-website`, and never retry in a loop.\n\n## Slow site\n\n- WordPress: `wordpress_litespeed-cache_show-lite-speed-status` and `wordpress_object-cache_show-memcached-status`. Turning on Memcached with `wordpress_object-cache_toggle-memcached` is the usual quick win.\n- Other sites: server caching may be off or development mode left on, and neither has a read operation. `hosting_cache_toggle-website` with `enabled: true` does nothing when caching is already on; `hosting_cache_toggle-cacheless` with `enabled: false` turns development mode off.\n- PHP 7.x runs markedly slower than 8.x; propose a supported 8.x version from `hosting_php_get` when the app allows it.\n- Agency: `agency-hosting_metrics_list-order-resource-usage` with `time_frame_hours: 24` shows CPU, memory and processes per website against the plan quota.\n- Shared and Cloud have no CPU or memory metrics in the API. When the evidence points at resource limits, send the user to hPanel's resource usage page.\n\n## Apply the fix\n\nState the cause, the evidence and the single change proposed, and make it only after the user agrees. Then re-run the step 2 check, polling any queued job first, to show the symptom is gone. When the fix needs something the API cannot do, say so and name the hPanel page.\n\n## Not available through the API\n\n- Website backups and restores — hPanel's Backups page.\n- CPU, memory and process usage for Shared and Cloud plans.\n- PHP error and access logs.\n"
|
|
147
147
|
}
|
|
148
148
|
]
|
|
149
149
|
}
|
package/src/core/skills.ts
CHANGED
|
@@ -23,10 +23,10 @@ const skills: Skill[] = [
|
|
|
23
23
|
"resources": [
|
|
24
24
|
{
|
|
25
25
|
"uri": "skill://audit-hosting/SKILL.md",
|
|
26
|
-
"digest": "sha256:
|
|
27
|
-
"size":
|
|
26
|
+
"digest": "sha256:7220be5f12f2df2fbe3de85a6fa33fb19086b3878244e978b6be62f3b45803f3",
|
|
27
|
+
"size": 5546,
|
|
28
28
|
"mimeType": "text/markdown",
|
|
29
|
-
"text": "---\nname: audit-hosting\ndescription: \"Audit a Hostinger web hosting account (Shared, Cloud and Agency plans) and report what needs attention: every plan and website, SSL problems, broken or vulnerable WordPress installs, failed Node.js builds and vulnerable npm packages, databases and Agency Plan orders near their limits, and hosting plans about to lapse. Read-only; produces a prioritised to-do list and names the skill that fixes each item. Triggers: what do I have on Hostinger, audit my hosting, check all my websites, what needs attention, health check my sites, are any of my sites broken, which of my sites are insecure.\"\n---\n\n# Audit hosting\n\nRead-only from start to finish. The output is a report; every fix is a separate, confirmed step through another skill.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute`, up to 20 steps a batch. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting` and `billing` as separate servers. When a product group is switched off, skip its checks and say which were skipped.\n- Page every list until `meta.total` is covered.\n- Leave `hosting_php_get` out — it is large and says nothing about account health.\n\n## 1. Inventory\n\nOne batch per server:\n\n- `hosting_orders_list` with `statuses: [\"active\", \"suspended\"]`. `cloud_*` plan names are Cloud; the rest (`hostinger_premium_*`, `hostinger_business_*`, …) are Shared.\n- `hosting_websites_list` — every Shared and Cloud website with `website_type`, `username`, `order_id` and `is_enabled` (false means suspended).\n- `wordpress_installations_list` with `ownership: \"all\"` — `id`, `is_valid`, `validation_error`.\n- `agency-hosting_orders_list` and `agency-hosting_websites_list-plan` — Agency orders and sites (`details.uid`, `details.type`, `details.domains`, `details.state`).\n\nTell the user the size (plans, websites, WordPress installs) before the checks. For large accounts offer to scope the audit to one order or domain.\n\n## 2. Checks\n\nPer Shared and Cloud website (skip `builder` and `horizons`):\n\n- `hosting_ssl_status` — flag `failed` (with `last_error`), `expired`, `not_installed` on a custom domain, `is_https_redirect_enabled: false`, and `expires_at` within 30 days when `is_lifetime` is false. Lifetime certificates renew on their own.\n- Node.js sites: `hosting_nodejs_list-builds` with `per_page: 1`
|
|
29
|
+
"text": "---\nname: audit-hosting\ndescription: \"Audit a Hostinger web hosting account (Shared, Cloud and Agency plans) and report what needs attention: every plan and website, SSL problems, broken or vulnerable WordPress installs, failed Node.js builds and vulnerable npm packages, databases and Agency Plan orders near their limits, and hosting plans about to lapse. Read-only; produces a prioritised to-do list and names the skill that fixes each item. Triggers: what do I have on Hostinger, audit my hosting, check all my websites, what needs attention, health check my sites, are any of my sites broken, which of my sites are insecure.\"\n---\n\n# Audit hosting\n\nRead-only from start to finish. The output is a report; every fix is a separate, confirmed step through another skill.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute`, up to 20 steps a batch. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting` and `billing` as separate servers. When a product group is switched off, skip its checks and say which were skipped.\n- Page every list until `meta.total` is covered.\n- Leave `hosting_php_get` out — it is large and says nothing about account health.\n\n## 1. Inventory\n\nOne batch per server:\n\n- `hosting_orders_list` with `statuses: [\"active\", \"suspended\"]`. `cloud_*` plan names are Cloud; the rest (`hostinger_premium_*`, `hostinger_business_*`, …) are Shared.\n- `hosting_websites_list` — every Shared and Cloud website with `website_type`, `username`, `order_id` and `is_enabled` (false means suspended).\n- `wordpress_installations_list` with `ownership: \"all\"` — `id`, `is_valid`, `validation_error`.\n- `agency-hosting_orders_list` and `agency-hosting_websites_list-plan` — Agency orders and sites (`details.uid`, `details.type`, `details.domains`, `details.state`).\n\nTell the user the size (plans, websites, WordPress installs) before the checks. For large accounts offer to scope the audit to one order or domain.\n\n## 2. Checks\n\nPer Shared and Cloud website (skip `builder` and `horizons`):\n\n- `hosting_ssl_status` — flag `failed` (with `last_error`), `expired`, `not_installed` on a custom domain, `is_https_redirect_enabled: false`, and `expires_at` within 30 days when `is_lifetime` is false. Lifetime certificates renew on their own.\n- Node.js sites: `hosting_get-deployment` (latest build failed? `build.state`; on the hosted server use `hosting_nodejs_list-builds` with `per_page: 1`) and `hosting_nodejs_list-vulnerabilities` with `severities: [\"critical\", \"high\"]`.\n\nPer hosting account (`username`): `hosting_databases_list` — flag `disk_usage_mb` above 80% of `max_size_mb`.\n\nPer WordPress install: `wordpress_installations_show-core-version` (core vulnerabilities) and `wordpress_plugins_list-installed` (vulnerable plugins and pending updates).\n\nPer Agency order: `agency-hosting_metrics_list-order-resource-usage` with `time_frame_hours: 168` and `agency-hosting_metrics_list-plan-order-disk-usage` with `time_frame_days: 7` — flag usage above 80% of the plan quota and name the heaviest websites.\n\nPer Agency site: `agency-hosting_ssl_website-status` for each custom domain in `details.domains`; flag `details.state` other than `active`.\n\nPlans about to lapse (billing product): `billing_subscriptions_list`, joined to hosting orders on `subscription_id` — flag `not_renewing`, or `is_auto_renewed: false` with `expires_at` within 30 days. Every site on that plan goes down with it.\n\nFrom outside, for each custom domain:\n\n```bash\ncurl -sS -o /dev/null -w \"%{http_code}\\n\" --max-time 15 https://DOMAIN/\ncurl -sSI --max-time 15 https://DOMAIN/ | grep -i \"^platform\"\n```\n\nNo `platform: hostinger` header means the domain does not reach this hosting.\n\n## 3. Report\n\n```\n# Hosting audit\n3 plans (2 Shared, 1 Cloud) + 1 Agency · 14 websites (6 WordPress, 3 Node.js, 5 other) · 4 Agency sites\n\n## Fix now\n- shop.example.com — latest Node.js build failed 2 days ago → troubleshoot-website\n- blog.example.com — contact-form-x 5.2 has a known vulnerability, fixed in 5.3 → maintain-wordpress\n\n## Soon\n- example.org — Business plan expires in 12 days, auto-renew off → renew in hPanel\n- Agency order 1000000001 — 86% of disk quota, mostly client-a.com\n\n## Worth knowing\n- 4 WordPress installs have pending plugin updates → maintain-wordpress\n\n## Healthy\ndocs.example.com, portfolio.example.com, …\n```\n\n- **Fix now:** site down or not reaching Hostinger, failed latest build, invalid WordPress install, SSL `failed` or `expired`, critical vulnerabilities, suspended website.\n- **Soon:** high vulnerabilities, a plan lapsing within 30 days, usage above 80% of a quota, HTTPS redirect off, non-lifetime certificates expiring.\n- **Worth knowing:** pending updates, inactive plugins with vulnerabilities.\n\nEach item names the evidence and the skill that fixes it: `troubleshoot-website`, `maintain-wordpress`, `connect-domain` or `deploy-to-hosting`. Patchable npm vulnerabilities on GitHub-deployed sites can be fixed with `hosting_nodejs_patch-vulnerabilities`, which opens a pull request — offer it, do not run it as part of the audit.\n\n## Not available through the API\n\nCPU and memory usage for Shared and Cloud plans, website backup status, and PHP error logs. Mention them once at the end so the user knows what the audit could not see.\n"
|
|
30
30
|
}
|
|
31
31
|
]
|
|
32
32
|
},
|
|
@@ -55,10 +55,10 @@ const skills: Skill[] = [
|
|
|
55
55
|
"resources": [
|
|
56
56
|
{
|
|
57
57
|
"uri": "skill://deploy-to-hosting/SKILL.md",
|
|
58
|
-
"digest": "sha256:
|
|
59
|
-
"size":
|
|
58
|
+
"digest": "sha256:a493669430a2c1c20c6cd965620f89ae60dd1204f7d414574202c6d392d8bad8",
|
|
59
|
+
"size": 15008,
|
|
60
60
|
"mimeType": "text/markdown",
|
|
61
|
-
"text": "---\nname: deploy-to-hosting\ndescription: \"Deploy an existing project to a website on Hostinger web hosting (Shared, Cloud or Agency plans) and keep it deployed: picks the right deploy for static sites, Node.js apps (Next.js, Nuxt, Express, Vite and similar), PHP apps and WordPress plugins or themes, sets up auto-deploy from GitHub or GitLab, manages Node.js environment variables and MySQL databases, and verifies the live site. Triggers: deploy this project, deploy to Hostinger, push my app live, redeploy, set up auto-deploy, connect my GitHub repo, add environment variables, my app needs a database, deploy my WordPress plugin or theme.\"\n---\n\n# Deploy to hosting\n\nShip a project that already exists — on disk or in a Git repository — to a Hostinger website. Building a new site from a prompt (design, store, blog) is the `hostinger-headless` skill; this one takes code as it is.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"deploy static\").\n- Batch reads with `multi-execute`; values pass between steps as `$steps.<i>.<path>`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress` and `agency-hosting` as separate servers.\n- Every deploy overwrites the website's current contents. Confirm the target domain with the user before the first deploy to a site that already has content.\n\n## 1. Pick the target website\n\n- `.hostinger/site.json` in the project: reuse its `domain` and `username` (or `website_uid`).\n- Otherwise look the domain up with `hosting_websites_list` (Shared and Cloud; substring match — take the exact entry) and `agency-hosting_websites_list-plan` (Agency; keep `details.uid`).\n- No website yet:\n - Shared and Cloud: take a domain (the user's own, or `hosting_domains_generate-free-subdomain`) and an `order_id` from `hosting_orders_list`, then `hosting_websites_create`. `datacenter_code` is needed only for the first website on a new plan (first entry of `hosting_datacenters_list`). Poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed` — uploads and deploys return 404 or 409 before that.\n - Agency: `agency-hosting_website-setups_create` with `flavor: \"php-fpm\"` (plus `type: \"node-static\"` for built frontends), `settings.php.version` from `agency-hosting_php_list-versions-for-order` and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed`; it returns the `website_uid`.\n- Node.js apps run on Business and Cloud plans (`hostinger_business_*`, `cloud_*` in `hosting_orders_list`). On other plans, build locally and deploy the output as a static site.\n\n## 2. Choose the deploy\n\nWrong method is the most common failure. Decide from the project on disk:\n\n| Project | Shared / Cloud |\n| --- | --- |\n| Plain HTML/CSS/JS, or a framework's static build output | `hosting_deploy-static-website` |\n| `package.json` with a build or a server (Next.js, Nuxt, Express, Vite…) | `hosting_deploy-js-application` |\n| PHP code, no build step | `hosting_deploy-static-website` (extracts the archive as-is) |\n| WordPress plugin or theme folder | `hosting_deploy-wordpress-plugin` / `hosting_deploy-wordpress-theme` (`activate` optional) |\n| A whole WordPress site from elsewhere | the `migrate-to-hosting` skill |\n\nOn Agency the website's type decides (`agency-hosting_websites_get`): sites created as `node-static` take `agency-hosting_deploy-node-static-website`, which runs the build when the project has one; every other site takes `agency-hosting_deploy-php-application`, which extracts the archive as-is. WordPress plugins and themes on Agency sites are installed from wp-admin.\n\nArchive rules (name archives `name_YYYYMMDD_HHMMSS.zip`):\n\n- **Static:** build locally first. `index.html` must be at the archive root, not inside a folder: `cd dist && zip -r ../site_20260101_120000.zip .`\n- **Node.js source:** no `node_modules/`, no build output (`dist/`, `.next/`, `build/`), no `.env*`, nothing matched by `.gitignore`; 50 MB at most. `git archive --format=zip -o app_20260101_120000.zip HEAD` produces exactly the committed files — mention that uncommitted changes are left out.\n- Agency deploys are synchronous: the site is live when the call returns.\n\nThe operations in the table read the archive from this machine, so only the local `hostinger-api-mcp` server has them. On the hosted server (`mcp.hostinger.com`) `search` does not find them — upload the files yourself as below.\n\n### Without the local deploy operations\n\n1. Get upload credentials: `hosting_files_generate-upload-url` (`username`, `domain`); Agency: `agency-hosting_files_generate-upload-url` (`website_uid`). Both return `url`, `auth_key` and `rest_auth_key`, which authenticate the upload instead of the API token.\n2. Upload each file with TUS, where `DEST` is its path in the website's storage:\n\n```bash\nSIZE=$(wc -c < \"$FILE\" | tr -d ' ')\ncurl -sS -X POST \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Upload-Length: $SIZE\" -H \"Upload-Offset: 0\"\ncurl -sS -X PATCH \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Content-Type: application/offset+octet-stream\" -H \"Upload-Offset: 0\" --data-binary \"@$FILE\"\n```\n\n The first call returns `201`, the second `204` with an `Upload-Offset` header equal to the file size. `override=true` makes a retry safe.\n3. Deploy from the uploaded files (`RANDOM8` is any fresh 8-character string, e.g. `$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8)`):\n\n| Project | `DEST` | Then |\n| --- | --- | --- |\n| Static or PHP | `site.zip` | `hosting_websites_deploy-static-site-archive` with `archive_path: \"site.zip\"` |\n| Node.js | `app.zip` | `hosting_nodejs_build-settings-from-archive` with `archive_path: \"app.zip\"`, then `hosting_nodejs_start-build` with those settings, `source_type: \"archive\"` and `source_options.archive_path: \"app.zip\"` |\n| WordPress plugin | every file, as `wp-content/plugins/SLUG-RANDOM8/<path in the plugin>` | `wordpress_plugins_deploy` with `slug` and `plugin_path: \"SLUG-RANDOM8\"` |\n| WordPress theme | every file, as `wp-content/themes/SLUG-RANDOM8/<path in the theme>` | `wordpress_themes_deploy` with `slug`, `theme_path: \"SLUG-RANDOM8\"` and optional `is_activated` |\n| Agency, extracted as-is | `.h5g/site.zip` | `agency-hosting_files_import-website-from-archive` with `archive_name: \"site.zip\"` |\n| Agency `node-static` | `.h5g/RANDOM8/app.zip` | `agency-hosting_websites_build-nodejs-assets` with `archive_path: \".h5g/RANDOM8\"` — the directory, not the file |\n\n## 3. Node.js builds\n\n`hosting_deploy-js-application` uploads the archive to the document root, detects settings from `package.json` and starts a build. Track it with `hosting_nodejs_list-builds` and `hosting_nodejs_build` (by `uuid`), polling every 10–20 s — builds take minutes.\n\n- Failed build: `hosting_nodejs_analyse-failed-build` once per build (5 calls a minute), then `hosting_nodejs_build-logs` if the analysis is empty.\n- Wrong detection (framework, `output_directory`, or a missing `entry_file` for express, fastify, nest, nuxt and hono): run `hosting_nodejs_start-build` with explicit values, `source_type: \"archive\"` and `source_options.archive_path` set to the archive's file name in the document root (check it is there with `hosting_files_list-website-and-directories`). Store the same values with `hosting_nodejs_update-build-settings`.\n- To review detected settings before any build: upload the archive with `hosting_files_generate-upload-url` (the TUS steps are in its description), then `hosting_nodejs_build-settings-from-archive`.\n\n## 4. Auto-deploy from Git\n\n1. `hosting_git_list-installations`. With no `active` installation (check `status: \"pending\"` and `\"suspended\"` too), the user connects GitHub or GitLab once in hPanel under Websites → Manage → Advanced → Git; there is no API for that step.\n2. `hosting_git_list-installation-repositories` with the installation `uuid` gives `owner`, `name` and `default_branch` (10 calls a minute).\n3. `hosting_git_update-auto-deployment-settings` with `installation_uuid`, `owner`, `repository`, `branch` and optional `directory`.\n - PHP and static sites deploy the branch immediately and again on every push.\n - Node.js sites clone nothing on save: start the first build with `hosting_nodejs_start-build`, `source_type: \"git\"` and the same `source_options`. Later pushes build with the stored settings, so keep `hosting_nodejs_update-build-settings` correct.\n4. Confirm with `hosting_git_auto-deployment-settings`.\n\nAgency Plan sites have no Git operations; deploy archives.\n\n## 5. Environment variables (Node.js)\n\n`hosting_nodejs_replace-environment-variables` replaces the whole set — anything not sent is deleted.\n\n1. `hosting_nodejs_list-environment-variables` for the current keys. Values come back as `********`; never send those back.\n2. Build the full set: every current key plus the new ones, with real values from the project's `.env` or the user. When the real value of an existing key is unknown, ask — do not drop it.\n3. Send it once; the app restarts. Values baked in at build time (Next.js `NEXT_PUBLIC_*`, Vite `VITE_*`) need a new `hosting_nodejs_start-build`.\n\nKeys use uppercase letters, digits and underscores. Never commit `.env` files or repeat secret values back to the user.\n\n## 6. Database\n\n- **Node.js:** `hosting_databases_setup-website` creates a MySQL database and writes `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` and `DATABASE_URL` into the environment, then restarts the app. The password is generated and never returned. It fails with 422 when any of those keys exists — remove them first with the step 5 replace.\n- **PHP:** `hosting_databases_create` with `name`, `user`, a strong generated `password` and `website_domain`; read the prefixed full name back from `hosting_databases_list`. The app reads credentials from a config file on the server that stays out of Git, and connects to `localhost` or `127.0.0.1`.\n- **Agency:** `agency-hosting_databases_create-website`; the app connects to `localhost`.\n- The `srvNNNN.hstgr.io` host from `hosting_databases_list` is only for connections from outside Hostinger — never put it in the deployed app.\n\n## 7. Verify and record\n\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/\ncurl -s https://DOMAIN/ | grep -o \"TEXT THE PROJECT RENDERS\"\n```\n\nA `200` alone can be a placeholder page; match real copy. A new site may serve a default page briefly — clear it with `hosting_cache_clear-website` and retry before calling the deploy failed.\n\nWrite `.hostinger/site.json` in the project so later runs reuse the target: `{ \"domain\", \"username\" or \"website_uid\", \"type\": \"static\" | \"nodejs\" | \"php\" }`, keeping any fields already there.\n"
|
|
61
|
+
"text": "---\nname: deploy-to-hosting\ndescription: \"Deploy an existing project to a website on Hostinger web hosting (Shared, Cloud or Agency plans) and keep it deployed: picks the right deploy for static sites, Node.js apps (Next.js, Nuxt, Express, Vite and similar), PHP apps and WordPress plugins or themes, sets up auto-deploy from GitHub or GitLab, manages Node.js environment variables and MySQL databases, and verifies the live site. Triggers: deploy this project, deploy to Hostinger, push my app live, redeploy, set up auto-deploy, connect my GitHub repo, add environment variables, my app needs a database, deploy my WordPress plugin or theme.\"\n---\n\n# Deploy to hosting\n\nShip a project that already exists — on disk or in a Git repository — to a Hostinger website. Building a new site from a prompt (design, store, blog) is the `hostinger-headless` skill; this one takes code as it is.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"deploy static\").\n- Batch reads with `multi-execute`; values pass between steps as `$steps.<i>.<path>`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress` and `agency-hosting` as separate servers.\n- Every deploy overwrites the website's current contents. Confirm the target domain with the user before the first deploy to a site that already has content.\n\n## 1. Pick the target website\n\n- `.hostinger/site.json` in the project: reuse its `domain` and `username` (or `website_uid`).\n- Otherwise look the domain up with `hosting_websites_list` (Shared and Cloud; substring match — take the exact entry) and `agency-hosting_websites_list-plan` (Agency; keep `details.uid`).\n- No website yet:\n - Shared and Cloud: take a domain (the user's own, or `hosting_domains_generate-free-subdomain`) and an `order_id` from `hosting_orders_list`, then `hosting_websites_create`. `datacenter_code` is needed only for the first website on a new plan (first entry of `hosting_datacenters_list`). Poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed` — uploads and deploys return 404 or 409 before that.\n - Agency: `agency-hosting_website-setups_create` with `flavor: \"php-fpm\"` (plus `type: \"node-static\"` for built frontends), `settings.php.version` from `agency-hosting_php_list-versions-for-order` and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed`; it returns the `website_uid`.\n- Node.js apps run on Business and Cloud plans (`hostinger_business_*`, `cloud_*` in `hosting_orders_list`). On other plans, build locally and deploy the output as a static site.\n\n## 2. Choose the deploy\n\n**Shared and Cloud, on the local `hostinger-api-mcp` server:** one operation does every deploy — `hosting_deploy` with `domain` and either `path` (a directory on this machine) or `git: { repository: \"owner/name\", branch }`. Given a directory it detects what the project is, packs it itself (it skips `node_modules`, `.git` and `.env` files, listing the `.env` ones as `skippedFiles` so you can set their values with `hosting_nodejs_replace-environment-variables`; it does not read `.gitignore`, so keep build output out of the directory) and does the upload, build and Git setup. Do not archive the directory or call upload and build operations by hand.\n\n| Project | `hosting_deploy` treats it as |\n| --- | --- |\n| Plain HTML/CSS/JS, or a framework's static build output | `static` — extracts as-is |\n| `package.json` with a build script, a start script or a server dependency (Next.js, Nuxt, Express, Vite…) | `nodejs` — starts a build, returns `buildUuid` |\n| PHP code, no build step | `static` |\n| WordPress plugin folder (a `Plugin Name:` header) or theme folder (`Theme Name:` in `style.css`) | `wordpress-plugin` / `wordpress-theme`; `activate: true` activates a theme |\n| A whole WordPress site from elsewhere | `wordpress-site`, with `databaseDump` — see the `migrate-to-hosting` skill |\n\n- Pass `type` to override detection. It is required for an archive (an archive cannot be inspected) and when a directory matches more than one WordPress type, which `hosting_deploy` rejects as ambiguous.\n- Node.js build settings come from the project; detection covers the framework and the build script. Set `appType`, `outputDirectory`, `buildScript`, `entryFile`, `nodeVersion` (default 22), `rootDirectory` or `packageManager` when it is wrong. A TypeScript or other compiled server app always needs `entryFile` set to the built file (for example `dist/server.js`): detection only guesses a root-level file, and the build fails with \"Entry file not found\". The entry file is relative to the root directory for express, fastify, hono, react-router and other, and to the output directory for nest, nuxt, nitro, astro and svelte-kit (`main.js`, not `dist/main.js`); Next.js ignores it. Per-framework values are in the Hostinger docs under Node.js (Supported Frameworks, Build Settings).\n- Static, PHP, plugin and theme deploys are live when the call returns. A WordPress site import only starts (`status: import_started`) and finishes extracting a few minutes later; do not report it complete or verify it before then. Node.js builds run on the server: see step 3.\n\n**Agency:** the website's type decides (`agency-hosting_websites_get`): sites created as `node-static` take `agency-hosting_deploy-node-static-website`, which runs the build when the project has one; every other site takes `agency-hosting_deploy-php-application`, which extracts the archive as-is. They deploy archives, synchronously: the site is live when the call returns. WordPress plugins and themes on Agency sites are installed from wp-admin.\n\nArchive rules for Agency (name archives `name_YYYYMMDD_HHMMSS.zip`) and for archives you build yourself:\n\n- **Static:** build locally first. `index.html` must be at the archive root, not inside a folder: `cd dist && zip -r ../site_20260101_120000.zip .`\n- **Node.js source:** no `node_modules/`, no build output (`dist/`, `.next/`, `build/`), no `.env*`, nothing matched by `.gitignore`; 50 MB at most. `git archive --format=zip -o app_20260101_120000.zip HEAD` produces exactly the committed files — mention that uncommitted changes are left out.\n\n`hosting_deploy` and the `agency-hosting_deploy-*` operations read files from this machine, so only the local server has them. On the hosted server (`mcp.hostinger.com`) `search` does not find them — upload the files yourself as below.\n\n### Without the local deploy operations (hosted server; on the local server only for Agency)\n\n1. Get upload credentials: `hosting_files_generate-upload-url` (`username`, `domain`); Agency: `agency-hosting_files_generate-upload-url` (`website_uid`). Both return `url`, `auth_key` and `rest_auth_key`, which authenticate the upload instead of the API token.\n2. Upload each file with TUS, where `DEST` is its path in the website's storage:\n\n```bash\nSIZE=$(wc -c < \"$FILE\" | tr -d ' ')\ncurl -sS -X POST \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Upload-Length: $SIZE\" -H \"Upload-Offset: 0\"\ncurl -sS -X PATCH \"$URL/$DEST?override=true\" -H \"X-Auth: $AUTH_KEY\" -H \"X-Auth-Rest: $REST_AUTH_KEY\" -H \"Tus-Resumable: 1.0.0\" -H \"Content-Type: application/offset+octet-stream\" -H \"Upload-Offset: 0\" --data-binary \"@$FILE\"\n```\n\n The first call returns `201`, the second `204` with an `Upload-Offset` header equal to the file size. `override=true` makes a retry safe.\n3. Deploy from the uploaded files (`RANDOM8` is any fresh 8-character string, e.g. `$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8)`):\n\n| Project | `DEST` | Then |\n| --- | --- | --- |\n| Static or PHP | `site.zip` | `hosting_websites_deploy-static-site-archive` with `archive_path: \"site.zip\"` |\n| Node.js | `app.zip` | `hosting_nodejs_build-settings-from-archive` with `archive_path: \"app.zip\"`, then `hosting_nodejs_start-build` with those settings, `source_type: \"archive\"` and `source_options.archive_path: \"app.zip\"` |\n| WordPress plugin | every file, as `wp-content/plugins/SLUG-RANDOM8/<path in the plugin>` | `wordpress_plugins_deploy` with `slug` and `plugin_path: \"SLUG-RANDOM8\"` |\n| WordPress theme | every file, as `wp-content/themes/SLUG-RANDOM8/<path in the theme>` | `wordpress_themes_deploy` with `slug`, `theme_path: \"SLUG-RANDOM8\"` and optional `is_activated` |\n| Agency, extracted as-is | `.h5g/site.zip` | `agency-hosting_files_import-website-from-archive` with `archive_name: \"site.zip\"` |\n| Agency `node-static` | `.h5g/RANDOM8/app.zip` | `agency-hosting_websites_build-nodejs-assets` with `archive_path: \".h5g/RANDOM8\"` — the directory, not the file |\n\n## 3. Node.js builds\n\n`hosting_deploy` returns a `buildUuid` at once; the build runs on the server and takes minutes. Track it with `hosting_get-deployment` (`domain`, optionally `buildUuid`; the latest build by default), polling every 10–20 s until `build.state` is `completed` or `failed`. It returns the build, its log and the stored build settings; pass the previous `logs.lines` as `fromLine` to read only new output.\n\n- Failed build: the response already carries `analysis` (fetched once per build; the API allows 5 a minute).\n- Wrong detection (framework, `output_directory`, or an entry file inside the build output, such as `dist/server.js` for a compiled app): deploy again with `appType`, `outputDirectory`, `buildScript` or `entryFile` set. An archive deploy sends its settings with the request and leaves the stored ones alone; a Git deploy also stores these values, so later pushes build with them.\n\nOn the hosted server, which has no `hosting_deploy` or `hosting_get-deployment`:\n\n- After the upload steps below, start the build and track it with `hosting_nodejs_list-builds` and `hosting_nodejs_build` (by `uuid`), polling every 10–20 s.\n- Failed build: `hosting_nodejs_analyse-failed-build` once per build (5 calls a minute), then `hosting_nodejs_build-logs` if the analysis is empty.\n- Wrong detection: run `hosting_nodejs_start-build` with explicit values, `source_type: \"archive\"` and `source_options.archive_path` set to the archive's file name in the document root (check it is there with `hosting_files_list-website-and-directories`). Store the same values with `hosting_nodejs_update-build-settings`.\n- To review detected settings before any build: upload the archive with `hosting_files_generate-upload-url` (the TUS steps are in its description), then `hosting_nodejs_build-settings-from-archive`.\n\n## 4. Auto-deploy from Git\n\nOn the local server, `hosting_deploy` with `git: { repository: \"owner/name\", branch }` does all of it: it finds the Git installation that can reach the repository and deploys it as the `type` you give. Always pass `type: \"static\"` or `\"nodejs\"` unless the site already runs a Node.js app (or you pass Node.js settings such as `appType`): a new site is not detected as Node.js, and a Node.js repository deployed as static would publish its source. Then:\n- **PHP and static sites:** saves the auto-deployment settings, which deploys the branch immediately and again on every push;\n- **Node.js sites:** starts a build of the branch with the stored build settings; later pushes build the same way. A Git deploy has nothing to detect from, so when none are stored pass `appType` and `nodeVersion` (from `engines` in `package.json`), plus `outputDirectory` and `buildScript` if the app has a build step; they are stored for those pushes.\n\nWith no active installation it stops and says so: the user connects GitHub or GitLab once in hPanel under Websites → Manage → Advanced → Git; there is no API for that step. Confirm with `hosting_get-deployment`, which returns the stored `gitAutoDeployment`.\n\nOn the hosted server, by hand:\n\n1. `hosting_git_list-installations`. With no `active` installation (check `status: \"pending\"` and `\"suspended\"` too), the user connects GitHub or GitLab once in hPanel, as above.\n2. `hosting_git_list-installation-repositories` with the installation `uuid` gives `owner`, `name` and `default_branch` (10 calls a minute).\n3. `hosting_git_update-auto-deployment-settings` with `installation_uuid`, `owner`, `repository`, `branch` and optional `directory`.\n - PHP and static sites deploy the branch immediately and again on every push.\n - Node.js sites clone nothing on save: start the first build with `hosting_nodejs_start-build`, `source_type: \"git\"` and the same `source_options`. Later pushes build with the stored settings, so keep `hosting_nodejs_update-build-settings` correct.\n4. Confirm with `hosting_git_auto-deployment-settings`.\n\nAgency Plan sites have no Git operations; deploy archives.\n\n## 5. Environment variables (Node.js)\n\n`hosting_nodejs_replace-environment-variables` replaces the whole set — anything not sent is deleted.\n\n1. `hosting_nodejs_list-environment-variables` for the current keys. Values come back as `********`; never send those back.\n2. Build the full set: every current key plus the new ones, with real values from the project's `.env` or the user. When the real value of an existing key is unknown, ask — do not drop it.\n3. Send it once; the app restarts. Values baked in at build time (Next.js `NEXT_PUBLIC_*`, Vite `VITE_*`) need a new `hosting_nodejs_start-build`.\n\nKeys use uppercase letters, digits and underscores. Never commit `.env` files or repeat secret values back to the user.\n\n## 6. Database\n\n- **Node.js:** `hosting_databases_setup-website` creates a MySQL database and writes `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD` and `DATABASE_URL` into the environment, then restarts the app. The password is generated and never returned. It fails with 422 when any of those keys exists — remove them first with the step 5 replace.\n- **PHP:** `hosting_databases_create` with `name`, `user`, a strong generated `password` and `website_domain`; read the prefixed full name back from `hosting_databases_list`. The app reads credentials from a config file on the server that stays out of Git, and connects to `localhost` or `127.0.0.1`.\n- **Agency:** `agency-hosting_databases_create-website`; the app connects to `localhost`.\n- The `srvNNNN.hstgr.io` host from `hosting_databases_list` is only for connections from outside Hostinger — never put it in the deployed app.\n\n## 7. Verify and record\n\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/\ncurl -s https://DOMAIN/ | grep -o \"TEXT THE PROJECT RENDERS\"\n```\n\nA `200` alone can be a placeholder page; match real copy. A new site may serve a default page briefly — clear it with `hosting_cache_clear-website` and retry before calling the deploy failed.\n\nWrite `.hostinger/site.json` in the project so later runs reuse the target: `{ \"domain\", \"username\" or \"website_uid\", \"type\": \"static\" | \"nodejs\" | \"php\" }`, keeping any fields already there.\n"
|
|
62
62
|
}
|
|
63
63
|
]
|
|
64
64
|
},
|
|
@@ -78,17 +78,17 @@ const skills: Skill[] = [
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"uri": "skill://hostinger-headless/references/DATABASE.md",
|
|
81
|
-
"digest": "sha256:
|
|
82
|
-
"size":
|
|
81
|
+
"digest": "sha256:b0d2d0a893d2f483e9bd961839397fe6dd6011c1b7149bed747bef8ae703b65a",
|
|
82
|
+
"size": 4476,
|
|
83
83
|
"mimeType": "text/markdown",
|
|
84
|
-
"text": "# Database and runtime — MySQL hosts, env vars, and what to poll\n\nUse this when the app needs MySQL, or when a deploy \"succeeded\" but the app cannot reach its database. Everything here uses the **hosting** MCP operations; Agency Plan differences are at the end.\n\n## 1. Create the database\n\n1. `hosting_databases_create` on the site's `username` with a database name, a user and a password you generate — name and user are prefixed with the account username automatically.\n2. Read the full, prefixed `name` and `user` back from `hosting_databases_list`; every other database operation wants the full name.\n3. Do not print the password to the user once it is stored, and never commit it.\n\n## 2. Which host the app connects to\n\n| Where the code runs | Host | Port | Why |\n| --- | --- | --- | --- |\n| PHP on the website | `localhost` or `127.0.0.1` | 3306 | `localhost` uses the MySQL socket; both are granted |\n| Node.js on the website | `127.0.0.1` | 3306 | `localhost` may resolve to IPv6 `::1`, and not every database user has that grant |\n| Outside Hostinger (a laptop, another server) | the `host` from `hosting_databases_list` (`srvNNNN.hstgr.io`) | 3306 | needs `hosting_databases_create-remote-connection` for that client's IP first — never `%`, it opens the database to every address on the internet |\n\nDo not put the remote `host` into the deployed app — it has no grant for connections that come from the server itself.\n\n## 3. Hand credentials to the app\n\n- **Node.js:** environment variables via `hosting_nodejs_replace-environment-variables`. Conventional keys: `DB_HOST=127.0.0.1`, `DB_PORT=3306`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, plus `DATABASE_URL=mysql://USER:PASSWORD@127.0.0.1:3306/NAME` for ORMs that want one string — URL-encode `USER` and `PASSWORD` there (`encodeURIComponent`), or a password containing `@`, `:`, `/` or `#` breaks the URL. The call is a **full replace**: list the current keys with `hosting_nodejs_list-environment-variables` (values come back masked as `********` — never copy those), then send the complete set with real values. Saving restarts the process; frameworks that bake variables into the build (Next.js, `NEXT_PUBLIC_*`) need a new `hosting_nodejs_start-build` afterwards.\n- **PHP:** a config file on the server that the app reads (its own `config.php`, WordPress's `wp-config.php`). Ship it with the deploy, keep it out of git.\n- **Never** in client-side JavaScript, in a committed `.env`, or in chat replies.\n\n## 4. What is asynchronous, and what to poll\n\n| You called | Poll this until | Typical wait |\n| --- | --- | --- |\n| `hosting_websites_create` | `hosting_websites_list-setups` with the domain reports `status: completed` | up to a few minutes |\n| `hosting_deploy
|
|
84
|
+
"text": "# Database and runtime — MySQL hosts, env vars, and what to poll\n\nUse this when the app needs MySQL, or when a deploy \"succeeded\" but the app cannot reach its database. Everything here uses the **hosting** MCP operations; Agency Plan differences are at the end.\n\n## 1. Create the database\n\n1. `hosting_databases_create` on the site's `username` with a database name, a user and a password you generate — name and user are prefixed with the account username automatically.\n2. Read the full, prefixed `name` and `user` back from `hosting_databases_list`; every other database operation wants the full name.\n3. Do not print the password to the user once it is stored, and never commit it.\n\n## 2. Which host the app connects to\n\n| Where the code runs | Host | Port | Why |\n| --- | --- | --- | --- |\n| PHP on the website | `localhost` or `127.0.0.1` | 3306 | `localhost` uses the MySQL socket; both are granted |\n| Node.js on the website | `127.0.0.1` | 3306 | `localhost` may resolve to IPv6 `::1`, and not every database user has that grant |\n| Outside Hostinger (a laptop, another server) | the `host` from `hosting_databases_list` (`srvNNNN.hstgr.io`) | 3306 | needs `hosting_databases_create-remote-connection` for that client's IP first — never `%`, it opens the database to every address on the internet |\n\nDo not put the remote `host` into the deployed app — it has no grant for connections that come from the server itself.\n\n## 3. Hand credentials to the app\n\n- **Node.js:** environment variables via `hosting_nodejs_replace-environment-variables`. Conventional keys: `DB_HOST=127.0.0.1`, `DB_PORT=3306`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, plus `DATABASE_URL=mysql://USER:PASSWORD@127.0.0.1:3306/NAME` for ORMs that want one string — URL-encode `USER` and `PASSWORD` there (`encodeURIComponent`), or a password containing `@`, `:`, `/` or `#` breaks the URL. The call is a **full replace**: list the current keys with `hosting_nodejs_list-environment-variables` (values come back masked as `********` — never copy those), then send the complete set with real values. Saving restarts the process; frameworks that bake variables into the build (Next.js, `NEXT_PUBLIC_*`) need a new `hosting_nodejs_start-build` afterwards.\n- **PHP:** a config file on the server that the app reads (its own `config.php`, WordPress's `wp-config.php`). Ship it with the deploy, keep it out of git.\n- **Never** in client-side JavaScript, in a committed `.env`, or in chat replies.\n\n## 4. What is asynchronous, and what to poll\n\n| You called | Poll this until | Typical wait |\n| --- | --- | --- |\n| `hosting_websites_create` | `hosting_websites_list-setups` with the domain reports `status: completed` | up to a few minutes |\n| `hosting_deploy` of a Node.js app | `hosting_get-deployment` reports a `completed` or `failed` build | minutes |\n| `hosting_nodejs_start-build` (hosted server, which has no `hosting_deploy`) | `hosting_nodejs_build` state is `completed` or `failed` | minutes |\n| `wordpress_installations_install`, plugin/theme/core jobs | `wordpress_installations_list` lists the install | 1–2 minutes |\n| `hosting_databases_repair`, `hosting_websites_delete` | nothing to poll — runs in the background | minutes |\n| `agency-hosting_website-setups_create` | `agency-hosting_website-setups_status` with `setup_uuid` is `completed` | minutes |\n\nPoll with backoff (a few seconds, then tens of seconds). A queued response is not a failure, and re-sending the write does not speed it up.\n\n## 5. When the app is up but broken\n\n- Build failed: `hosting_get-deployment` returns the logs and a diagnosis together (hosted server: `hosting_nodejs_build-logs` for the raw log, `hosting_nodejs_analyse-failed-build` for a diagnosis).\n- Build passed, app errors: `hosting_nodejs_runtime-logs` with a `period` such as `1h`; entries before `last_deployed_at` belong to the previous deploy.\n- `Access denied for user 'x'@'::1'`: the app used `localhost` from Node.js — set `DB_HOST` to `127.0.0.1`.\n- PHP limits (memory, upload size): `hosting_php_get`, then `hosting_php_update-options`.\n\n## Agency Plan websites (`agency-hosting_*`)\n\n`agency-hosting_databases_create-website` creates the database and its single user; the user is granted on `localhost`, so the PHP app connects to `localhost`. Deploys are synchronous there — `agency-hosting_deploy-php-application` returns when the site is live. Other jobs (SSL, backups) show up in `agency-hosting_websites_list-processes`.\n"
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
"uri": "skill://hostinger-headless/references/DEPLOYMENT.md",
|
|
88
|
-
"digest": "sha256:
|
|
89
|
-
"size":
|
|
88
|
+
"digest": "sha256:65a47de1a56ed42d1821169330237b9d715505adfb7bf312342918181d889a9f",
|
|
89
|
+
"size": 3384,
|
|
90
90
|
"mimeType": "text/markdown",
|
|
91
|
-
"text": "# Deployment — getting the build live\n\nMatch the deploy method to what the project actually is — this is the single most common failure point.\n\
|
|
91
|
+
"text": "# Deployment — getting the build live\n\nMatch the deploy method to what the project actually is — this is the single most common failure point.\n\nOn the local `hostinger-api-mcp` server one operation does every deploy: `hosting_deploy` with `domain` and `path` (the project directory; it detects the type, packs the files itself; it skips `node_modules`, `.git` and `.env` files, reporting the `.env` ones as `skippedFiles` (set their values with `hosting_nodejs_replace-environment-variables`); it does not read `.gitignore`, so keep build output out of the directory) or `git: { repository, branch }` with `type: \"static\"` or `\"nodejs\"` (a new site is not yet detected as Node.js). It reads files from this machine, so the hosted server (`mcp.hostinger.com`) does not have it: there, upload the files and deploy from the upload as described in the `deploy-to-hosting` skill (\"Without the local deploy operations\"). Agency Plan sites deploy through the Agency operations listed there as well.\n\n## Static site → `hosting_deploy` (detected as `static`)\n\nFor pre-built files only: plain HTML/CSS/JS, or the **build output** of a framework (run the build locally first, then pass the output directory as `path`).\n\n- `index.html` must be at the **root** of that directory — not nested inside a folder.\n- Deployment is effectively immediate — verify right after.\n\n## Node.js app → `hosting_deploy` (detected as `nodejs`)\n\nFor anything that needs a server or a server-side build (Express, Next.js, NestJS, SSR frameworks). Pass the project's **source** directory, not the output: the install and build run on Hostinger.\n\n- The call returns a `buildUuid` and the build runs on the server. Track it with `hosting_get-deployment` (`domain`) until `build.state` is `completed` or `failed`; on failure the response carries the logs and an analysis — fix, and deploy again. Poll with backoff: builds take minutes, not seconds.\n- When the framework, output directory or entry file is detected wrong, pass `appType`, `outputDirectory`, `buildScript` or `entryFile` to `hosting_deploy`. A TypeScript or other compiled server app always needs `entryFile` set to the built file (for example `dist/server.js`).\n\n## WordPress → `hosting_deploy` with `type: \"wordpress-site\"` / plugin & theme directories\n\nOnly when the user explicitly wants a WordPress *site* migrated or themed. A site import takes the site directory plus `databaseDump` (a `.sql` file) and can run for several minutes; a plugin or theme directory is detected from its header (`activate: true` activates a theme). (WordPress as a headless content backend behind an agent-built frontend is a different flow — that's `WORDPRESS.md`, installed fresh via the API, not imported here.)\n\n## Verify (every deploy)\n\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" https://YOURDOMAIN/\ncurl -s https://YOURDOMAIN/ | grep -o \"SOME_REAL_HEADLINE_TEXT\"\n```\n\nReplace the grep target with copy you actually rendered — a 200 alone can be a placeholder page. A freshly created site may serve a default page for a short while; if content doesn't match, clear the cache (`hosting_cache_clear-website`) and retry before assuming the deploy failed. For store runs, also run the checkout verification in `STORE.md`.\n\nWhen the site is live, report the URL and remind the user the site is managed from hPanel (https://hpanel.hostinger.com).\n"
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"uri": "skill://hostinger-headless/references/SETUP.md",
|
|
@@ -138,10 +138,10 @@ const skills: Skill[] = [
|
|
|
138
138
|
"resources": [
|
|
139
139
|
{
|
|
140
140
|
"uri": "skill://migrate-to-hosting/SKILL.md",
|
|
141
|
-
"digest": "sha256:
|
|
142
|
-
"size":
|
|
141
|
+
"digest": "sha256:b0074ad1de43e13d30306d67952000cd518b704e0c8e2be0384b9f4b15fbf485",
|
|
142
|
+
"size": 7399,
|
|
143
143
|
"mimeType": "text/markdown",
|
|
144
|
-
"text": "---\nname: migrate-to-hosting\ndescription: \"Move an existing website from another host to Hostinger web hosting (Shared, Cloud or Agency plans) without downtime: WordPress sites from a files archive and SQL dump, static and PHP sites from an archive, Node.js apps from source. Creates the website on the real domain, imports files and database, tests the copy before any DNS change, then switches the domain and SSL. Triggers: migrate my site to Hostinger, move my website from another host, transfer my WordPress site, import my website, switch hosting to Hostinger.\"\n---\n\n# Migrate to hosting\n\nThe old host keeps serving the site until the copy on Hostinger is proven to work. DNS moves last.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"import wordpress\").\n- Batch reads with `multi-execute`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting`, `domains` and `dns` as separate servers.\n- Imports and deploys overwrite the target website's contents; confirm the target before each one.\n\n## 1. What is being moved\n\nEstablish, asking only for what cannot be inferred:\n\n- **Site type:** WordPress, static, PHP (with or without MySQL), or Node.js.\n- **The export:**\n - WordPress — an archive of the whole WordPress root (including `wp-content` and `wp-config.php`) and a `.sql` dump.\n - PHP — a files archive, plus a `.sql` dump when the app has a database.\n - Static — the files. Node.js — the source or its Git repository.\n - Without one, the user exports it from the old host's panel, or over SSH: `tar -czf site.tar.gz -C /path/to/site .` and `mysqldump --single-transaction -u USER -p DBNAME > db.sql`.\n- **The exact home URL** (`https`, with or without `www`) — WordPress keeps it in the database, so the new site must answer on the same one.\n- **Current DNS**, to preserve what already works:\n\n```bash\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short MX DOMAIN; dig +short TXT DOMAIN\n```\n\n- **Cron jobs** on the old host — they do not move with the files.\n\n## 2. Create the website on the real domain\n\nCreate the Hostinger website on the domain being migrated, not on a free subdomain: step 4 tests it by pointing only this machine at Hostinger, so nothing changes for visitors yet.\n\n- Shared and Cloud: `hosting_domains_verify-ownership` first. When `is_accessible` is false, the user adds the returned `TXT` record at their current DNS provider, next to the existing ones, and verification is repeated. Then `hosting_websites_create` with `domain` and `order_id` (from `hosting_orders_list`), and poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed`.\n- Agency: `agency-hosting_website-setups_create` with the `domain`, `flavor: \"php-fpm\"`, a `settings.php.version` matching the old host (options in `agency-hosting_php_list-versions-for-order`) and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed` for the `website_uid`.\n\n## 3. Import\n\n`
|
|
144
|
+
"text": "---\nname: migrate-to-hosting\ndescription: \"Move an existing website from another host to Hostinger web hosting (Shared, Cloud or Agency plans) without downtime: WordPress sites from a files archive and SQL dump, static and PHP sites from an archive, Node.js apps from source. Creates the website on the real domain, imports files and database, tests the copy before any DNS change, then switches the domain and SSL. Triggers: migrate my site to Hostinger, move my website from another host, transfer my WordPress site, import my website, switch hosting to Hostinger.\"\n---\n\n# Migrate to hosting\n\nThe old host keeps serving the site until the copy on Hostinger is proven to work. DNS moves last.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"import wordpress\").\n- Batch reads with `multi-execute`. Batches chain operations from one server only — the Hostinger Connector runs `hosting`, `wordpress`, `agency-hosting`, `domains` and `dns` as separate servers.\n- Imports and deploys overwrite the target website's contents; confirm the target before each one.\n\n## 1. What is being moved\n\nEstablish, asking only for what cannot be inferred:\n\n- **Site type:** WordPress, static, PHP (with or without MySQL), or Node.js.\n- **The export:**\n - WordPress — an archive of the whole WordPress root (including `wp-content` and `wp-config.php`) and a `.sql` dump.\n - PHP — a files archive, plus a `.sql` dump when the app has a database.\n - Static — the files. Node.js — the source or its Git repository.\n - Without one, the user exports it from the old host's panel, or over SSH: `tar -czf site.tar.gz -C /path/to/site .` and `mysqldump --single-transaction -u USER -p DBNAME > db.sql`.\n- **The exact home URL** (`https`, with or without `www`) — WordPress keeps it in the database, so the new site must answer on the same one.\n- **Current DNS**, to preserve what already works:\n\n```bash\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short MX DOMAIN; dig +short TXT DOMAIN\n```\n\n- **Cron jobs** on the old host — they do not move with the files.\n\n## 2. Create the website on the real domain\n\nCreate the Hostinger website on the domain being migrated, not on a free subdomain: step 4 tests it by pointing only this machine at Hostinger, so nothing changes for visitors yet.\n\n- Shared and Cloud: `hosting_domains_verify-ownership` first. When `is_accessible` is false, the user adds the returned `TXT` record at their current DNS provider, next to the existing ones, and verification is repeated. Then `hosting_websites_create` with `domain` and `order_id` (from `hosting_orders_list`), and poll `hosting_websites_list-setups` with `domain` every 10–15 s until `status: completed`.\n- Agency: `agency-hosting_website-setups_create` with the `domain`, `flavor: \"php-fpm\"`, a `settings.php.version` matching the old host (options in `agency-hosting_php_list-versions-for-order`) and `datacenter_code` from `agency-hosting_datacenters_list`. Poll `agency-hosting_website-setups_status` until `completed` for the `website_uid`.\n\n## 3. Import\n\n`hosting_deploy` and `agency-hosting_deploy-php-application` read files from this machine and exist only in the local `hostinger-api-mcp` server. On the hosted server (`mcp.hostinger.com`), upload the files first as described in the `deploy-to-hosting` skill (\"Without the local deploy operations\") and use the operation named in brackets below.\n\n**WordPress, Shared and Cloud:** `hosting_deploy` with `domain`, `path` (the site directory or its archive), `databaseDump` and `type: \"wordpress-site\"` uploads both, extracts the files and imports the database; large sites take several minutes. Always pass `type`: left to detection, a directory without `wp-config.php` or `wp-content` at its top level is taken for a plain site and the dump is not imported. [Upload `site.zip` and `dump.sql`, then `wordpress_installations_import-website` with `archive_path` and `sql_path`.] Then `wordpress_installations_detect` with `username` and poll `wordpress_installations_list` with `domain` until the install appears with `is_valid: true`.\n\n**Static, or PHP without a database:** `hosting_deploy` with `domain` and `path` [upload, then `hosting_websites_deploy-static-site-archive`]; Agency: `agency-hosting_deploy-php-application` [upload to `.h5g/`, then `agency-hosting_files_import-website-from-archive`].\n\n**PHP with a database, Shared and Cloud:**\n\n1. `hosting_databases_create` with a strong generated password; read the full name, user and `host` back from `hosting_databases_list`.\n2. Import the dump from this machine: allow only its public IP (`curl -s https://api.ipify.org`) with `hosting_databases_create-remote-connection`, run `mysql -h HOST -u USER -p NAME < db.sql`, then remove the rule with `hosting_databases_delete-remote-connection`. Without a MySQL client, use `hosting_databases_phpmyadmin-link` and import there.\n3. Put the new name, user and password into the app's config file, with host `localhost`, before archiving; then deploy as above. Never ship the `srvNNNN.hstgr.io` host inside the app.\n\n**Node.js:** deploy with the `deploy-to-hosting` skill. When a dump must be imported, create the database with `hosting_databases_create` rather than `hosting_databases_setup-website` — the latter never reveals the password needed for the import — and pass the credentials through environment variables.\n\n**Agency:** files with `agency-hosting_deploy-php-application` [or upload plus `agency-hosting_files_import-website-from-archive`]; the database with `agency-hosting_databases_create-website`, imported through phpMyAdmin in hPanel (no import operation exists). For WordPress, set the new credentials in `wp-config.php` before archiving.\n\n## 4. Test before DNS moves\n\nFind the server address: `details.ipv4` for Agency; for Shared and Cloud, the `A` record for `@` in the Hostinger zone (`dns_records_list` on the domain) or the IP hPanel shows for the website. Then point only this machine at it:\n\n```bash\ncurl -sSk --resolve DOMAIN:443:IP -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/\ncurl -sSk --resolve DOMAIN:443:IP https://DOMAIN/ | grep -o \"TEXT FROM THE LIVE SITE\"\ncurl -sSk --resolve DOMAIN:443:IP -o /dev/null -w \"%{http_code}\\n\" https://DOMAIN/wp-login.php\n```\n\n`-k` is expected here: the certificate for the domain can only be issued after DNS moves. Check the home page, an inner page and, for WordPress, the login page. For a look in the browser, the user adds `IP DOMAIN www.DOMAIN` to their hosts file and removes it afterwards. Fix anything broken now, while visitors still see the old site.\n\n## 5. Switch DNS and SSL\n\nFollow the `connect-domain` skill from its DNS step: keep every `MX` and `TXT` record from step 1, then install SSL once the domain resolves to Hostinger. When the user controls the old DNS, lowering the TTL of the `A` records to 300 a day ahead shortens the switch.\n\n## 6. After the switch\n\n- Verify without `--resolve`: `curl -sSI https://DOMAIN/` shows `platform: hostinger`.\n- Recreate the old host's cron jobs with `hosting_cron-jobs_create` (Agency: `agency-hosting_cron-jobs_create-website`).\n- Keep the old hosting running for a few days — some resolvers still cache the old address, and email hosted there must be moved separately.\n"
|
|
145
145
|
}
|
|
146
146
|
]
|
|
147
147
|
},
|
|
@@ -154,10 +154,10 @@ const skills: Skill[] = [
|
|
|
154
154
|
"resources": [
|
|
155
155
|
{
|
|
156
156
|
"uri": "skill://troubleshoot-website/SKILL.md",
|
|
157
|
-
"digest": "sha256:
|
|
158
|
-
"size":
|
|
157
|
+
"digest": "sha256:bd75940c8fd84f9b67d392063203761a2903108be0117602588e92051a87ea56",
|
|
158
|
+
"size": 9790,
|
|
159
159
|
"mimeType": "text/markdown",
|
|
160
|
-
"text": "---\nname: troubleshoot-website\ndescription: \"Diagnose and fix a website on Hostinger web hosting (Shared, Cloud or Agency plans) that is down, slow, erroring, insecure or failing to build. Checks the site from outside, reads builds, runtime logs, WordPress health, SSL, cache and PHP settings through the Hostinger MCP, names the cause with evidence, and applies the fix once the user agrees. Triggers: my site is down, site not loading, 500 / 502 / 503 error, white screen, error establishing a database connection, site is slow, SSL or certificate warning, not secure, changes not showing, Node.js build failed, app keeps crashing.\"\n---\n\n# Troubleshoot a website\n\nOne website and one symptom in; a named cause, the evidence for it, and a fix out. Stay read-only until the cause is stated and the user agrees to the fix.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute` and pass values between steps with `$steps.<i>.<path>`, e.g. `\"$steps.0.data.0.username\"`. A batch stops at its first failure.\n- The Hostinger Connector runs each product as its own MCP server (`hosting`, `wordpress`, `agency-hosting`, `domains`, `dns`), so a batch can only chain operations from one server. When `search` cannot find an operation, that product group is switched off in the Connector — ask the user to enable it.\n\n## 1. Find the website\n\nRun both lookups, and keep the result for every later call:\n\n- `hosting_websites_list` with `domain` — Shared and Cloud plans. The filter is a substring match, so take the entry whose `domain` is exactly the one asked about. Keep `username`, `order_id` and `website_type`; every `hosting_*` and `wordpress_*` call is keyed on `username` + `domain`.\n- `agency-hosting_websites_list-plan` with `domain` — Agency Plan. Keep `details.uid` (the `website_uid` of every `agency-hosting_*` call), `details.type`, `details.ipv4` and `details.domains`.\n\nNeither finds it: the domain is not a website on this account — say so and show where it points (step 2).\n\n## 2. Look at it from outside\n\nRun these alongside step 1:\n\n```bash\ncurl -sS -o /dev/null -w \"%{http_code} ttfb=%{time_starttransfer}s %{redirect_url}\\n\" https://DOMAIN/\ncurl -sSI https://DOMAIN/\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short CAA DOMAIN\n```\n\n- Hostinger responses carry `platform: hostinger` and `panel: hpanel`. Without them, or with DNS pointing elsewhere, traffic is not reaching this hosting — hand over to the `connect-domain` skill.\n- Certificate or TLS errors → [SSL](#ssl).\n- `5xx`, a blank page or an error page → [By website type](#3-by-website-type).\n- `200` with old content → cache: `hosting_cache_clear-website` (also purges the Hostinger CDN; pass `directory` for WordPress in a subfolder), plus `wordpress_litespeed-cache_purge-lite-speed` for WordPress; Agency: `agency-hosting_cache_clear-website`.\n- Slow first byte → [Slow site](#slow-site). Behind the Hostinger CDN, `x-hcdn-upstream-rt` is the origin's own response time in seconds; a small value there means the server is not the bottleneck.\n\n## 3. By website type\n\n`website_type` (Shared/Cloud) or `details.type` (Agency) picks the branch. `builder` and `horizons` sites are not managed by these operations — send the user to hPanel.\n\n### Node.js (`nodejs`)\n\nBatch `
|
|
160
|
+
"text": "---\nname: troubleshoot-website\ndescription: \"Diagnose and fix a website on Hostinger web hosting (Shared, Cloud or Agency plans) that is down, slow, erroring, insecure or failing to build. Checks the site from outside, reads builds, runtime logs, WordPress health, SSL, cache and PHP settings through the Hostinger MCP, names the cause with evidence, and applies the fix once the user agrees. Triggers: my site is down, site not loading, 500 / 502 / 503 error, white screen, error establishing a database connection, site is slow, SSL or certificate warning, not secure, changes not showing, Node.js build failed, app keeps crashing.\"\n---\n\n# Troubleshoot a website\n\nOne website and one symptom in; a named cause, the evidence for it, and a fix out. Stay read-only until the cause is stated and the user agrees to the fix.\n\n## Calling the operations\n\n- Read the `inputSchema` that `search` returns before the first call of each operation. If a name below is rejected as unknown, `search` for what the step does (e.g. \"ssl status\").\n- Batch reads with `multi-execute` and pass values between steps with `$steps.<i>.<path>`, e.g. `\"$steps.0.data.0.username\"`. A batch stops at its first failure.\n- The Hostinger Connector runs each product as its own MCP server (`hosting`, `wordpress`, `agency-hosting`, `domains`, `dns`), so a batch can only chain operations from one server. When `search` cannot find an operation, that product group is switched off in the Connector — ask the user to enable it.\n\n## 1. Find the website\n\nRun both lookups, and keep the result for every later call:\n\n- `hosting_websites_list` with `domain` — Shared and Cloud plans. The filter is a substring match, so take the entry whose `domain` is exactly the one asked about. Keep `username`, `order_id` and `website_type`; every `hosting_*` and `wordpress_*` call is keyed on `username` + `domain`.\n- `agency-hosting_websites_list-plan` with `domain` — Agency Plan. Keep `details.uid` (the `website_uid` of every `agency-hosting_*` call), `details.type`, `details.ipv4` and `details.domains`.\n\nNeither finds it: the domain is not a website on this account — say so and show where it points (step 2).\n\n## 2. Look at it from outside\n\nRun these alongside step 1:\n\n```bash\ncurl -sS -o /dev/null -w \"%{http_code} ttfb=%{time_starttransfer}s %{redirect_url}\\n\" https://DOMAIN/\ncurl -sSI https://DOMAIN/\ndig +short NS DOMAIN; dig +short A DOMAIN; dig +short CAA DOMAIN\n```\n\n- Hostinger responses carry `platform: hostinger` and `panel: hpanel`. Without them, or with DNS pointing elsewhere, traffic is not reaching this hosting — hand over to the `connect-domain` skill.\n- Certificate or TLS errors → [SSL](#ssl).\n- `5xx`, a blank page or an error page → [By website type](#3-by-website-type).\n- `200` with old content → cache: `hosting_cache_clear-website` (also purges the Hostinger CDN; pass `directory` for WordPress in a subfolder), plus `wordpress_litespeed-cache_purge-lite-speed` for WordPress; Agency: `agency-hosting_cache_clear-website`.\n- Slow first byte → [Slow site](#slow-site). Behind the Hostinger CDN, `x-hcdn-upstream-rt` is the origin's own response time in seconds; a small value there means the server is not the bottleneck.\n\n## 3. By website type\n\n`website_type` (Shared/Cloud) or `details.type` (Agency) picks the branch. `builder` and `horizons` sites are not managed by these operations — send the user to hPanel.\n\n### Node.js (`nodejs`)\n\nBatch `hosting_get-deployment` (the latest build with its log, failure analysis and stored settings), `hosting_nodejs_runtime-logs` (`period: \"1h\"`, `levels: [\"ERROR\", \"WARN\"]`) and `hosting_nodejs_list-environment-variables` (keys only; values always come back masked). On the hosted server, which has no `hosting_get-deployment`, use `hosting_nodejs_list-builds` (`per_page: 3`) in its place.\n\n- Latest build `failed`: `hosting_get-deployment` already holds the `analysis` (fetched once per build — the API re-runs it on every call and allows 5 a minute). A wrongly detected framework, output directory or missing `entry_file` is the usual cause: compare the returned `buildSettings` with the project and deploy again with corrected `appType`, `outputDirectory`, `buildScript` or `entryFile`; a Git deploy stores them, so pushes build correctly too. On the hosted server: `hosting_nodejs_analyse-failed-build` once for that build, then `hosting_nodejs_build-logs`; compare `hosting_nodejs_build-settings`, rebuild through `hosting_nodejs_start-build` and store the values with `hosting_nodejs_update-build-settings`.\n- Build `completed` but the app errors: read the runtime logs; entries older than `last_deployed_at` belong to the previous deploy. A variable the code reads but the key list lacks is fixed with the `deploy-to-hosting` skill's environment step. `Access denied for user '…'@'::1'` means the app connects to `localhost` — `DB_HOST` must be `127.0.0.1`.\n- Hung process: `hosting_nodejs_restart-application` (restarts without rebuilding).\n\n### WordPress (`wordpress`)\n\n`wordpress_installations_list` with `username` and `domain` gives the install `id` — the `software` parameter of every `wordpress_*` call. Batch `wordpress_installations_check-if-are-valid` (`software_ids: [id]`, `force: true`), `wordpress_plugins_list-installed` and `wordpress_maintenance_show-status`.\n\n- Invalid install: `validation_error` names the problem.\n- Broken after a plugin or theme change: deactivate suspects one at a time with `wordpress_plugins_deactivate` (queued — allow a few seconds), re-run the step 2 check after each, and reactivate with `wordpress_plugins_activate` any that were not the cause.\n- Maintenance page stuck: `wordpress_maintenance_toggle` with `enabled: false`.\n- \"Error establishing a database connection\": `hosting_databases_list` with `domain`; corrupted tables are fixed by `hosting_databases_repair` (runs in the background). `wp-config.php` cannot be read through the API because files with secrets are refused — for credential checks hand the user `hosting_databases_phpmyadmin-link`.\n- Memory or upload-size errors → [PHP](#php).\n\n### Static or PHP (`other`)\n\n- `403` or `404` at `/`: `hosting_files_list-website-and-directories` with `max_depth: 1`. `index.html` or `index.php` must sit at the document root; finding it one folder down means the archive was packed a level too deep — redeploy it flat with the `deploy-to-hosting` skill.\n- Read `.htaccess` or other config with `hosting_files_website-content`.\n- PHP errors → [PHP](#php).\n\n### PHP\n\n`hosting_php_get` returns every extension and option (around 25 KB), so call it only for PHP problems. `hosting_php_update-version` switches versions. `hosting_php_update-options` silently caps values at the plan maximum (`max` in `hosting_php_get`), so read the applied value back. Agency: `agency-hosting_php_list-options-for-website`, then `agency-hosting_php_replace-website-options` — a full replace, so send every custom option that should stay.\n\n### Agency Plan sites\n\n`agency-hosting_websites_get` shows state and quotas, `agency-hosting_websites_list-processes` shows failed jobs (SSL setup, backups), and `agency-hosting_wordpress_settings` shows core version, LiteSpeed, object cache and maintenance mode. When `wordpress_installations_list` does not return the site, plugins are managed from wp-admin.\n\n## SSL\n\nShared and Cloud, `hosting_ssl_status`:\n\n- `not_installed` or `failed` (`last_error` says why): the domain must resolve to Hostinger, and any CAA record must allow `letsencrypt.org`, before `hosting_ssl_install` can succeed. Poll the status until `active` or `failed`.\n- `installing` or `waiting_for_retry`: wait — another install request returns 422.\n- Free `*.hostingersite.com` subdomains use a platform certificate; installing returns 422 by design.\n- Browser still warns while the certificate is `active`: turn on the redirect with `hosting_ssl_toggle-https-redirect` when `is_https_redirect_enabled` is false, otherwise the page loads `http://` assets (mixed content) that the app has to change.\n\nAgency, `agency-hosting_ssl_website-status` for each domain: every domain allows three certificate setups per seven days and one request a minute. Check `agency-hosting_websites_list-processes` before `agency-hosting_ssl_install-website` or `agency-hosting_ssl_reinstall-website`, and never retry in a loop.\n\n## Slow site\n\n- WordPress: `wordpress_litespeed-cache_show-lite-speed-status` and `wordpress_object-cache_show-memcached-status`. Turning on Memcached with `wordpress_object-cache_toggle-memcached` is the usual quick win.\n- Other sites: server caching may be off or development mode left on, and neither has a read operation. `hosting_cache_toggle-website` with `enabled: true` does nothing when caching is already on; `hosting_cache_toggle-cacheless` with `enabled: false` turns development mode off.\n- PHP 7.x runs markedly slower than 8.x; propose a supported 8.x version from `hosting_php_get` when the app allows it.\n- Agency: `agency-hosting_metrics_list-order-resource-usage` with `time_frame_hours: 24` shows CPU, memory and processes per website against the plan quota.\n- Shared and Cloud have no CPU or memory metrics in the API. When the evidence points at resource limits, send the user to hPanel's resource usage page.\n\n## Apply the fix\n\nState the cause, the evidence and the single change proposed, and make it only after the user agrees. Then re-run the step 2 check, polling any queued job first, to show the symptom is gone. When the fix needs something the API cannot do, say so and name the hPanel page.\n\n## Not available through the API\n\n- Website backups and restores — hPanel's Backups page.\n- CPU, memory and process usage for Shared and Cloud plans.\n- PHP error and access logs.\n"
|
|
161
161
|
}
|
|
162
162
|
]
|
|
163
163
|
}
|