Summary
Two bugs in MCP schedule management that can silently corrupt schedule state when AI agents call `update_agent_schedule`:
-
Accidental re-enable: The `enabled` field description in `update_agent_schedule` was too terse. An AI model updating other fields (e.g. cron expression) might include `enabled: true` to be "thorough" or copy it from a `list_agent_schedules` response — immediately re-enabling a schedule the user had intentionally disabled.
-
Silent no-op on retry config: `ScheduleUpdateRequest` (Pydantic model in `routers/schedules.py`) was missing `max_retries` and `retry_delay_seconds`. When an MCP call included these fields, Pydantic's `exclude_unset=True` silently dropped them — the DB layer's `allowed_fields` list included them, but they could never reach it.
Context
Discovered during investigation of schedule CRUD path: MCP tool → Pydantic model → `model_dump(exclude_unset=True)` → `db.update_schedule()` → SQL UPDATE.
Acceptance Criteria
Technical Notes
Files changed:
- `src/mcp-server/src/tools/schedules.ts` — expand `enabled` description in `updateAgentSchedule` Zod schema
- `src/backend/routers/schedules.py` — add `max_retries` and `retry_delay_seconds` to `ScheduleUpdateRequest`
The bug path for (1): disabled schedule → MCP update call with `enabled: true` in payload → backend applies it → schedule re-enabled without user intent.
Summary
Two bugs in MCP schedule management that can silently corrupt schedule state when AI agents call `update_agent_schedule`:
Accidental re-enable: The `enabled` field description in `update_agent_schedule` was too terse. An AI model updating other fields (e.g. cron expression) might include `enabled: true` to be "thorough" or copy it from a `list_agent_schedules` response — immediately re-enabling a schedule the user had intentionally disabled.
Silent no-op on retry config: `ScheduleUpdateRequest` (Pydantic model in `routers/schedules.py`) was missing `max_retries` and `retry_delay_seconds`. When an MCP call included these fields, Pydantic's `exclude_unset=True` silently dropped them — the DB layer's `allowed_fields` list included them, but they could never reach it.
Context
Discovered during investigation of schedule CRUD path: MCP tool → Pydantic model → `model_dump(exclude_unset=True)` → `db.update_schedule()` → SQL UPDATE.
Acceptance Criteria
Technical Notes
Files changed:
The bug path for (1): disabled schedule → MCP update call with `enabled: true` in payload → backend applies it → schedule re-enabled without user intent.