Build an optimized shift roster
build_shift_rosterSolve a staff rostering problem to optimality with a MILP solver and return who works which shift each day, coverage, unfilled posts, hours per person and warnings. Solves take 5-60 s. Pass either example (to solve a built-in example as-is) or the roster input fields. If the result has status 'running', call get_shift_roster_result with its job_id. If it has status 'too_large', shorten the horizon or reduce people/shift types and retry. If it has status 'busy', wait the retry_after_seconds it gives and call again -- one call at a time, never in parallel. Safe defaults (e.g. the next 7 days when days is omitted) are listed in the result's assumptions; tell the user about them. Roster input. Minimal example: {"days": ["2026-10-05", "2026-10-06"], "shifts": [{"shift": "Day", "start": "07:00", "end": "19:00"}, {"shift": "Night", "start": "19:00", "end": "07:00", "night": "yes"}], "demands": [{"name": "RN", "penalty": 500}], "people": [{"name": "Ana", "cost": 40, "max_hw": 48}, ...], "grids": {"RN": {"2026-10-05|Day": 2, "2026-10-05|Night": 1}}, "parameters": {"MinRestHours": 11}}. Call get_shift_example for complete, realistic inputs.
Tool call template
This tool declares no required parameters. Add optional parameters from the input schema as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {},
"name": "build_shift_roster"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | OPTIONAL. Day labels in order: ISO dates ('2026-10-05') or weekday names ('Mon'). Dates or weekdays enable weekend rules. Omit it to plan the next 7 days (ISO dates starting tomorrow); the default used is reported in the result's `assumptions`. | |
| goal | No | One sentence, in the user's own words, of what they are trying to do (e.g. 'a 4-week nurse rota for 12 nurses on 12-hour shifts'). Optional; helps improve the tool. | |
| grids | No | Optional per-day/shift cells, keyed by a demand name or a person name, each an object keyed 'DAY|SHIFT'. Demand grid value = headcount required (demand with no grid = 1 on every shift). Person grid value: 'a' or 1 = available, 'f' = must work, 0 or missing = UNAVAILABLE (person with no grid = available everywhere). | |
| people | No | ||
| shifts | No | Shift types. A shift may cross midnight (end < start). | |
| skills | No | Who can cover which demand. Omitted = everyone can cover every demand. | |
| demands | No | Posts to fill (roles). Headcount per day/shift goes in grids. | |
| example | No | Solve this built-in example instead of passing the fields below. | |
| parameters | No | Optional rules. MinRestHours (11), MaxConsecutiveDays (6), MaxConsecutiveNights (4), ForbidDayAfterNight ('yes'), NightStartsAfter ('18:00'), MinBlockDays (1), WeekendFairnessPenalty (0), EquityPenalty (0) = even out total hours, NightEquityPenalty (0) = even out total nights (try 20), NightDifferential (1.0), WeekendDifferential (1.0), TimeLimitSeconds (max 60 here), GapPercent (2). | |
| wait_seconds | No | How long to wait for the solve inside this call (default 25). |