hostinger-api-mcp 3.27.2 → 3.27.3
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 +7 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/headless/VERSION +2 -2
- package/src/core/runtime.js +21 -4
- package/src/core/runtime.ts +21 -4
- package/src/servers/agency-hosting.js +1 -1
- package/src/servers/agency-hosting.ts +1 -1
- 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/gpu.js +1 -1
- package/src/servers/gpu.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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ 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.27.3 — 2026-11-03
|
|
8
|
+
|
|
9
|
+
### Also in this release
|
|
10
|
+
|
|
11
|
+
- Bundled agent skills: `skills/headless/VERSION`
|
|
12
|
+
- Request handling and authentication: `src/core/runtime.js`, `src/core/runtime.ts`
|
|
13
|
+
|
|
7
14
|
## v3.27.2 — 2026-11-03
|
|
8
15
|
|
|
9
16
|
### Also in this release
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
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.27.
|
|
9
|
+
"version": "3.27.3",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@hostinger/mcp",
|
|
14
|
-
"version": "3.27.
|
|
14
|
+
"version": "3.27.3",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
package/skills/headless/VERSION
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
version=3.27.
|
|
2
|
-
commit=
|
|
1
|
+
version=3.27.3
|
|
2
|
+
commit=fddd58626392
|
|
3
3
|
built=2026-11-03
|
package/src/core/runtime.js
CHANGED
|
@@ -357,6 +357,8 @@ class MCPServer {
|
|
|
357
357
|
|
|
358
358
|
// System directories and the roots of the home directories. /var as a whole stays deployable: sites live in /var/www, and macOS keeps its temp dir there.
|
|
359
359
|
systemDirectories = ['/etc', '/root', '/usr', '/bin', '/sbin', '/boot', '/proc', '/sys', '/dev', '/var/lib', '/var/log', '/var/db', '/var/root', '/private/etc', '/private/var/lib', '/private/var/log', '/private/var/db', '/private/var/root', '/System', '/Library',
|
|
360
|
+
// Homebrew on Apple silicon and MacPorts keep service data (databases) and configs under their prefix.
|
|
361
|
+
'/opt/homebrew', '/opt/local',
|
|
360
362
|
// Container secrets (Docker's /run/secrets, the Kubernetes service-account token under /var/run/secrets) and runtime state.
|
|
361
363
|
'/run', '/var/run', '/private/var/run',
|
|
362
364
|
// Every user's home directory, whatever the current home is (root's is /root, a container's can be /).
|
|
@@ -402,10 +404,9 @@ class MCPServer {
|
|
|
402
404
|
// A profile reached outside the home roots (WSL's /mnt/c/Users/me, a home on a mounted disk): the top-level data
|
|
403
405
|
// of a directory under a Users or home directory, and a profile, or a directory holding profiles (/mnt/c/Users,
|
|
404
406
|
// /mnt/c), that has the data of one; a project's own users/ or home/ deploys.
|
|
405
|
-
const looksLikeProfile = (dir) => ['AppData', 'Library', '.ssh', '.aws', '.gnupg', '.kube'].some((name) => fs.existsSync(path.join(dir, name)));
|
|
406
407
|
const holdsProfiles = (dir) => {
|
|
407
408
|
try {
|
|
408
|
-
return fs.readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isDirectory() && looksLikeProfile(path.join(dir, entry.name)));
|
|
409
|
+
return fs.readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isDirectory() && this.looksLikeProfile(path.join(dir, entry.name)));
|
|
409
410
|
} catch (error) {
|
|
410
411
|
return false;
|
|
411
412
|
}
|
|
@@ -417,11 +418,11 @@ class MCPServer {
|
|
|
417
418
|
}
|
|
418
419
|
const top = segments[i + 2];
|
|
419
420
|
if (top === undefined) {
|
|
420
|
-
return i + 1 < segments.length ? looksLikeProfile(real) : holdsProfiles(real);
|
|
421
|
+
return i + 1 < segments.length ? this.looksLikeProfile(real) : holdsProfiles(real);
|
|
421
422
|
}
|
|
422
423
|
return top !== '.claude-worktrees' && (top.startsWith('.') || ['library', 'appdata', 'snap'].includes(top.toLowerCase()));
|
|
423
424
|
}));
|
|
424
|
-
const inSystem = !inHome && this.systemDirectories.some((dir) => inside(dir, real));
|
|
425
|
+
const inSystem = !inHome && this.systemDirectories.some((dir) => inside(dir, real) || inside(real, dir));
|
|
425
426
|
// Windows drops trailing dots and spaces from a name: .ssh. is .ssh.
|
|
426
427
|
const inCredentials = real.split(path.sep).some((segment) => this.credentialDirectories.includes((process.platform === 'win32' ? segment.replace(/[. ]+$/, '') : segment).toLowerCase()));
|
|
427
428
|
if (inside(real, home) || otherHome || inHomeData || inProfile || inSystem || inCredentials || (fs.statSync(real).isFile() && this.isSecretFile(path.basename(real)))) {
|
|
@@ -429,6 +430,12 @@ class MCPServer {
|
|
|
429
430
|
}
|
|
430
431
|
}
|
|
431
432
|
|
|
433
|
+
// A user's profile, told by its app data or credentials: Library/Application Support rather than Library, which
|
|
434
|
+
// on a case-insensitive file system also matches a project's own library/.
|
|
435
|
+
looksLikeProfile(dir) {
|
|
436
|
+
return ['AppData', path.join('Library', 'Application Support'), '.ssh', '.aws', '.gnupg', '.kube'].some((name) => fs.existsSync(path.join(dir, name)));
|
|
437
|
+
}
|
|
438
|
+
|
|
432
439
|
// Env files (examples such as .env.example are kept), credentials and private keys: a deploy would serve them
|
|
433
440
|
// publicly. Matches the CLI's isSecretFile, plus .npmrc and the Hostinger credential files.
|
|
434
441
|
isSecretFile(name) {
|
|
@@ -453,6 +460,11 @@ class MCPServer {
|
|
|
453
460
|
listDeployFiles(dir, exclude) {
|
|
454
461
|
const files = [];
|
|
455
462
|
const skipped = [];
|
|
463
|
+
// A profile copy deployed as is (a backup disk's me/), told by its app data alone: a project's own .aws/ or .kube/
|
|
464
|
+
// at the top is skipped below, as before.
|
|
465
|
+
if (['AppData', path.join('Library', 'Application Support')].some((name) => fs.existsSync(path.join(dir, name)))) {
|
|
466
|
+
throw new Error('Refusing to deploy ' + dir + ': it is a home directory. Pass the project directory or archive.');
|
|
467
|
+
}
|
|
456
468
|
const walk = (relativeDir) => {
|
|
457
469
|
for (const entry of fs.readdirSync(path.join(dir, relativeDir), { withFileTypes: true })) {
|
|
458
470
|
if (entry.isSymbolicLink()) {
|
|
@@ -464,6 +476,11 @@ class MCPServer {
|
|
|
464
476
|
if (entry.name !== '.config' && this.credentialDirectories.includes(entry.name.toLowerCase())) {
|
|
465
477
|
skipped.push(relativePath);
|
|
466
478
|
} else if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
479
|
+
// assertDeployablePath judges only the top of the path: a profile copy nested deeper (a backup disk's
|
|
480
|
+
// Users/<name>) would ship its app data and keys.
|
|
481
|
+
if (this.looksLikeProfile(path.join(dir, relativePath))) {
|
|
482
|
+
throw new Error('Refusing to deploy ' + dir + ': ' + relativePath + ' is a home directory. Pass the project directory or archive.');
|
|
483
|
+
}
|
|
467
484
|
walk(relativePath);
|
|
468
485
|
}
|
|
469
486
|
} else if (entry.isFile() && entry.name !== '.DS_Store' && path.resolve(dir, relativePath) !== exclude) {
|
package/src/core/runtime.ts
CHANGED
|
@@ -389,6 +389,8 @@ class MCPServer {
|
|
|
389
389
|
|
|
390
390
|
// System directories and the roots of the home directories. /var as a whole stays deployable: sites live in /var/www, and macOS keeps its temp dir there.
|
|
391
391
|
private systemDirectories = ['/etc', '/root', '/usr', '/bin', '/sbin', '/boot', '/proc', '/sys', '/dev', '/var/lib', '/var/log', '/var/db', '/var/root', '/private/etc', '/private/var/lib', '/private/var/log', '/private/var/db', '/private/var/root', '/System', '/Library',
|
|
392
|
+
// Homebrew on Apple silicon and MacPorts keep service data (databases) and configs under their prefix.
|
|
393
|
+
'/opt/homebrew', '/opt/local',
|
|
392
394
|
// Container secrets (Docker's /run/secrets, the Kubernetes service-account token under /var/run/secrets) and runtime state.
|
|
393
395
|
'/run', '/var/run', '/private/var/run',
|
|
394
396
|
// Every user's home directory, whatever the current home is (root's is /root, a container's can be /).
|
|
@@ -434,10 +436,9 @@ class MCPServer {
|
|
|
434
436
|
// A profile reached outside the home roots (WSL's /mnt/c/Users/me, a home on a mounted disk): the top-level data
|
|
435
437
|
// of a directory under a Users or home directory, and a profile, or a directory holding profiles (/mnt/c/Users,
|
|
436
438
|
// /mnt/c), that has the data of one; a project's own users/ or home/ deploys.
|
|
437
|
-
const looksLikeProfile = (dir: string): boolean => ['AppData', 'Library', '.ssh', '.aws', '.gnupg', '.kube'].some((name: string) => fs.existsSync(path.join(dir, name)));
|
|
438
439
|
const holdsProfiles = (dir: string): boolean => {
|
|
439
440
|
try {
|
|
440
|
-
return fs.readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isDirectory() && looksLikeProfile(path.join(dir, entry.name)));
|
|
441
|
+
return fs.readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isDirectory() && this.looksLikeProfile(path.join(dir, entry.name)));
|
|
441
442
|
} catch (error) {
|
|
442
443
|
return false;
|
|
443
444
|
}
|
|
@@ -449,11 +450,11 @@ class MCPServer {
|
|
|
449
450
|
}
|
|
450
451
|
const top = segments[i + 2];
|
|
451
452
|
if (top === undefined) {
|
|
452
|
-
return i + 1 < segments.length ? looksLikeProfile(real) : holdsProfiles(real);
|
|
453
|
+
return i + 1 < segments.length ? this.looksLikeProfile(real) : holdsProfiles(real);
|
|
453
454
|
}
|
|
454
455
|
return top !== '.claude-worktrees' && (top.startsWith('.') || ['library', 'appdata', 'snap'].includes(top.toLowerCase()));
|
|
455
456
|
}));
|
|
456
|
-
const inSystem = !inHome && this.systemDirectories.some((dir: string) => inside(dir, real));
|
|
457
|
+
const inSystem = !inHome && this.systemDirectories.some((dir: string) => inside(dir, real) || inside(real, dir));
|
|
457
458
|
// Windows drops trailing dots and spaces from a name: .ssh. is .ssh.
|
|
458
459
|
const inCredentials = real.split(path.sep).some((segment: string) => this.credentialDirectories.includes((process.platform === 'win32' ? segment.replace(/[. ]+$/, '') : segment).toLowerCase()));
|
|
459
460
|
if (inside(real, home) || otherHome || inHomeData || inProfile || inSystem || inCredentials || (fs.statSync(real).isFile() && this.isSecretFile(path.basename(real)))) {
|
|
@@ -461,6 +462,12 @@ class MCPServer {
|
|
|
461
462
|
}
|
|
462
463
|
}
|
|
463
464
|
|
|
465
|
+
// A user's profile, told by its app data or credentials: Library/Application Support rather than Library, which
|
|
466
|
+
// on a case-insensitive file system also matches a project's own library/.
|
|
467
|
+
private looksLikeProfile(dir: string): boolean {
|
|
468
|
+
return ['AppData', path.join('Library', 'Application Support'), '.ssh', '.aws', '.gnupg', '.kube'].some((name: string) => fs.existsSync(path.join(dir, name)));
|
|
469
|
+
}
|
|
470
|
+
|
|
464
471
|
// Env files (examples such as .env.example are kept), credentials and private keys: a deploy would serve them
|
|
465
472
|
// publicly. Matches the CLI's isSecretFile, plus .npmrc and the Hostinger credential files.
|
|
466
473
|
private isSecretFile(name: string): boolean {
|
|
@@ -485,6 +492,11 @@ class MCPServer {
|
|
|
485
492
|
private listDeployFiles(dir: string, exclude?: string): { files: string[]; skipped: string[] } {
|
|
486
493
|
const files: string[] = [];
|
|
487
494
|
const skipped: string[] = [];
|
|
495
|
+
// A profile copy deployed as is (a backup disk's me/), told by its app data alone: a project's own .aws/ or .kube/
|
|
496
|
+
// at the top is skipped below, as before.
|
|
497
|
+
if (['AppData', path.join('Library', 'Application Support')].some((name: string) => fs.existsSync(path.join(dir, name)))) {
|
|
498
|
+
throw new Error('Refusing to deploy ' + dir + ': it is a home directory. Pass the project directory or archive.');
|
|
499
|
+
}
|
|
488
500
|
const walk = (relativeDir: string): void => {
|
|
489
501
|
for (const entry of fs.readdirSync(path.join(dir, relativeDir), { withFileTypes: true })) {
|
|
490
502
|
if (entry.isSymbolicLink()) {
|
|
@@ -496,6 +508,11 @@ class MCPServer {
|
|
|
496
508
|
if (entry.name !== '.config' && this.credentialDirectories.includes(entry.name.toLowerCase())) {
|
|
497
509
|
skipped.push(relativePath);
|
|
498
510
|
} else if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
511
|
+
// assertDeployablePath judges only the top of the path: a profile copy nested deeper (a backup disk's
|
|
512
|
+
// Users/<name>) would ship its app data and keys.
|
|
513
|
+
if (this.looksLikeProfile(path.join(dir, relativePath))) {
|
|
514
|
+
throw new Error('Refusing to deploy ' + dir + ': ' + relativePath + ' is a home directory. Pass the project directory or archive.');
|
|
515
|
+
}
|
|
499
516
|
walk(relativePath);
|
|
500
517
|
}
|
|
501
518
|
} else if (entry.isFile() && entry.name !== '.DS_Store' && path.resolve(dir, relativePath) !== exclude) {
|
|
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
|
|
|
4
4
|
import tools from '../core/tools/agency-hosting.js';
|
|
5
5
|
import instructions from '../core/instructions.agency-hosting.js';
|
|
6
6
|
|
|
7
|
-
startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.27.
|
|
7
|
+
startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.27.3', tools, instructions });
|
|
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
|
|
|
4
4
|
import tools from '../core/tools/agency-hosting.js';
|
|
5
5
|
import instructions from '../core/instructions.agency-hosting.js';
|
|
6
6
|
|
|
7
|
-
startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.27.
|
|
7
|
+
startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.27.3', tools, instructions });
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
import { startServer } from '../core/runtime.js';
|
|
4
4
|
import tools from '../core/tools/agent-readiness.js';
|
|
5
5
|
|
|
6
|
-
startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.27.
|
|
6
|
+
startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.27.3', tools });
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
import { startServer } from '../core/runtime.js';
|
|
4
4
|
import tools from '../core/tools/agent-readiness.js';
|
|
5
5
|
|
|
6
|
-
startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.27.
|
|
6
|
+
startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.27.3', tools });
|
package/src/servers/all.js
CHANGED
|
@@ -5,4 +5,4 @@ import tools from '../core/tools/all.js';
|
|
|
5
5
|
import instructions from '../core/instructions.js';
|
|
6
6
|
import skills from '../core/skills.js';
|
|
7
7
|
|
|
8
|
-
startServer({ name: 'hostinger-api-mcp', version: '3.27.
|
|
8
|
+
startServer({ name: 'hostinger-api-mcp', version: '3.27.3', tools, instructions, skills });
|
package/src/servers/all.ts
CHANGED
|
@@ -5,4 +5,4 @@ import tools from '../core/tools/all.js';
|
|
|
5
5
|
import instructions from '../core/instructions.js';
|
|
6
6
|
import skills from '../core/skills.js';
|
|
7
7
|
|
|
8
|
-
startServer({ name: 'hostinger-api-mcp', version: '3.27.
|
|
8
|
+
startServer({ name: 'hostinger-api-mcp', version: '3.27.3', tools, instructions, skills });
|
package/src/servers/billing.js
CHANGED
package/src/servers/billing.ts
CHANGED
package/src/servers/dns.js
CHANGED
package/src/servers/dns.ts
CHANGED
package/src/servers/domains.js
CHANGED
package/src/servers/domains.ts
CHANGED
package/src/servers/ecommerce.js
CHANGED
package/src/servers/ecommerce.ts
CHANGED
package/src/servers/gpu.js
CHANGED
package/src/servers/gpu.ts
CHANGED
package/src/servers/horizons.js
CHANGED
package/src/servers/horizons.ts
CHANGED
package/src/servers/hosting.js
CHANGED
|
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
|
|
|
4
4
|
import tools from '../core/tools/hosting.js';
|
|
5
5
|
import instructions from '../core/instructions.js';
|
|
6
6
|
|
|
7
|
-
startServer({ name: 'hostinger-hosting-mcp', version: '3.27.
|
|
7
|
+
startServer({ name: 'hostinger-hosting-mcp', version: '3.27.3', tools, instructions });
|
package/src/servers/hosting.ts
CHANGED
|
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
|
|
|
4
4
|
import tools from '../core/tools/hosting.js';
|
|
5
5
|
import instructions from '../core/instructions.js';
|
|
6
6
|
|
|
7
|
-
startServer({ name: 'hostinger-hosting-mcp', version: '3.27.
|
|
7
|
+
startServer({ name: 'hostinger-hosting-mcp', version: '3.27.3', tools, instructions });
|
package/src/servers/mail.js
CHANGED
package/src/servers/mail.ts
CHANGED
package/src/servers/reach.js
CHANGED
package/src/servers/reach.ts
CHANGED
package/src/servers/vps.js
CHANGED
package/src/servers/vps.ts
CHANGED
package/src/servers/wordpress.js
CHANGED
package/src/servers/wordpress.ts
CHANGED