feat: committed env-var .mcp.json — hostinger tools in cloud sessions (v1.1.0) - #9
Conversation
… (v1.1.0) Cloud sessions load the repo's .mcp.json from the clone but the file was gitignored, so web/phone sessions got the skill with no tools. The tracked config launches hostinger-api-mcp via npx and reads HOSTINGER_API_TOKEN from the environment (shell env on devices, environment env vars in claude.ai cloud sessions); it is skipped silently when unset. Optional HOSTINGER_MCP_BINARY selects a category binary to keep the tool surface lean. enableAllProjectMcpServers auto-approves the committed config; .mcp.json.example becomes the multi-account reference shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf5d82b646
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "command": "npx", | ||
| "args": ["-y", "-p", "hostinger-api-mcp", "${HOSTINGER_MCP_BINARY:-hostinger-api-mcp}"], | ||
| "env": { | ||
| "HOSTINGER_API_TOKEN": "${HOSTINGER_API_TOKEN}" |
There was a problem hiding this comment.
Handle an unset token without invalidating the MCP config
When HOSTINGER_API_TOKEN is unset—the documented default for users who only clone this repository—this required expansion does not cause the server to be “skipped silently.” Claude Code's environment-variable expansion documentation states that a missing variable without a default makes Claude Code fail to parse the config, so the committed project MCP configuration is invalid for those users. Add behavior that conditionally skips launching the server, or document and implement a valid default.
Useful? React with 👍 / 👎.
| "env": { | ||
| "HOSTINGER_API_TOKEN": "${HOSTINGER_API_TOKEN}" | ||
| } |
There was a problem hiding this comment.
Extend the secret guard to the tracked MCP config
When a user replaces this placeholder with a real token for local testing—as the previous configuration workflow encouraged—the file is now tracked, but the No-leak guard in .github/workflows/ci.yml scans only .claude/. A real full-account Hostinger token can therefore be committed and pass CI; include .mcp.json in the credential scan now that it is deliberately tracked.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR makes the repo’s MCP connectivity work in claude.ai cloud sessions (and devices) by committing a placeholder-only .mcp.json that reads the Hostinger token from environment variables, and updates docs/versioning to reflect the new setup.
Changes:
- Commit a project
.mcp.jsonthat startshostinger-api-mcpvianpxusing${HOSTINGER_API_TOKEN}and optional${HOSTINGER_MCP_BINARY}selection. - Remove
.mcp.jsonfrom.gitignoreand update installation/docs to describe the env-var (“zero-config”) workflow. - Bump the skill/package version to 1.1.0 and document the release in the changelog.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents the new env-var based “zero-config” connection approach. |
| package.json | Version bump to 1.1.0. |
| CHANGELOG.md | Adds 1.1.0 entry describing the new connectivity workflow. |
| .mcp.json.example | Repositions the example as a reference shape (multi-account/per-category). |
| .mcp.json | New committed MCP server config using env-var placeholders and npx. |
| .gitignore | Stops ignoring .mcp.json so the placeholder config is tracked. |
| .claude/skills/hostinger-mcp/SKILL.md | Version bump to 1.1.0 in skill frontmatter. |
| .claude/skills/hostinger-mcp/references/installation.md | Adds env-var (“zero-config”) setup documentation. |
| .claude/settings.json | Enables auto-approval of project MCP servers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -61,6 +61,8 @@ Use it solo for your own boxes; reach for Aura when you operate a fleet on clien | |||
|
|
|||
| The skill activates when Hostinger is discussed and a `hostinger-*` MCP server is connected (tools appear as `mcp__hostinger*__*`). For setup — see [`installation.md`](.claude/skills/hostinger-mcp/references/installation.md) and [`.mcp.json.example`](.mcp.json.example). Install with `npm i -g hostinger-api-mcp`; authenticate with a `HOSTINGER_API_TOKEN` from hPanel. | |||
| "hostinger": { | ||
| "type": "stdio", | ||
| "command": "npx", | ||
| "args": ["-y", "-p", "hostinger-api-mcp", "${HOSTINGER_MCP_BINARY:-hostinger-api-mcp}"], |
| @@ -1,4 +1,5 @@ | |||
| { | |||
| "enableAllProjectMcpServers": true, | |||
| @@ -1,5 +1,5 @@ | |||
| { | |||
| "_comment": "Copy to .mcp.json (gitignored) and fill real tokens; never commit them. One connection per category binary you need (keeps context lean) and one per Hostinger account. Get the API token from hPanel. Node.js v24+ required.", | |||
| "_comment": "Multi-account / per-category JSON shape for reference. Do NOT copy over .mcp.json — that file is now committed and must only ever contain ${VAR} placeholders. Put real tokens in your user scope instead (`claude mcp add -s user ...` per references/installation.md) or in env vars. One connection per category binary you need (keeps context lean) and one per Hostinger account. Get the API token from hPanel. Node.js v24+ required.", | |||
…version (Codex round-1 P1s)
P1 (config parse): ${HOSTINGER_API_TOKEN:-} keeps the committed config parseable when the var is unset - a bare ${VAR} fails the whole config parse per the Claude Code docs; wording updated to the real unavailable-until-set behavior. P1 (leak guard): the CI no-leak scan now covers the tracked .mcp.json/.mcp.json.example so a real token pasted into them fails CI; verified the scan passes on the placeholder files locally. Also pins the npx launch to hostinger-api-mcp@1.8.2 (auto-approved config + unpinned latest = supply-chain risk; Copilot raised the same on the sibling siteagent PR), untangles the README zero-config vs npm-i-g paths, and corrects the Node-version note (upstream says 24+, verified on 22).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
|
@codex review Generated by Claude Code |
| # Also scan the tracked MCP configs — placeholder-only by policy, so a | ||
| # real token pasted into them must fail CI. | ||
| if grep -rniE "(api[_-]?key|bearer|secret|password|token)[\"'[:space:]=:]+[A-Za-z0-9/_-]{24,}" .claude/ .mcp.json .mcp.json.example \ | ||
| | grep -viE "your-|YOUR_|ACCT_[AB]|example|<|\$\{|placeholder|HOSTINGER_API_TOKEN"; then |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa1063ccb2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if grep -rniE "(api[_-]?key|bearer|secret|password|token)[\"'[:space:]=:]+[A-Za-z0-9/_-]{24,}" .claude/ .mcp.json .mcp.json.example \ | ||
| | grep -viE "your-|YOUR_|ACCT_[AB]|example|<|\$\{|placeholder|HOSTINGER_API_TOKEN"; then |
There was a problem hiding this comment.
Remove the token-key exemption from the leak guard
When someone pastes a real credential into the newly tracked config as "HOSTINGER_API_TOKEN": "<real-token>", the first grep matches it, but the second grep discards the entire line merely because it contains the key name HOSTINGER_API_TOKEN. The pipeline consequently reports no match and CI passes, defeating the added protection against committing a live Hostinger credential; exempt only the placeholder value rather than every line containing this key.
Useful? React with 👍 / 👎.
…e or the example filename (Codex round-2 P1) The round-1 guard discarded any line containing HOSTINGER_API_TOKEN, so a real value under that key passed CI; and because grep prefixes matches with the file path, the 'example' exemption matched the .mcp.json.example filename and waved through anything in that file. The pipeline now strips the path:line: prefix before the exemption filter and exempts only placeholder values. Regression-tested both ways locally: clean tree passes, a planted 36-char token in .mcp.json is detected. Also adds the npx '--' separator so a mis-set HOSTINGER_MCP_BINARY starting with '-' can't be parsed as an option (Copilot); verified the pinned launch still boots. Copilot's case-sensitivity claim was wrong - the first grep already has -i. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
|
@codex review Generated by Claude Code |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.claude/settings.json:2
enableAllProjectMcpServers: truewill auto-enable any MCP server defined at the project level. That’s a security footgun in forks/PR branches (it can execute arbitrary commands via stdio servers), and it also makes future additions to.mcp.jsonauto-approved by default.
"enableAllProjectMcpServers": true,
| ## Activation | ||
|
|
||
| The skill activates when Hostinger is discussed and a `hostinger-*` MCP server is connected (tools appear as `mcp__hostinger*__*`). For setup — see [`installation.md`](.claude/skills/hostinger-mcp/references/installation.md) and [`.mcp.json.example`](.mcp.json.example). Install with `npm i -g hostinger-api-mcp`; authenticate with a `HOSTINGER_API_TOKEN` from hPanel. | ||
| The skill activates when Hostinger is discussed and a `hostinger-*` MCP server is connected (tools appear as `mcp__hostinger*__*`). Two setup paths — pick one: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2b7bf1e31
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # filename matches the "example" exemption and waves real tokens through. | ||
| # No exemption for the HOSTINGER_API_TOKEN key name — only placeholder | ||
| # VALUES (${...}, YOUR_..., etc.) are exempt, so a real value still fails. | ||
| if grep -rniE "(api[_-]?key|bearer|secret|password|token)[\"'[:space:]=:]+[A-Za-z0-9/_-]{24,}" .claude/ .mcp.json .mcp.json.example \ |
There was a problem hiding this comment.
Detect tokens across JSON line breaks
When valid JSON places the key and value on separate lines—for example, "HOSTINGER_API_TOKEN": followed by a long token on the next line—grep evaluates each line independently, so neither line matches both halves of this pattern and the no-leak guard passes. A real credential can therefore be committed in either tracked MCP config despite the stated policy; parse the JSON or scan configured values independently of line layout.
Useful? React with 👍 / 👎.
…dex round-3 P1); README glob wording Valid JSON can split key and value across lines, evading the line-based grep; the no-leak job now also parses the tracked MCP configs and requires every env/header value to be an env placeholder or shorter than 24 chars, independent of layout. Catches base64-style values with ./+/= too, which the grep charset missed. Verified both ways locally (clean tree passes, planted 39-char value detected) and the workflow YAML parses. README activation wording now covers the committed config's plain 'hostinger' name (Copilot); CHANGELOG documents the trusted-folder nuance of enableAllProjectMcpServers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
|
@codex review Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5288372861
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # placeholder or too short to be a live credential. | ||
| python3 - <<'PY' | ||
| import json, re, sys | ||
| PLACEHOLDER = re.compile(r'\$\{[A-Za-z_][A-Za-z0-9_]*(:-[^}]*)?\}') |
There was a problem hiding this comment.
Reject secrets embedded in placeholder defaults
Restrict the placeholder match so it accepts only an empty/non-secret default and covers the entire value. As written, a value such as ${HOSTINGER_API_TOKEN:-abcdefghijklmnopqrstuvwxyz123456} matches this regex, and the earlier line-based guard also exempts any line containing ${, so CI passes even though the tracked config contains a usable fallback credential. This defeats the new placeholder-only policy and can leak a live Hostinger token into git.
Useful? React with 👍 / 👎.
… P1)
${VAR:-<secret>} matched the placeholder regex and the $\{ grep exemption, so a live fallback credential in the tracked config passed both guard layers. The JSON guard now fails any :- default of credential size (>=24 chars) and any literal residue outside placeholders of that size. Unit-checked: secret default and prefix-secret cases fail; empty defaults, Bearer-prefixed placeholders, and short literals pass; clean tree passes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.claude/settings.json:2
- Enabling
enableAllProjectMcpServersby default means that once a user trusts this repo, Claude Code will auto-approve and attempt to start all project MCP servers (including thenpx-launched one) without an explicit per-user approval step. That’s a meaningful security/operational default for downstream consumers of the repo; consider leaving it off by default and documenting the opt-in instead.
{
"enableAllProjectMcpServers": true,
| if grep -rniE "(api[_-]?key|bearer|secret|password|token)[\"'[:space:]=:]+[A-Za-z0-9/_-]{24,}" .claude/ .mcp.json .mcp.json.example \ | ||
| | sed 's/^[^:]*:[0-9]*://' \ | ||
| | grep -viE "your-|YOUR_|ACCT_[AB]|example|<|\$\{|placeholder"; then |
|
@codex review Generated by Claude Code |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
.github/workflows/ci.yml:63
- The no-leak guard’s exemption regex still includes
exampleeven after stripping thepath:line:prefix. That means any line containing the word “example” (e.g., docs that use example domains) would bypass the secret detector, which weakens the protection for.claude/and the tracked MCP configs.
if grep -rniE "(api[_-]?key|bearer|secret|password|token)[\"'[:space:]=:]+[A-Za-z0-9/_-]{24,}" .claude/ .mcp.json .mcp.json.example \
| sed 's/^[^:]*:[0-9]*://' \
| grep -viE "your-|YOUR_|ACCT_[AB]|example|<|\$\{|placeholder"; then
| for path in ('.mcp.json', '.mcp.json.example'): | ||
| cfg = json.load(open(path)) | ||
| for name, srv in cfg.get('mcpServers', {}).items(): |
| - **Committed `.mcp.json`** (secrets as placeholders only) — launches `hostinger-api-mcp` via `npx` with the token from the `HOSTINGER_API_TOKEN` env var, so claude.ai cloud environments (which load the repo's `.mcp.json` from the clone and inject env vars from the environment config) and devices with the var in their shell get the tools with no per-machine setup. The `${HOSTINGER_API_TOKEN:-}` default keeps the config parseable when the var is unset — the connection then just shows as unavailable until the token is provided (a bare unset `${VAR}` would fail the whole config parse, per the Claude Code docs — Codex round-1 P1). Optional `HOSTINGER_MCP_BINARY` picks a category binary (e.g. `hostinger-vps-mcp`) to keep the tool surface lean. | ||
| - The `npx` launch is **version-pinned** (`hostinger-api-mcp@1.8.2`) — the config is auto-approved, so an unpinned latest would be a standing supply-chain risk; bump the pin deliberately. | ||
| - The CI **no-leak guard now scans the tracked `.mcp.json` / `.mcp.json.example`** (Codex round-1 P1) so a real token pasted into them can't pass CI. Exemptions apply to placeholder **values** only — not the key name or the `example` filename (Codex round-2 P1) — and a JSON-parsing check validates the actual env/header values independent of line layout, closing the split-across-lines evasion (Codex round-3 P1). |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a484a5131a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for m in PLACEHOLDER.finditer(val): | ||
| if len(m.group(2) or '') >= 24: | ||
| return True | ||
| return len(PLACEHOLDER.sub('', val)) >= 24 |
There was a problem hiding this comment.
Accumulate placeholder defaults before checking credential length
When a credential is divided among multiple defaults, such as ${A:-abcdefghijkl}${B:-mnopqrstuvwx}, each default and the remaining literal text are individually shorter than 24 characters, so secret_shaped returns false even though the value expands to a 24-character embedded credential. This lets the tracked MCP configs pass the no-leak guard with a complete secret; check the combined defaults and literal residue, or reject non-empty defaults entirely.
Useful? React with 👍 / 👎.
…evasion (Codex round-5 P1)
A credential split across several placeholder defaults (${A:-half1}${B:-half2}) passed the per-default check since each piece was under 24 chars. The guard now sums all :- defaults plus the literal residue - exactly what the value can expand to with unset vars - and fails at credential size. Unit-checked including the split case and the legit multi-part values; clean tree passes. Also uses a context manager for the file handles (Copilot).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
|
@codex review Generated by Claude Code |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Why
claude.ai cloud sessions load a repo's
.mcp.jsonstraight from the clone, but this repo gitignored the file (tokens-in-file convention) — so web/phone sessions got the skill with no tools.What
.mcp.jsonthat launches the official server vianpx -y -p hostinger-api-mcpand reads${HOSTINGER_API_TOKEN}from the environment — shell env on devices, the environment's env vars in cloud sessions. Unset var → server skipped silently.${HOSTINGER_MCP_BINARY:-hostinger-api-mcp}selects a category binary (e.g.hostinger-vps-mcp) per environment, honoring the skill's lean-context guidance without hardcoding a guess. Verifiednpx -y hostinger-api-mcpboots on Node 22 (this cloud image)..mcp.jsonremoved from.gitignore; the tracked file must only ever contain${VAR}placeholders..mcp.json.examplere-purposed as the multi-account/per-category reference shape..claude/settings.jsonsetsenableAllProjectMcpServersso the committed config is auto-approved.installation.md+ README document the env-var route and the migration off a local gitignored.mcp.json.Part of the toolbox cloud-connectivity rollout — sibling PRs in cloudways-mcp, aura-mcp, sumit-mcp, siteagent-elementor-studio, and the env-var onboarding table in agent-skills.
🤖 Generated with Claude Code
https://claude.ai/code/session_014wNQYbS2Umgd7RWV8CAyYa
Generated by Claude Code