PR #158 opened: fix(client): listApplicationDeployments returns envelope, defaults to essential projection
Symptom
listApplicationDeployments(uuid) can return responses larger than 1 MB on apps with a typical deployment history (20–40 deployments). When called from an MCP client (e.g. Claude Code), the response can blow past the model's context window or simply exhaust the MCP token budget on a single tool call. Smoke-tested live against Coolify 4.0.0-beta.472: a 35-deployment app returned ~1 MB JSON, of which >99% was raw build-log blobs embedded in each deployment.
Root cause
Two issues, same fix:
-
Type lie. The current return type
Promise<Deployment[]>does not match the real Coolify response.GET /api/v1/deployments/applications/{uuid}actually returns an envelope:{ "count": 35, "deployments": [ /* Deployment[] */ ] }Verified live against Coolify
4.0.0-beta.472. The existing type causes any caller using.length,.map(), etc. to blow up at runtime — only no-op callers were unaffected. -
No projection. Each
Deploymentcarries a fulllogsfield (the entire build-log stream, often 30–100 KB per deployment). Returning all of them by default is a footgun for LLM/MCP callers.
Fix
- Return the envelope shape
{ count, deployments }honestly. - Default
deploymentstoDeploymentEssential[](nologsblob, setslogs_available: truebreadcrumb so callers know to refetch a single one if needed). - Add
options.includeLogs?: booleanopt-in for callers that genuinely want the raw build logs. - Tolerate malformed envelopes (
{}→{ count: 0, deployments: [] }). - Update
diagnoseApplication(the only internal caller) to flatten the envelope before iterating. - Plumb a matching
include_logsknob through thedeploymentMCP tool'slist_for_appaction.
Smoke test (real Coolify 4.0.0-beta.472)
| Mode | Bytes |
|---|---|
Old (Deployment[] w/ logs) | ~1,000,000+ |
New default (DeploymentEssential[]) | 4,194 |
New includeLogs: true | unchanged from old |
That's a ~250× reduction by default, and the raw-log path is still available behind a flag.
Tests
- Replaced
should list application deploymentswith three cases:- default essential projection (no
logs, haslogs_available: true, dropsid) includeLogs: truereturns full deployments unchanged- tolerates malformed envelope (
{})
- default essential projection (no
- Updated 4
mockResponse(...)calls indiagnoseApplicationtests to wrap their input in the new envelope shape. npm test: 264/264 pass. Coverage stays at 97.7% statements / 83.9% branches / 99.4% functions / 98.7% lines.npm run lint: clean (4 pre-existing warnings, 0 new).npm run build: clean.
Breaking change
Yes, but signaled by the signature change: Promise<Deployment[]> → Promise<{ count: number; deployments: Deployment[] | DeploymentEssential[] }>. Any caller currently treating the result as an array would have already been broken at runtime against real Coolify (since the API doesn't actually return an array), so in practice this only fixes broken callers and gives them a typed migration path.
Generated with Claude Code.