Stu Mason
Stu Mason

Activity

Pull Request Merged

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):

CallResponse sizeItem keys
list_resources (default)3,749 bytes4 (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_github
  • manual_webhook_secret_gitlab
  • manual_webhook_secret_gitea
  • manual_webhook_secret_bitbucket
  • http_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):

CallSecrets ***Secrets plaintext
include_full=true (default reveal=false)11/110
include_full=true reveal=true011/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:

  1. Test mock at src/__tests__/coolify-client.test.ts:4335 (mockFetch is typed as any so TypeScript didn't catch the drift from the EnvironmentVariable type definition)
  2. CHANGELOG [2.11.0] env_vars expanded bullet

Runtime code was already correct — this is doc + test-mock cleanup only.

Breaking change (typed-only)

  • listResources signature (#203, #204): Promise<ResourceListItem[]>Promise<ResourceListItem[] | ResourceListItemFull[]> with new optional options?: { include_full?: boolean; reveal?: boolean } parameter. Programmatic consumers of @masonator/coolify-mcp will need to widen their result type (or narrow at the call site with include_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 (unrelated any types in error handlers).
  • pnpm test356 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.
+272
additions
-12
deletions
6
files changed