PR #206 merged: fix(system): list_resources essential projection, secret masking, is_build_time typo cleanup
Closes #203, #204, #205.
This PR addresses three issues that surfaced post-v2.11.0 when wiring up the new system tool against a real Coolify instance with 30+ resources. All three are scoped to list_resources plus a small docs/test-mock typo bleed-in from #172. Mirrors the same opt-in / masking patterns shipped previously by #158 (include_logs) and #159 / #182 (env_vars masking with reveal).
Three commits
1. fix(system): default list_resources to essential projection, add include_full opt-in — closes #203
Previously typed as Promise<ResourceListItem[]> but actually returned the full Coolify /api/v1/resources payload (~95 fields per row, ~16 KB per item). On a moderate instance with 33+ resources this exceeded 500 KB on a single call, blowing MCP token budgets and effectively making list_resources unusable for LLM-driven workflows.
Now defaults to a true { uuid, name, type, status? } projection applied at the API boundary in listResources(). Set include_full: true to opt back into the raw Coolify payload.
Live verification on a Coolify v4 instance (34 resources):
| Call | Response size | Item keys |
|---|---|---|
list_resources (default) | 3,749 bytes | 4 (uuid/name/type/status) |
list_resources include_full=true | ~105 KB | ~95 (raw Coolify) |
~143× smaller on the default path.
2. fix(security): mask webhook secrets and basic-auth password in list_resources — closes #204
The full /api/v1/resources response embeds five sensitive fields on every application row:
manual_webhook_secret_githubmanual_webhook_secret_gitlabmanual_webhook_secret_giteamanual_webhook_secret_bitbuckethttp_basic_auth_password
The first four are HMAC signing keys for inbound deploy webhooks — forging one lets an attacker trigger a deploy on that repo independent of the Coolify API token. The basic-auth password gates front-of-app access.
Before this change, any MCP client / LLM granted permission to call system list_resources with include_full: true silently received every one of these. The user almost certainly did not intend to grant secret-exfiltration when granting a "read-only enumeration" tool.
Applies the v2.9.0 env_vars masking pattern (#159 / #182) exactly: replace each sensitive field with '***' at the API boundary in listResources(). Pass reveal: true alongside include_full: true to round-trip plaintext. Masking is applied at the client method so any other code path that calls listResources() also inherits the protection.
Live verification on the same instance (11 git-deployed apps):
| Call | Secrets *** | Secrets plaintext |
|---|---|---|
include_full=true (default reveal=false) | 11/11 | 0 |
include_full=true reveal=true | 0 | 11/11 |
3. docs: fix is_build_time typo bleed-in from #172 — closes #205
PR #174 renamed the env-var build-time flag from is_build_time to is_buildtime everywhere (Coolify's API rejects the underscored form with HTTP 422 on single endpoints and silently ignores it on bulk endpoints). PR #172 was authored against pre-#174 main and during the merge into post-#174 main, two is_build_time references slipped back in:
- Test mock at
src/__tests__/coolify-client.test.ts:4335(mockFetch is typed asanyso TypeScript didn't catch the drift from theEnvironmentVariabletype definition) CHANGELOG [2.11.0]env_vars expandedbullet
Runtime code was already correct — this is doc + test-mock cleanup only.
Breaking change (typed-only)
listResourcessignature (#203, #204):Promise<ResourceListItem[]>→Promise<ResourceListItem[] | ResourceListItemFull[]>with new optionaloptions?: { include_full?: boolean; reveal?: boolean }parameter. Programmatic consumers of@masonator/coolify-mcpwill need to widen their result type (or narrow at the call site withinclude_full). Note: the previous type was wrong-at-runtime against real Coolify (claimed 4 fields, returned ~95), so any caller that worked end-to-end was already accommodating the bloated shape.
Verification
pnpm build— passes (tsc clean).pnpm lint— 0 errors, 4 pre-existing warnings (unrelatedanytypes in error handlers).pnpm test— 356 tests pass (was 348 before; +8 new tests covering essential projection, masking, reveal, null-secret edge case, default-projection-with-reveal no-op).- Coverage: 98.09% statements / 99.53% functions.
- Live smoke against a real Coolify v4 instance (34 resources / 11 apps) confirmed all three behaviors as documented above.