PR #243 merged: fix: validate scheduled-task command length client-side, add error hints
What
Coolify rejects scheduled-task command values beyond ~250 chars with a bodyless HTTP 500 (Internal Server Error, no validation message) that the MCP previously passed through verbatim. This closes #234, which absorbed item 3 of the now-closed #237.
Upstream evidence for the limit
Checked Coolify's own migrations (gh api repos/coollabsio/coolify/contents/database/migrations). The table is created in database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php:
$table->string('command');
A plain Laravel string() column is varchar(255). I checked every later scheduled-tasks migration (add_timeout_to_scheduled_tasks_table, improve_scheduled_task_executions_tracking, etc.) — none of them touch the command column's type. So the limit is 255, pinned from upstream source, not just the largest empirically-known-good value (247).
This matches the empirical datapoints in the issue: 247 chars OK, ~265+ fails — consistent with a 255-char ceiling (255 itself would still pass; the reporter's smallest failing sample was ~265).
Changes
- Client-side validation (
src/lib/mcp-server.ts):commandin thescheduled_taskstool shape now has.max(255, '...')with an actionable message. The shape is shared betweencreateandupdate, so both are covered by one change. Tool description also mentions the limit. - Status-code-aware error hints (
src/lib/coolify-client.ts): new pure functionerrorHint(status, path)appends a short hint to bodyless failures:500on a/scheduled-taskspath → command-length limit as a known cause.401/403→ checkCOOLIFY_ACCESS_TOKENvalidity/scopes.404on a uuid-shaped route → uuid may belong to a different resource type (app vs service vs database).- Anything else → no hint appended (passthrough unchanged).
- Docs: added the gotcha (limit + workaround) to
site/concepts/coolify-api-gotchas.md, matching the existing entry style and citing the migration file.
Tests
- An over-long command is rejected via the tool's zod
inputSchemabefore any HTTP call — asserted that the mockedcreateApplicationScheduledTask/updateApplicationScheduledTaskclient methods are never invoked. - A 255-char command still validates successfully (boundary case).
- Unit tests for
errorHintcovering all three mapped cases and the default (undefined) passthrough. - Integration-style test: a real bodyless 500 from
createApplicationScheduledTasknow surfaces the hint in the thrown error.
npm test (371 tests passing), npm run lint, npx prettier --check ., and npm run build all pass.
Uncertain / worth a second look
- The 404 "uuid route" heuristic in
errorHintis a generic regex (/[\w-]{8,}(\/|$)/) rather than validating true UUID format, since Coolify's uuids aren't RFC4122-shaped. It's intentionally loose per "don't over-engineer" — flagging in case a tighter check is preferred.
Closes #234
🤖 Generated with Claude Code