hostinger-api-mcp 3.30.1 → 3.31.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 (62) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +7 -2
  3. package/gemini-extension.json +2 -1
  4. package/package.json +1 -1
  5. package/server.json +2 -2
  6. package/skills/headless/SKILL.md +7 -5
  7. package/skills/headless/VERSION +3 -3
  8. package/skills/headless/connect/SKILL.md +33 -16
  9. package/skills/headless/connect/bootstrap.mjs +25 -14
  10. package/skills/headless/connect/launch.mjs +42 -0
  11. package/skills/headless/connect/launch.sh +23 -0
  12. package/skills/headless/connect/tools/antigravity.md +5 -5
  13. package/skills/headless/connect/tools/claude-code.md +3 -3
  14. package/skills/headless/connect/tools/codex.md +7 -7
  15. package/skills/headless/connect/tools/cursor.md +9 -9
  16. package/skills/headless/connect/tools/devin.md +5 -5
  17. package/skills/headless/connect/tools/vscode.md +7 -7
  18. package/skills/headless/hostinger-mcp.mjs +4 -9
  19. package/skills/headless/steps/03-provision/ecommerce/SKILL.md +2 -2
  20. package/skills/headless/steps/03-provision/webapp/SKILL.md +1 -1
  21. package/skills/headless/steps/03-provision/wordpress/SKILL.md +2 -2
  22. package/skills/headless/steps/04-content-model/wordpress/SKILL.md +1 -1
  23. package/skills/headless/steps/08-deploy/SKILL.md +3 -3
  24. package/src/core/oauth.js +14 -4
  25. package/src/core/oauth.ts +14 -4
  26. package/src/core/runtime.js +7 -1
  27. package/src/core/runtime.ts +7 -1
  28. package/src/core/skills.js +59 -45
  29. package/src/core/skills.ts +59 -45
  30. package/src/core/tools/all.js +1 -1
  31. package/src/core/tools/all.ts +1 -1
  32. package/src/core/tools/horizons.js +1 -1
  33. package/src/core/tools/horizons.ts +1 -1
  34. package/src/servers/agency-hosting.js +1 -1
  35. package/src/servers/agency-hosting.ts +1 -1
  36. package/src/servers/agent-readiness.js +1 -1
  37. package/src/servers/agent-readiness.ts +1 -1
  38. package/src/servers/all.js +1 -1
  39. package/src/servers/all.ts +1 -1
  40. package/src/servers/billing.js +1 -1
  41. package/src/servers/billing.ts +1 -1
  42. package/src/servers/dns.js +1 -1
  43. package/src/servers/dns.ts +1 -1
  44. package/src/servers/domains.js +1 -1
  45. package/src/servers/domains.ts +1 -1
  46. package/src/servers/ecommerce.js +1 -1
  47. package/src/servers/ecommerce.ts +1 -1
  48. package/src/servers/gpu.js +1 -1
  49. package/src/servers/gpu.ts +1 -1
  50. package/src/servers/horizons.js +1 -1
  51. package/src/servers/horizons.ts +1 -1
  52. package/src/servers/hosting.js +1 -1
  53. package/src/servers/hosting.ts +1 -1
  54. package/src/servers/mail.js +1 -1
  55. package/src/servers/mail.ts +1 -1
  56. package/src/servers/reach.js +1 -1
  57. package/src/servers/reach.ts +1 -1
  58. package/src/servers/vps.js +1 -1
  59. package/src/servers/vps.ts +1 -1
  60. package/src/servers/wordpress.js +1 -1
  61. package/src/servers/wordpress.ts +1 -1
  62. package/types.d.ts +3 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ 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.31.0 — 2026-11-06
8
+
9
+ ### Operations
10
+
11
+ - Changed the description of `horizons_websites_get`
12
+
13
+ ### Also in this release
14
+
15
+ - Documentation: `README.md`
16
+ - Request handling and authentication: `src/core/runtime.js`, `src/core/runtime.ts`
17
+ - Build and packaging: `types.d.ts`
18
+
19
+ ## v3.30.2 — 2026-11-06
20
+
21
+ ### Also in this release
22
+
23
+ - Documentation: `README.md`
24
+ - Distribution manifests: `gemini-extension.json`
25
+ - Bundled agent skills: 18 files
26
+ - OAuth sign-in flow: `src/core/oauth.js`, `src/core/oauth.ts`
27
+ - Request handling and authentication: `src/core/runtime.js`, `src/core/runtime.ts`
28
+ - Other files: `src/core/skills.js`, `src/core/skills.ts`
29
+
7
30
  ## v3.30.1 — 2026-11-05
8
31
 
9
32
  ### Also in this release
package/README.md CHANGED
@@ -133,11 +133,14 @@ hostinger-api-mcp --logout
133
133
 
134
134
  ### JSON configuration for Claude, Cursor, etc.
135
135
 
136
+ Register Node and the server script by absolute path, never `npx` or a bare `node`/`hostinger-api-mcp`: tools start the server in your project, where `npx` puts the project's `node_modules/.bin` first on `PATH`, a version manager (asdf, mise) runs whatever Node the project's `.tool-versions` names, and Windows looks a bare name up in the project folder first. Any of these lets a cloned repository run its own code with your Hostinger credentials. After the global install, `node -p process.execPath` prints the Node path and `npm root -g` the folder that holds `@hostinger/mcp`. Run both from your home folder.
137
+
136
138
  ```json
137
139
  {
138
140
  "mcpServers": {
139
141
  "hostinger-api": {
140
- "command": "hostinger-api-mcp",
142
+ "command": "/absolute/path/to/node",
143
+ "args": ["/absolute/path/to/global/node_modules/@hostinger/mcp/src/servers/all.js"],
141
144
  "env": {
142
145
  "DEBUG": "false",
143
146
  "HOSTINGER_API_TOKEN": "YOUR API TOKEN"
@@ -1907,7 +1910,9 @@ Get the link for the user to open their website in Hostinger Horizons interface.
1907
1910
  Use this tool when the user wants the link to an existing website, or when you need its
1908
1911
  website URL before or after editing it.\n
1909
1912
  `is_in_progress` is true while changes are being generated or the website is being published;
1910
- wait until it is false before publishing. `published_at` is when the website was last published,
1913
+ wait until it is false before publishing. `is_generating` is true while changes are being generated,
1914
+ and `actions_in_progress` has `website_publish` while the website is being published.
1915
+ `published_at` is when the website was last published,
1911
1916
  `is_template` is whether its published pages show the "Use template" banner, and
1912
1917
  `has_ecommerce_store` is whether it has an online store.\n
1913
1918
  Websites can be edited with the `Edit website` tool, or by the user in Hostinger Horizons
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.30.1",
3
+ "version": "3.31.0",
4
4
  "description": "Hostinger API — manage domains, DNS, hosting, VPS, billing and more from Gemini CLI.",
5
5
  "mcpServers": {
6
6
  "hostinger": {
@@ -9,6 +9,7 @@
9
9
  "-y",
10
10
  "@hostinger/mcp"
11
11
  ],
12
+ "cwd": "${extensionPath}",
12
13
  "env": {
13
14
  "HOSTINGER_API_TOKEN": "${HOSTINGER_API_TOKEN}"
14
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.30.1",
3
+ "version": "3.31.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
@@ -17,12 +17,12 @@
17
17
  "url": "https://github.com/hostinger/api-mcp-server",
18
18
  "source": "github"
19
19
  },
20
- "version": "3.30.1",
20
+ "version": "3.31.0",
21
21
  "packages": [
22
22
  {
23
23
  "registryType": "npm",
24
24
  "identifier": "@hostinger/mcp",
25
- "version": "3.30.1",
25
+ "version": "3.31.0",
26
26
  "transport": {
27
27
  "type": "stdio"
28
28
  },
@@ -192,13 +192,15 @@ has usually outlasted the job, so it returns at once. The single rule that makes
192
192
  ### Waiting on Hostinger: `wait.mjs`
193
193
 
194
194
  `wait.mjs` (next to this file) waits for a slow Hostinger job in one command, so you don't spend a turn
195
- on every check:
195
+ on every check. Run it, like `push-content.mjs`, from the home folder (`cd "$HOME" && …`): both
196
+ start the Hostinger MCP server with the user's sign-in, and a version manager's `node` (asdf, mise)
197
+ runs whatever Node the current project's `.tool-versions` names:
196
198
 
197
199
  ```bash
198
- node <skill>/wait.mjs setup <domain> # a fresh site's setup → completed
199
- node <skill>/wait.mjs cms <domain> <username> # a shell swap's WordPress install at /cms → valid
200
- node <skill>/wait.mjs build <domain> <buildUuid> # the deploy build → completed, then the root serves 200
201
- node <skill>/wait.mjs live <domain> # the root serves 200
200
+ cd "$HOME" && node <skill>/wait.mjs setup <domain> # a fresh site's setup → completed
201
+ cd "$HOME" && node <skill>/wait.mjs cms <domain> <username> # a shell swap's WordPress install at /cms → valid
202
+ cd "$HOME" && node <skill>/wait.mjs build <domain> <buildUuid> # the deploy build → completed, then the root serves 200
203
+ cd "$HOME" && node <skill>/wait.mjs live <domain> # the root serves 200
202
204
  ```
203
205
 
204
206
  Run it in the foreground, with a `--timeout` just under your tool's command limit (e.g. `--timeout 9m`
@@ -1,3 +1,3 @@
1
- version=3.30.1
2
- commit=4d02050e3406
3
- built=2026-11-05
1
+ version=3.31.0
2
+ commit=27fa03d3cce1
3
+ built=2026-11-06
@@ -77,10 +77,10 @@ Read `<skill>/VERSION`: its line 1 is the skills version this run uses, which go
77
77
  Run the bundled script. It verifies the MCP server and handles sign-in, emitting one JSON event per line on stdout. Run it as a background/streaming process. Show the user only the sign-in URL (`awaiting_user`) or a
78
78
  failure's `detail`, and handle the other events silently (table below).
79
79
 
80
- The script is safe and inspectable: it only checks the MCP server via `npx` and drives the OAuth sign-in (a browser flow with a localhost callback) — no other network calls, no filesystem writes.
80
+ The script is safe and inspectable: it copies the launcher to `~/.hostinger/mcp/launch.mjs`, checks the MCP server through it and drives the OAuth sign-in (a browser flow with a localhost callback) — no other network calls, no other filesystem writes.
81
81
 
82
82
  ```bash
83
- node <skill>/connect/bootstrap.mjs
83
+ cd "$HOME" && node <skill>/connect/bootstrap.mjs
84
84
  ```
85
85
 
86
86
  ### Relay these events
@@ -89,11 +89,12 @@ The script emits one JSON object per line:
89
89
 
90
90
  | Event | What to do |
91
91
  | --- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
92
+ | `launcher` (`command`, `args`) | How to start the MCP server: use these for every registration (Phase 2). |
92
93
  | `mcp_ok` | MCP server reachable — continue. |
93
94
  | `logged_in` | Already authenticated (env token or a previous sign-in) — continue. |
94
95
  | `awaiting_user` (`verificationUri`) | A browser window should have opened on the user's machine. Show the URL in plain prose and wait for the user to finish signing in. The OAuth callback lands on a localhost port, so the sign-in must be completed on this same machine. |
95
96
  | `success` | Bootstrap done — continue to Phase 2. |
96
- | `mcp_unreachable` / `login_failed` (with `detail`) | Stop and show the user the `detail`. Do not improvise a parallel setup by hand. |
97
+ | `launcher_failed` / `mcp_unreachable` / `login_failed` (with `detail`) | Stop and show the user the `detail`. Do not improvise a parallel setup by hand. |
97
98
 
98
99
  If the environment has a `HOSTINGER_API_TOKEN` set (for example CI), the bootstrap reports `logged_in` immediately — no browser needed.
99
100
 
@@ -107,8 +108,8 @@ hostinger-api-mcp --login
107
108
  hostinger-api-mcp --logout
108
109
 
109
110
  # Without a global install:
110
- npx --yes --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-api-mcp --login
111
- npx --yes --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-api-mcp --logout
111
+ cd "$HOME" && node "$HOME/.hostinger/mcp/launch.mjs" --login
112
+ cd "$HOME" && node "$HOME/.hostinger/mcp/launch.mjs" --logout
112
113
  ```
113
114
 
114
115
  Credentials live in `~/.config/hostinger-mcp/credentials.json` (macOS/Linux) or `%APPDATA%\hostinger-mcp\credentials.json` (Windows) and are shared by every Hostinger MCP binary. OAuth works only when the tool runs the server over its default local (stdio) transport, which is what every registration below uses; `--http` needs `HOSTINGER_API_TOKEN`.
@@ -127,8 +128,8 @@ one group says nothing about the other:
127
128
 
128
129
  | Group | Operations | Comes from | Needed by |
129
130
  |---|---|---|---|
130
- | **Hosting** | `hosting_*` (websites, deploy, build report), `wordpress_*` | `hostinger` (`npx -y --prefix="$HOME" @hostinger/mcp@latest`), or the scoped servers such as `hostinger-hosting` + `hostinger-wordpress` | every build |
131
- | **Ecommerce** | `ecommerce_*` (stores, products, shipping, payments) | **only** `hostinger-ecommerce` (`npx --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-ecommerce-mcp`), or the Ecommerce MCP in the Hostinger Connector. Neither `hostinger` nor the scoped hosting servers include it | Ecommerce backends (chosen later, in refine) |
131
+ | **Hosting** | `hosting_*` (websites, deploy, build report), `wordpress_*` | `hostinger` (`<command> <launcher>`), or the scoped servers such as `hostinger-hosting` + `hostinger-wordpress` | every build |
132
+ | **Ecommerce** | `ecommerce_*` (stores, products, shipping, payments) | **only** `hostinger-ecommerce` (`<command> <launcher> hostinger-ecommerce-mcp`), or the Ecommerce MCP in the Hostinger Connector. Neither `hostinger` nor the scoped hosting servers include it | Ecommerce backends (chosen later, in refine) |
132
133
 
133
134
  Check each group on its own, right here at connect, before anything else:
134
135
 
@@ -148,8 +149,8 @@ Most coding tools load MCP servers only when they start, so a server registered
148
149
  until the tool restarts. When either tool group above is missing:
149
150
 
150
151
  1. **Register the missing servers** in the tool's MCP config, as the tool route below shows: `hostinger`
151
- (`npx -y --prefix="$HOME" @hostinger/mcp@latest`) if the hosting group is missing, and `hostinger-ecommerce`
152
- (`npx --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-ecommerce-mcp`) if the ecommerce group is missing.
152
+ (`<command> <launcher>`) if the hosting group is missing, and `hostinger-ecommerce`
153
+ (`<command> <launcher> hostinger-ecommerce-mcp`) if the ecommerce group is missing.
153
154
  Skip a server that is already registered under its name. When neither group is there, register
154
155
  both: the backend isn't chosen until refine, and one restart then covers every backend.
155
156
  2. **Write `connect.json`** (Phase 3) before you stop. The skill folder from Phase 1 stays in place,
@@ -163,12 +164,28 @@ until the tool restarts. When either tool group above is missing:
163
164
 
164
165
  If a tool loads new servers without a restart (VS Code), use them right away and skip steps 3–4.
165
166
 
166
- **Every `npx` command and registration keeps `--prefix` set to the user's home folder.** The tool
167
- starts the server, and you run commands, in the user's project, often a cloned repository or
168
- template. Without `--prefix`, npm reads the `.npmrc` there, and whoever wrote it can point npx at
169
- another registry or run their own code. In shell commands write `--prefix="$HOME"` (the shell expands
170
- it when you register). In JSON or TOML configs replace `<home>` with the home folder's absolute path
171
- (`echo $HOME`, e.g. `/Users/me` or `C:\\Users\\me`). Never drop the flag or leave `<home>` in place.
167
+ **Every registration and every command that starts the MCP server goes through the launcher**
168
+ (`~/.hostinger/mcp/launch.sh` and `launch.mjs`, which the bootstrap writes): never `npx` directly, with or without
169
+ `--prefix`. The tool starts the server, and you run commands, in the user's project, often a cloned
170
+ repository or template. npx run there puts the project's `node_modules/.bin` first on PATH and reads
171
+ its `.npmrc`, so whoever wrote the project runs their own `node` with the user's Hostinger sign-in.
172
+ The launcher runs npx from the home folder instead. A registration runs exactly the bootstrap's
173
+ `launcher` event, never a bare `node`: a version manager (asdf, mise) picks the Node that the project's
174
+ own `.tool-versions` names. On macOS and Linux the event is `/bin/sh` with `launch.sh`, which finds
175
+ Node only after moving to the home folder, so Node upgrades don't break it; on Windows it is the
176
+ absolute path of `node.exe` with `launch.mjs`. Replace `<command>` and `<launcher>` with that event's
177
+ `command` and `args[0]`, in shell commands and in JSON or TOML configs alike, and never leave a
178
+ placeholder in place. In JSON and TOML configs, double every backslash of a Windows path
179
+ (`C:\\Program Files\\nodejs\\node.exe`); a single one is an escape there (`\n` in `\nodejs` becomes a
180
+ newline). Commands you run yourself start in the home folder
181
+ (`cd "$HOME" && node …`) for the same reason.
182
+
183
+ **An existing Hostinger registration is "already registered" only when it runs exactly the
184
+ bootstrap's `launcher` event** (same `command`, `args[0]` the launcher, plus `hostinger-ecommerce-mcp`
185
+ for that server). Before you trust one (both groups present, or a name the tool lists), check its
186
+ command (Claude Code: `claude mcp get <name>`; otherwise the tool's MCP config). Anything else, such as
187
+ `npx`, a bare `node` or `hostinger-api-mcp`, or any other command or path than the event's:
188
+ remove it and register it again through the launcher, then follow *register, restart, resume*.
172
189
 
173
190
  | Tool | Route |
174
191
  |-------------|---------------------------------|
@@ -180,7 +197,7 @@ it when you register). In JSON or TOML configs replace `<home>` with the home fo
180
197
  | Devin | `connect/tools/devin.md` |
181
198
 
182
199
  If the user's tool isn't listed yet, connect it the generic way: register both Hostinger MCP servers
183
- in that tool's MCP config (command `npx`, args as above), then follow *register, restart, resume*.
200
+ in that tool's MCP config (command `<command>`, args `<launcher>` as above), then follow *register, restart, resume*.
184
201
 
185
202
  ### The skills come from Phase 1 only
186
203
 
@@ -2,10 +2,10 @@
2
2
  // Hostinger Headless — bootstrap.
3
3
  // Verifies the Hostinger MCP server is reachable and drives the OAuth sign-in,
4
4
  // emitting one JSON event per line on stdout so a coding agent can relay
5
- // progress to the user. No filesystem writes besides what the MCP itself
6
- // stores (OAuth credentials); no network calls of its own.
5
+ // progress to the user. Its only writes are the launcher (~/.hostinger/mcp/launch.mjs, which
6
+ // coding tools register) and what the MCP itself stores (OAuth credentials); no network calls of its own.
7
7
  import { spawn, spawnSync } from 'node:child_process';
8
- import { existsSync, readFileSync } from 'node:fs';
8
+ import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
9
9
  import path from 'node:path';
10
10
  import os from 'node:os';
11
11
 
@@ -17,19 +17,30 @@ const fail = (event, extra = {}) => {
17
17
  process.exit(1);
18
18
  };
19
19
 
20
- // ── platform-safe binary names (npm/npx are .cmd on Windows) ─────────────────
20
+ // ── the MCP server, always through the launcher ──────────────────────────────
21
+ // launch.mjs runs the latest published package via npx from the home folder (see its header for why
22
+ // npx must never run in the project). Coding tools register the home copy, which every run refreshes,
23
+ // so a registration keeps working when the skill folder moves to a new version.
21
24
  const isWin = process.platform === 'win32';
22
- const bin = (name) => (isWin ? `${name}.cmd` : name);
23
- // Run the MCP via npx — no global install, always the latest published version.
24
- // Use --package so npx resolves the published package, then invoke the unified binary.
25
- const MCP = [bin('npx'), '-y', '--package=@hostinger/mcp@latest', 'hostinger-api-mcp'];
26
- // Node >= 18.20.2 / 20.12.2 refuses to spawn a .cmd/.bat without a shell
27
- // (CVE-2024-27980), so npx.cmd needs shell:true on Windows. Our args are all
28
- // fixed literals, so enabling the shell introduces no injection risk.
29
- const spawnShell = isWin;
25
+ const LAUNCHER = path.join(os.homedir(), '.hostinger', 'mcp', 'launch.mjs');
26
+ try {
27
+ mkdirSync(path.dirname(LAUNCHER), { recursive: true });
28
+ copyFileSync(new URL('./launch.mjs', import.meta.url), LAUNCHER);
29
+ copyFileSync(new URL('./launch.sh', import.meta.url), LAUNCHER.replace(/\.mjs$/, '.sh'));
30
+ } catch (e) {
31
+ fail('launcher_failed', { detail: String(e) });
32
+ }
33
+ const MCP = [process.execPath, LAUNCHER];
34
+ // A registration never names a bare `node`: Windows looks it up in the working directory (the project)
35
+ // first, and a version manager's shim (asdf, mise) runs the Node the project's .tool-versions names.
36
+ // macOS/Linux register /bin/sh with launch.sh, which finds node only after moving to home, so Node
37
+ // upgrades keep working. Windows names this Node by absolute path (this script runs from home).
38
+ emit('launcher', isWin
39
+ ? { command: process.execPath, args: [LAUNCHER] }
40
+ : { command: '/bin/sh', args: [LAUNCHER.replace(/\.mjs$/, '.sh')] });
30
41
 
31
42
  function capture(cmd, args) {
32
- const r = spawnSync(cmd, args, { encoding: 'utf8', shell: spawnShell, cwd: os.homedir() });
43
+ const r = spawnSync(cmd, args, { encoding: 'utf8', cwd: os.homedir() });
33
44
  return { status: r.status ?? 1, out: `${r.stdout || ''}${r.stderr || ''}`, error: r.error };
34
45
  }
35
46
 
@@ -72,7 +83,7 @@ function existingAuth() {
72
83
  // prefix — forward it so the agent can show it if the browser didn't open.
73
84
  function login() {
74
85
  return new Promise((resolve) => {
75
- const child = spawn(MCP[0], [...MCP.slice(1), '--login'], { shell: spawnShell, cwd: os.homedir() });
86
+ const child = spawn(MCP[0], [...MCP.slice(1), '--login'], { cwd: os.homedir() });
76
87
  let diag = '';
77
88
  let urlSent = false;
78
89
  const collect = (chunk) => {
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ // Hostinger Headless — starts the latest Hostinger MCP server for a coding tool or a script.
3
+ // node launch.mjs [hostinger-<group>-mcp] [--login | --logout | --version]
4
+ //
5
+ // Coding tools start stdio servers in the user's project, often a cloned repository or template.
6
+ // npx run there puts <project>/node_modules/.bin, and the same folder of every parent, first on PATH
7
+ // (no npm flag turns that off) and reads the project's .npmrc, so the project's own `node` would run
8
+ // the server with the user's Hostinger credentials. This launcher runs npx from the home folder, with
9
+ // no relative or node_modules entries left on PATH, so nothing in the project is ever looked up.
10
+ import { spawn } from 'node:child_process';
11
+ import { homedir } from 'node:os';
12
+ import path from 'node:path';
13
+
14
+ const [PACKAGE, DEFAULT_BIN] = ['--package=@hostinger/mcp@latest', 'hostinger-api-mcp'];
15
+ const isWin = process.platform === 'win32';
16
+ const home = homedir();
17
+
18
+ const args = process.argv.slice(2);
19
+ // npx.cmd needs a shell on Windows (CVE-2024-27980), so every argument must be shell-inert.
20
+ if (args.some((a) => !/^[\w@.=:/-]+$/.test(a))) {
21
+ process.stderr.write(`launch.mjs: unexpected argument in ${JSON.stringify(args)}\n`);
22
+ process.exit(2);
23
+ }
24
+ const bin = /^[a-z0-9-]+-mcp$/.test(args[0] ?? '') ? args.shift() : DEFAULT_BIN;
25
+
26
+ // Windows may spell it Path; a relative entry or a node_modules folder can come from the project.
27
+ // The server returns to the project once started, so relative paths in tool arguments still work
28
+ // (launch.sh has already moved to home and names the project itself).
29
+ const env = { ...process.env, MCP_PROJECT_DIR: process.env.MCP_PROJECT_DIR || process.cwd() };
30
+ for (const key of Object.keys(env).filter((k) => k.toUpperCase() === 'PATH')) {
31
+ env[key] = env[key].split(path.delimiter)
32
+ .filter((p) => path.isAbsolute(p) && !p.split(/[\\/]/).includes('node_modules'))
33
+ .join(path.delimiter);
34
+ }
35
+
36
+ const child = spawn(isWin ? 'npx.cmd' : 'npx', ['-y', PACKAGE, bin, ...args], { cwd: home, env, stdio: 'inherit', shell: isWin });
37
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) process.on(signal, () => child.kill(signal));
38
+ child.on('error', (e) => {
39
+ process.stderr.write(`launch.mjs: could not start npx: ${e.message}\n`);
40
+ process.exit(1);
41
+ });
42
+ child.on('exit', (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
@@ -0,0 +1,23 @@
1
+ #!/bin/sh
2
+ # Hostinger Headless — what coding tools register on macOS and Linux: /bin/sh <home>/.hostinger/mcp/launch.sh
3
+ # /bin/sh never moves, and node is looked up only here, after moving to the home folder, so a Node
4
+ # upgrade (Homebrew, nvm, asdf) keeps the registration working, and a version manager's shim picks the
5
+ # user's own Node, never the one a project's .tool-versions names. Relative and node_modules entries
6
+ # are dropped from PATH first: either could hold a node the project put there.
7
+ # The server returns to the project once started (relative paths in tool arguments), so name it first.
8
+ MCP_PROJECT_DIR=$(pwd)
9
+ export MCP_PROJECT_DIR
10
+ cd || exit 1
11
+ set -f
12
+ safe=
13
+ IFS=:
14
+ for dir in $PATH; do
15
+ case $dir in
16
+ /*node_modules*) ;;
17
+ /*) safe=${safe:+$safe:}$dir ;;
18
+ esac
19
+ done
20
+ unset IFS
21
+ PATH=$safe
22
+ export PATH
23
+ exec node "${0%/*}/launch.mjs" "$@"
@@ -12,7 +12,7 @@ description: "Specific Antigravity Hostinger MCP Server connection instructions
12
12
 
13
13
  The later stages drive the Hostinger connector through Antigravity's native MCP tools. Check **both** tool groups (hosting and ecommerce), as *Check both tool groups* in `connect/SKILL.md`
14
14
  says: other Hostinger tools responding doesn't mean the `hostinger-ecommerce` ones are there. Both
15
- respond → use them and move on.
15
+ respond and both registrations run the launcher (*An existing Hostinger registration* in `connect/SKILL.md`) → use them and move on.
16
16
 
17
17
  If either is missing, add the missing server(s) to `~/.gemini/antigravity/mcp_config.json` (Windows:
18
18
  `C:\Users\<USERNAME>\.gemini\antigravity\mcp_config.json`), which you can reach from the Agent panel's
@@ -25,12 +25,12 @@ no tokens to handle:
25
25
  {
26
26
  "mcpServers": {
27
27
  "hostinger": {
28
- "command": "npx",
29
- "args": ["-y", "--prefix=<home>", "@hostinger/mcp@latest"]
28
+ "command": "<command>",
29
+ "args": ["<launcher>"]
30
30
  },
31
31
  "hostinger-ecommerce": {
32
- "command": "npx",
33
- "args": ["--prefix=<home>", "--package=@hostinger/mcp@latest", "hostinger-ecommerce-mcp"]
32
+ "command": "<command>",
33
+ "args": ["<launcher>", "hostinger-ecommerce-mcp"]
34
34
  }
35
35
  }
36
36
  }
@@ -19,14 +19,14 @@ groups as *Check both tool groups* in `connect/SKILL.md` says:
19
19
  `hostinger-wordpress`, `hostinger-domains`, …) never include it, so a session full of
20
20
  `mcp__hostinger-*__*` tools can still be missing it.
21
21
 
22
- Both present → use them and move on. Either missing → register the missing server(s) at user scope
22
+ Both present and both registrations run the launcher (*An existing Hostinger registration* in `connect/SKILL.md`) → use them and move on. Either missing → register the missing server(s) at user scope
23
23
  now (`claude mcp list` shows what's already registered; skip those). The bootstrap already signed you
24
24
  in, so they reuse the cached sign-in (`~/.config/hostinger-mcp/credentials.json`, or
25
25
  `HOSTINGER_API_TOKEN`) and there are no tokens to handle:
26
26
 
27
27
  ```bash
28
- claude mcp add hostinger --scope user -- npx -y --prefix="$HOME" @hostinger/mcp@latest # hosting group missing
29
- claude mcp add hostinger-ecommerce --scope user -- npx --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-ecommerce-mcp # ecommerce group missing
28
+ claude mcp add hostinger --scope user -- "<command>" "<launcher>" # hosting group missing
29
+ claude mcp add hostinger-ecommerce --scope user -- "<command>" "<launcher>" hostinger-ecommerce-mcp # ecommerce group missing
30
30
  ```
31
31
 
32
32
  Claude Code loads MCP servers only at startup, so follow *register, restart, resume* in
@@ -12,27 +12,27 @@ description: "Specific Codex Hostinger MCP Server connection instructions for th
12
12
 
13
13
  The later stages drive the Hostinger connector through Codex's native MCP tools. Check **both** tool groups (hosting and ecommerce), as *Check both tool groups* in `connect/SKILL.md`
14
14
  says: other Hostinger tools responding doesn't mean the `hostinger-ecommerce` ones are there. Both
15
- respond → use them and move on.
15
+ respond and both registrations run the launcher (*An existing Hostinger registration* in `connect/SKILL.md`) → use them and move on.
16
16
 
17
17
  If either is missing, register the missing server(s); skip one already registered. The bootstrap already signed you in, so they reuse the cached
18
18
  sign-in (`~/.config/hostinger-mcp/credentials.json`, or `HOSTINGER_API_TOKEN`) and there are no tokens
19
19
  to handle:
20
20
 
21
21
  ```bash
22
- codex mcp add hostinger -- npx -y --prefix="$HOME" @hostinger/mcp@latest
23
- codex mcp add hostinger-ecommerce -- npx --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-ecommerce-mcp
22
+ codex mcp add hostinger -- "<command>" "<launcher>"
23
+ codex mcp add hostinger-ecommerce -- "<command>" "<launcher>" hostinger-ecommerce-mcp
24
24
  ```
25
25
 
26
26
  or add them to `~/.codex/config.toml`:
27
27
 
28
28
  ```toml
29
29
  [mcp_servers.hostinger]
30
- command = "npx"
31
- args = ["-y", "--prefix=<home>", "@hostinger/mcp@latest"]
30
+ command = "<command>"
31
+ args = ["<launcher>"]
32
32
 
33
33
  [mcp_servers.hostinger-ecommerce]
34
- command = "npx"
35
- args = ["--prefix=<home>", "--package=@hostinger/mcp@latest", "hostinger-ecommerce-mcp"]
34
+ command = "<command>"
35
+ args = ["<launcher>", "hostinger-ecommerce-mcp"]
36
36
  ```
37
37
 
38
38
  Codex loads MCP servers only when it starts, so follow *register, restart, resume* in
@@ -13,13 +13,13 @@ description: "Specific Cursor Hostinger MCP Server connection instructions for t
13
13
 
14
14
  **Prerequisite:** Node.js 20 or newer on `PATH` (`node -v`). The published package engines require `>=20`; use Node 24 if you follow the package README.
15
15
 
16
- The Hostinger MCP is the npm package `@hostinger/mcp`. You do **not** need a global install — Cursor (and this session) can run it through `npx`. Prefer the unified binary `hostinger-api-mcp` (every operation). Scoped binaries such as `hostinger-hosting-mcp` are optional.
16
+ The Hostinger MCP is the npm package `@hostinger/mcp`. You do **not** need a global install — Cursor (and this session) run it through the launcher (`~/.hostinger/mcp/`, written by the connect bootstrap), which starts the latest release with `npx` from your home folder. Never run `npx` for it directly: from the project, npx would run the project's own `node`. `<command>` and `<launcher>` below come from the bootstrap's `launcher` event (see `connect/SKILL.md`). Prefer the unified binary `hostinger-api-mcp` (every operation). Scoped binaries such as `hostinger-hosting-mcp` are optional.
17
17
 
18
18
  ### Option A — no global install (recommended)
19
19
 
20
20
  ```bash
21
21
  # Verify the package/binary is reachable
22
- npx --yes --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-api-mcp --version
22
+ cd "$HOME" && node "$HOME/.hostinger/mcp/launch.mjs" --version
23
23
  ```
24
24
 
25
25
  ### Option B — global install
@@ -37,7 +37,7 @@ hostinger-api-mcp --version
37
37
  Check **both** tool groups, as *Check both tool groups* in `connect/SKILL.md` says: hosting
38
38
  (`mcp__hostinger__*` or `mcp__hostinger-hosting__*`) **and** ecommerce (`mcp__hostinger-ecommerce__*`).
39
39
  The scoped `mcp__hostinger-*__*` servers never include ecommerce, so they alone don't count. Both
40
- present → skip registration: go to Step 2 only if you still need sign-in, otherwise go to Step 3.
40
+ present and both registrations run the launcher (*An existing Hostinger registration* in `connect/SKILL.md`) → skip registration: go to Step 2 only if you still need sign-in, otherwise go to Step 3.
41
41
 
42
42
  If either is missing, register the missing server(s) in `~/.cursor/mcp.json` (global, so every project and every
43
43
  later run has them). Merge them into any existing `mcpServers` rather than replacing the file.
@@ -48,12 +48,12 @@ OAuth can run:
48
48
  {
49
49
  "mcpServers": {
50
50
  "hostinger": {
51
- "command": "npx",
52
- "args": ["--yes", "--prefix=<home>", "--package=@hostinger/mcp@latest", "hostinger-api-mcp"]
51
+ "command": "<command>",
52
+ "args": ["<launcher>"]
53
53
  },
54
54
  "hostinger-ecommerce": {
55
- "command": "npx",
56
- "args": ["--yes", "--prefix=<home>", "--package=@hostinger/mcp@latest", "hostinger-ecommerce-mcp"]
55
+ "command": "<command>",
56
+ "args": ["<launcher>", "hostinger-ecommerce-mcp"]
57
57
  }
58
58
  }
59
59
  }
@@ -74,7 +74,7 @@ If the connect bootstrap already emitted `logged_in` / `success`, credentials ar
74
74
  Otherwise run the login command. It registers a dynamic OAuth client (once per machine), **opens the user's browser** to Hostinger's authorization page, listens on a localhost callback, stores tokens, and exits:
75
75
 
76
76
  ```bash
77
- npx --yes --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-api-mcp --login
77
+ cd "$HOME" && node "$HOME/.hostinger/mcp/launch.mjs" --login
78
78
  ```
79
79
 
80
80
  (With a global install: `hostinger-api-mcp --login`.)
@@ -95,7 +95,7 @@ They are shared across every Hostinger MCP binary. Expired access tokens refresh
95
95
  To sign out later:
96
96
 
97
97
  ```bash
98
- npx --yes --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-api-mcp --logout
98
+ cd "$HOME" && node "$HOME/.hostinger/mcp/launch.mjs" --logout
99
99
  ```
100
100
 
101
101
  **API token (optional, CI / scripts):** set `HOSTINGER_API_TOKEN` in the environment before launching Cursor. When present it always wins and no OAuth code runs. Do not commit the token.
@@ -12,7 +12,7 @@ description: "Specific Devin Hostinger MCP Server connection instructions for th
12
12
 
13
13
  The later stages drive the Hostinger connector through Devin's native MCP tools. Check **both** tool groups (hosting and ecommerce), as *Check both tool groups* in `connect/SKILL.md`
14
14
  says: other Hostinger tools responding doesn't mean the `hostinger-ecommerce` ones are there. Both
15
- respond → use them and move on.
15
+ respond and both registrations run the launcher (*An existing Hostinger registration* in `connect/SKILL.md`) → use them and move on.
16
16
 
17
17
  If either is missing, register the missing server(s) for Devin; skip one already registered. The bootstrap already signed you in, so they reuse the
18
18
  cached sign-in (`~/.config/hostinger-mcp/credentials.json`, or `HOSTINGER_API_TOKEN`) and there are no
@@ -21,18 +21,18 @@ tokens to handle.
21
21
  - **Devin CLI:**
22
22
 
23
23
  ```bash
24
- devin mcp add hostinger -- npx -y --prefix="$HOME" @hostinger/mcp@latest
25
- devin mcp add hostinger-ecommerce -- npx --prefix="$HOME" --package=@hostinger/mcp@latest hostinger-ecommerce-mcp
24
+ devin mcp add hostinger -- "<command>" "<launcher>"
25
+ devin mcp add hostinger-ecommerce -- "<command>" "<launcher>" hostinger-ecommerce-mcp
26
26
  ```
27
27
 
28
28
  - **Devin app:** Settings → MCP Marketplace → **Add Your Own**, transport **STDIO**, once per server:
29
29
 
30
30
  ```json
31
- { "command": "npx", "args": ["-y", "--prefix=<home>", "@hostinger/mcp@latest"] }
31
+ { "command": "<command>", "args": ["<launcher>"] }
32
32
  ```
33
33
 
34
34
  ```json
35
- { "command": "npx", "args": ["--prefix=<home>", "--package=@hostinger/mcp@latest", "hostinger-ecommerce-mcp"] }
35
+ { "command": "<command>", "args": ["<launcher>", "hostinger-ecommerce-mcp"] }
36
36
  ```
37
37
 
38
38
  If the tools still aren't in this session, follow *register, restart, resume* in `connect/SKILL.md`:
@@ -12,7 +12,7 @@ description: "Specific VS Code Hostinger MCP Server connection instructions for
12
12
 
13
13
  The later stages drive the Hostinger connector through VS Code's native MCP tools. Check **both** tool groups (hosting and ecommerce), as *Check both tool groups* in `connect/SKILL.md`
14
14
  says: other Hostinger tools responding doesn't mean the `hostinger-ecommerce` ones are there. Both
15
- respond → use them and move on.
15
+ respond and both registrations run the launcher (*An existing Hostinger registration* in `connect/SKILL.md`) → use them and move on.
16
16
 
17
17
  If either is missing, register the missing server(s) for VS Code; skip one already registered. The bootstrap already signed you in, so they reuse
18
18
  the cached sign-in (`~/.config/hostinger-mcp/credentials.json`, or `HOSTINGER_API_TOKEN`) and there are
@@ -25,13 +25,13 @@ no tokens to handle. Add them to `.vscode/mcp.json` (workspace) or your user `se
25
25
  "servers": {
26
26
  "hostinger": {
27
27
  "type": "stdio",
28
- "command": "npx",
29
- "args": ["-y", "--prefix=<home>", "@hostinger/mcp@latest"]
28
+ "command": "<command>",
29
+ "args": ["<launcher>"]
30
30
  },
31
31
  "hostinger-ecommerce": {
32
32
  "type": "stdio",
33
- "command": "npx",
34
- "args": ["--prefix=<home>", "--package=@hostinger/mcp@latest", "hostinger-ecommerce-mcp"]
33
+ "command": "<command>",
34
+ "args": ["<launcher>", "hostinger-ecommerce-mcp"]
35
35
  }
36
36
  }
37
37
  }
@@ -40,8 +40,8 @@ no tokens to handle. Add them to `.vscode/mcp.json` (workspace) or your user `se
40
40
  Or add them in two commands:
41
41
 
42
42
  ```bash
43
- code --add-mcp '{"name":"hostinger","command":"npx","args":["-y","--prefix=<home>","@hostinger/mcp@latest"]}'
44
- code --add-mcp '{"name":"hostinger-ecommerce","command":"npx","args":["--prefix=<home>","--package=@hostinger/mcp@latest","hostinger-ecommerce-mcp"]}'
43
+ code --add-mcp '{"name":"hostinger","command":"<command>","args":["<launcher>"]}'
44
+ code --add-mcp '{"name":"hostinger-ecommerce","command":"<command>","args":["<launcher>","hostinger-ecommerce-mcp"]}'
45
45
  ```
46
46
 
47
47
  VS Code picks up new servers and their tools become available right away, with no editor restart.
@@ -3,20 +3,15 @@
3
3
 
4
4
  import { spawn } from 'node:child_process';
5
5
  import { homedir } from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
6
7
 
7
- // ── platform-safe binary names (npm/npx are .cmd on Windows), as in connect/bootstrap.mjs ──────────
8
- const isWin = process.platform === 'win32';
9
- const bin = (name) => (isWin ? `${name}.cmd` : name);
10
- const MCP = [bin('npx'), '-y', '--package=@hostinger/mcp@latest', 'hostinger-api-mcp'];
11
- // Node >= 18.20.2 / 20.12.2 refuses to spawn a .cmd/.bat without a shell
12
- // (CVE-2024-27980), so npx.cmd needs shell:true on Windows. Our args are all
13
- // fixed literals, so enabling the shell introduces no injection risk.
14
- const spawnShell = isWin;
8
+ // ── always through the launcher, which runs npx from the home folder, never in the project ─────────
9
+ const MCP = [process.execPath, fileURLToPath(new URL('./connect/launch.mjs', import.meta.url))];
15
10
 
16
11
  // One server per script run. Once it dies every pending and later call rejects, so the caller ends with
17
12
  // exit 2 rather than hanging.
18
13
  export function connect(clientName) {
19
- const child = spawn(MCP[0], MCP.slice(1), { stdio: ['pipe', 'pipe', 'pipe'], shell: spawnShell, cwd: homedir() });
14
+ const child = spawn(MCP[0], MCP.slice(1), { stdio: ['pipe', 'pipe', 'pipe'], cwd: homedir() });
20
15
  const pending = new Map();
21
16
  let buffer = '';
22
17
  let diag = '';