Issue #232 closed: deployment get with `lines` bypasses the essential projection — leaks server secrets and blows token budgets
What happens
deployment {action: get, uuid, lines: N} switches from the slim toDeploymentEssential() projection to the raw upstream payload (getDeployment(uuid, { includeLogs: true })), and that raw Coolify response embeds the entire application graph: rendered docker_compose, custom_labels, webhook secrets, the destination server object with proxy config, and server.settings including logdrain_custom_config (which contains a live bearer token for the log drain) and sentinel_token.
Observed in production use (2026-07-02): deployment {action: get, uuid: ..., lines: 5} returned a ~78KB payload — 5 log lines wrapped in the full application + server + proxy + log-drain config. It blew the calling agent's tool-result cap, and the secrets above were in the body.
Why it matters
- Security: v2.12.0 deliberately masked webhook secrets in
list_resources— this path undoes that class of protection. Any agent asking for deployment logs gets log-drain credentials and the sentinel token in context (and potentially into transcripts/telemetry). - Token budget: the whole point of
toDeploymentEssential(coolify-client.ts ~line 300) is defeated the moment you ask for logs, which is the most common reason to callgetat all.
Where
- Handler:
src/lib/mcp-server.ts:1155— thelinesbranch callsgetDeployment(uuid, { includeLogs: true })and returns the raw object. - Projection helper:
src/lib/coolify-client.ts~300 (toDeploymentEssential).
Suggested fix
Always project through toDeploymentEssential, and when lines is set attach logs (via the existing truncateLogs() in mcp-server.ts:70) onto the projection — never return the raw upstream object. If any raw field is genuinely needed later, add it to the projection explicitly. Belt-and-braces: run the projection output through the same secret-masking used by list_resources so future upstream fields can't reintroduce a leak.
Acceptance
deployment getwithlinesreturns: essential fields +logs(truncated) only; noapplication.*, noserver.*, no compose, no tokens.- A test asserting the response for a logs-included get contains no
logdrain,sentinel_token,manual_webhook_secret*, ordocker_composekeys.