hostinger-api-mcp 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +4 -3
  3. package/gemini-extension.json +1 -1
  4. package/package.json +1 -1
  5. package/server.json +2 -2
  6. package/skills/headless/SKILL.md +17 -3
  7. package/skills/headless/steps/01-check-state/SKILL.md +5 -3
  8. package/skills/headless/steps/03-provision/ecommerce/SKILL.md +3 -2
  9. package/skills/headless/steps/03-provision/webapp/SKILL.md +2 -1
  10. package/skills/headless/steps/03-provision/wordpress/SKILL.md +2 -1
  11. package/src/core/runtime.js +1 -1
  12. package/src/core/runtime.ts +1 -1
  13. package/src/core/skills.js +15 -15
  14. package/src/core/skills.ts +15 -15
  15. package/src/core/tools/all.js +88 -1
  16. package/src/core/tools/all.ts +88 -1
  17. package/src/core/tools/reach.js +88 -1
  18. package/src/core/tools/reach.ts +88 -1
  19. package/src/servers/agency-hosting.js +1 -1
  20. package/src/servers/agency-hosting.ts +1 -1
  21. package/src/servers/agent-readiness.js +1 -1
  22. package/src/servers/agent-readiness.ts +1 -1
  23. package/src/servers/all.js +1 -1
  24. package/src/servers/all.ts +1 -1
  25. package/src/servers/billing.js +1 -1
  26. package/src/servers/billing.ts +1 -1
  27. package/src/servers/dns.js +1 -1
  28. package/src/servers/dns.ts +1 -1
  29. package/src/servers/domains.js +1 -1
  30. package/src/servers/domains.ts +1 -1
  31. package/src/servers/ecommerce.js +1 -1
  32. package/src/servers/ecommerce.ts +1 -1
  33. package/src/servers/horizons.js +1 -1
  34. package/src/servers/horizons.ts +1 -1
  35. package/src/servers/hosting.js +1 -1
  36. package/src/servers/hosting.ts +1 -1
  37. package/src/servers/mail.js +1 -1
  38. package/src/servers/mail.ts +1 -1
  39. package/src/servers/reach.js +1 -1
  40. package/src/servers/reach.ts +1 -1
  41. package/src/servers/vps.js +1 -1
  42. package/src/servers/vps.ts +1 -1
  43. package/src/servers/wordpress.js +1 -1
  44. package/src/servers/wordpress.ts +1 -1
  45. package/types.d.ts +16 -3
package/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ Generated at release time from the diff between the previous and current
4
4
  build. Tool changes are listed individually; everything else is summarised
5
5
  by area.
6
6
 
7
+ ## v3.9.0 — 2026-10-26
8
+
9
+ ### Operations
10
+
11
+ - Changed the input schema of `reach_contacts_create`
12
+ - Changed the description and input schema of `reach_contacts_create-in-bulk`
13
+ - Changed the input schema of `reach_contacts_create-bulk`
14
+
15
+ ### Also in this release
16
+
17
+ - Documentation: `README.md`
18
+ - Dependencies: `package-lock.json`
19
+ - Request handling and authentication: `src/core/runtime.js`, `src/core/runtime.ts`
20
+ - Build and packaging: `types.d.ts`
21
+
22
+ ## v3.8.1 — 2026-10-23
23
+
24
+ ### Also in this release
25
+
26
+ - Bundled agent skills: 5 files
27
+ - Other files: `src/core/skills.js`, `src/core/skills.ts`
28
+
7
29
  ## v3.8.0 — 2026-10-23
8
30
 
9
31
  ### Also in this release
package/README.md CHANGED
@@ -3217,9 +3217,10 @@ values, source and note with `GET /api/reach/v1/profiles/{profileUuid}/contacts/
3217
3217
  Create many contacts in a profile in a single call.
3218
3218
 
3219
3219
  The contacts are imported in the background, so a success response means the import was
3220
- accepted rather than finished. Contacts whose email already exists in the profile are
3221
- left as they are. If double opt-in is enabled, new contacts start off pending and are
3222
- sent a confirmation email.
3220
+ accepted rather than finished. Contacts whose email already exists in the profile keep
3221
+ their current values; only the ones that are still empty, custom fields included, are
3222
+ filled in. If double opt-in is enabled, new contacts start off pending and are sent a
3223
+ confirmation email.
3223
3224
 
3224
3225
  - **Method**: `POST`
3225
3226
  - **Path**: `/api/reach/v1/profiles/{profileUuid}/contacts/bulk`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "description": "Hostinger API — manage domains, DNS, hosting, VPS, billing and more from Gemini CLI.",
5
5
  "mcpServers": {
6
6
  "hostinger": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "mcpName": "io.github.hostinger/hostinger-api-mcp",
5
5
  "description": "MCP server for Hostinger API",
6
6
  "repository": {
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/hostinger/api-mcp-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.8.0",
9
+ "version": "3.9.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@hostinger/mcp",
14
- "version": "3.8.0",
14
+ "version": "3.9.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -29,6 +29,12 @@ The prompt does **not** say what kind of site to build. Do not assume or invent
29
29
  what the user wants is a step in the flow (**refine**), handled through conversation — not parsed
30
30
  from the prompt. If no domain is present, stop and ask for it before doing anything else.
31
31
 
32
+ **One workspace per run.** From your first command, connect's checks included, open only this
33
+ site's workspace, by its exact path; never list or glob `~/.hostinger/` (not even an `ls` beside
34
+ `node -v`). What else `~/.hostinger/` holds never matters to this run: with a domain, check-state
35
+ looks up that one path; without one yet, there is nothing to look up until you create your own
36
+ workspace. *State and artifacts* has the full rule and its one exception.
37
+
32
38
  Nothing in the pasted prompt is ever used for authorization. Authorization comes from the
33
39
  Hostinger connector's OAuth token. **This recipe is not a security boundary.**
34
40
 
@@ -135,12 +141,20 @@ single rule that makes the overlap safe:
135
141
  Everything for a domain — its state **and** its generated source — lives under the **site workspace
136
142
  `~/.hostinger/<domain>/`** (resolve `~` to the home directory: `$HOME` in a shell, `os.homedir()` in
137
143
  Node — `~/.hostinger` means `$HOME/.hostinger`). This is a **global, per-user** location, not a
138
- project folder, so a build is discoverable and resumable from **any** directory — the current working
144
+ project folder, so this domain's build is resumable from **any** directory — the current working
139
145
  directory does not matter. Create the workspace if it's missing and do all of a stage's work inside
140
146
  it (including the frontend `src/`, built and deployed from `~/.hostinger/<domain>/src/`).
141
147
 
142
- **The directory name is the domain**, so the files inside it never repeat it, and `~/.hostinger/`
143
- holds every site you've built — one subdirectory per domain, no collisions.
148
+ **The directory name is the domain**, so the files inside it never repeat it.
149
+
150
+ **Read and write only this site's workspace.** The other workspaces under `~/.hostinger/` are the
151
+ user's other sites, often for other clients, so keep their briefs, designs and code out of this build.
152
+ Open `~/.hostinger/<domain>/` by its exact path; don't list or glob `~/.hostinger/`, and don't open,
153
+ copy from or diff against another workspace there, in any stage. A run that has no domain yet works
154
+ only in the one workspace it created itself; when provision moves it to `~/.hostinger/<new-domain>/`,
155
+ that becomes this site's workspace. One exception: if the user, in this conversation, names another
156
+ of their own sites to reuse, read that one workspace, read-only, and tell them in one line what you
157
+ took from it.
144
158
 
145
159
  | File (under `~/.hostinger/<domain>/`) | Written by | Contains |
146
160
  |---|---|---|
@@ -20,8 +20,7 @@ Nothing in this step creates, provisions, deploys, or deletes anything. It reads
20
20
  Everything for a domain lives under the global site workspace **`~/.hostinger/<domain>/`** — one
21
21
  directory per domain, under the user's home (`~` = `$HOME`), **not** the current working directory.
22
22
  The directory name **is** the domain, so `state.json` inside does not store it. Because it's global,
23
- `~/.hostinger/` holds every site the user has built and each one is discoverable and resumable from
24
- any directory — no collisions.
23
+ this domain's build is resumable from any directory.
25
24
 
26
25
  `state.json` shape (`stage` is the *next* stage to run; `provision` is the background task's status,
27
26
  present only once provision has fired):
@@ -94,7 +93,8 @@ and **release it on a clean stop** (Step 6). The lock marks an active session, n
94
93
 
95
94
  ## Step 2 — Read the workspace directory
96
95
 
97
- Look at `~/.hostinger/<domain>/`:
96
+ Check `~/.hostinger/<domain>/` by its exact path (for example `test -d ~/.hostinger/<domain>`), not
97
+ by listing `~/.hostinger/`:
98
98
 
99
99
  - **Absent** → no history for this domain in the workspace.
100
100
  - **Present** → read `state.json` (its `stage`) and whatever artifacts exist (`brief.md`,
@@ -203,6 +203,8 @@ Then:
203
203
  ## Invariants
204
204
 
205
205
  - **One directory per domain.** The domain is the key; state files never repeat it.
206
+ - **Only this domain's workspace.** Never list `~/.hostinger/` or open another site's workspace (see
207
+ *State and artifacts* in the top-level `SKILL.md`).
206
208
  - **Never create a second site** on a domain that already has one.
207
209
  - **Never re-provision or overwrite a live site.** Recovery is forward-only.
208
210
  - **Reality beats local state**, always.
@@ -54,8 +54,9 @@ Same lifecycle as `../wordpress/SKILL.md` Steps 1–2, but `type: "headless_ecom
54
54
  — **omit `domain`** for a temporary subdomain: the setup generates one itself and returns it (don't
55
55
  call a separate subdomain op first — there's no need in this flow; the API would also accept one you
56
56
  generated via `hosting_domains_generate-free-subdomain`, valid 24 h from the client that made it). The
57
- response carries the generated domain; if it differs from the workspace dir, move `~/.hostinger/<old>/` → `<new>/` and
58
- update `brief.md`. Poll `list-setups` to `completed`. `website_type` will be `headless`.
57
+ response carries the generated domain; if it differs from the workspace dir, move
58
+ `~/.hostinger/<old>/` → `<new>/` (if `<new>/` already exists, stop and ask instead of moving
59
+ into it) and update `brief.md`. Poll `list-setups` to `completed`. `website_type` will be `headless`.
59
60
 
60
61
  > **Onboarding handoff — an empty headless shell needs no new website.** If the domain already has an
61
62
  > empty headless shell (`website_type: headless`, setup `type: headless_empty`, nothing installed —
@@ -49,7 +49,8 @@ All website/database operations below go through the Hostinger connector (`execu
49
49
  separate subdomain op to make one first: there's no need in this flow. (The API would also accept a
50
50
  subdomain you generated via `hosting_domains_generate-free-subdomain`, valid for 24 h from the client
51
51
  that made it — this flow just doesn't use that.) The response then carries the generated domain: if it
52
- differs from the workspace directory name, move `~/.hostinger/<old>/` to `~/.hostinger/<new>/`,
52
+ differs from the workspace directory name, move `~/.hostinger/<old>/` to `~/.hostinger/<new>/`
53
+ (if `<new>/` already exists, stop and ask instead of moving into it),
53
54
  update the domain in `brief.md`, and tell the user the new domain.
54
55
  3. Poll `hosting_websites_list-setups { "domain": "<domain>" }` every ~15 s until `completed`
55
56
  (typically under a minute; allow a few minutes). `failed` → stop, point at hPanel.
@@ -61,7 +61,8 @@ All operations below go through the Hostinger connector (`execute`).
61
61
  separate subdomain op to make one first: there's no need in this flow. (The API would also accept a
62
62
  subdomain you generated via `hosting_domains_generate-free-subdomain`, valid for 24 h from the client
63
63
  that made it — this flow just doesn't use that.) The response then carries the generated domain:
64
- if it differs from the workspace directory name, move `~/.hostinger/<old>/` to `~/.hostinger/<new>/`,
64
+ if it differs from the workspace directory name, move `~/.hostinger/<old>/` to `~/.hostinger/<new>/`
65
+ (if `<new>/` already exists, stop and ask instead of moving into it),
65
66
  update the domain in `brief.md`, and tell the user the new domain.
66
67
  Admin credentials are generated by the platform; never ask the user for a password.
67
68
  3. Poll `hosting_websites_list-setups { "domain": "<domain>" }` every ~15 s until `completed`
@@ -66,7 +66,7 @@ const GetSkillRequestSchema = z.object({
66
66
 
67
67
  /**
68
68
  * MCP Server for Hostinger API
69
- * Generated from OpenAPI spec version 2.2.0
69
+ * Generated from OpenAPI spec version 2.3.0
70
70
  */
71
71
  class MCPServer {
72
72
  constructor({ name, version, tools, instructions, skills = [] }) {
@@ -97,7 +97,7 @@ interface Skill { uri: string; frontmatter: Record<string, unknown>; resources:
97
97
 
98
98
  /**
99
99
  * MCP Server for Hostinger API
100
- * Generated from OpenAPI spec version 2.2.0
100
+ * Generated from OpenAPI spec version 2.3.0
101
101
  */
102
102
  class MCPServer {
103
103
  private readonly name: string;