@@ -92,6 +92,7 @@ var expectedFullCatalog = sortedStrings(
9292 ToolListInstalledModels ,
9393 ToolListKnownBackends ,
9494 ToolListNodes ,
95+ ToolListScheduling ,
9596 ToolListVoiceProfiles ,
9697 ToolLoadModel ,
9798 ToolReloadModels ,
@@ -105,6 +106,9 @@ var expectedFullCatalog = sortedStrings(
105106 ToolCreateVoiceProfile ,
106107 ToolDeleteVoiceProfile ,
107108 ToolSetNodeVRAMBudget ,
109+ ToolSetScheduling ,
110+ ToolDeleteScheduling ,
111+ ToolGetScheduling ,
108112)
109113
110114// expectedReadOnlyCatalog is the tool set when DisableMutating=true. Sorted.
@@ -123,6 +127,8 @@ var expectedReadOnlyCatalog = sortedStrings(
123127 ToolListInstalledModels ,
124128 ToolListKnownBackends ,
125129 ToolListNodes ,
130+ ToolListScheduling ,
131+ ToolGetScheduling ,
126132 ToolListVoiceProfiles ,
127133 ToolSystemInfo ,
128134 ToolVRAMEstimate ,
@@ -165,6 +171,10 @@ var _ = Describe("Tool dispatch", func() {
165171 {ToolListKnownBackends , struct {}{}, "ListKnownBackends" },
166172 {ToolSystemInfo , struct {}{}, "SystemInfo" },
167173 {ToolListNodes , struct {}{}, "ListNodes" },
174+ {ToolListScheduling , struct {}{}, "ListScheduling" },
175+ {ToolGetScheduling , DeleteSchedulingRequest {ModelName : "qwen" }, "GetScheduling" },
176+ {ToolSetScheduling , SetSchedulingRequest {ModelName : "qwen" , MinReplicas : 1 , MaxReplicas : 2 }, "SetScheduling" },
177+ {ToolDeleteScheduling , DeleteSchedulingRequest {ModelName : "qwen" }, "DeleteScheduling" },
168178 {ToolListVoiceProfiles , struct {}{}, "ListVoiceProfiles" },
169179 {ToolInstallModel , InstallModelRequest {ModelName : "test/foo" }, "InstallModel" },
170180 {ToolImportModelURI , ImportModelURIRequest {URI : "Qwen/Qwen3-4B-GGUF" }, "ImportModelURI" },
@@ -219,6 +229,40 @@ var _ = Describe("Tool error surfacing", func() {
219229 })
220230})
221231
232+ var _ = Describe ("Scheduling tool behavior" , func () {
233+ It ("round-trips list/get/set/delete over the MCP surface" , func () {
234+ fc := & fakeClient {
235+ listScheduling : func () ([]ModelSchedulingConfig , error ) {
236+ return []ModelSchedulingConfig {{ModelName : "qwen" , MinReplicas : 1 , MaxReplicas : 2 }}, nil
237+ },
238+ getScheduling : func (modelName string ) (* ModelSchedulingConfig , error ) {
239+ return & ModelSchedulingConfig {ModelName : modelName , SpreadAll : true }, nil
240+ },
241+ setScheduling : func (req SetSchedulingRequest ) (* ModelSchedulingConfig , error ) {
242+ return & ModelSchedulingConfig {ModelName : req .ModelName , MinReplicas : req .MinReplicas , MaxReplicas : req .MaxReplicas }, nil
243+ },
244+ }
245+ ctx , sess , done := connectInMemory (fc , Options {})
246+ DeferCleanup (done )
247+
248+ listRes := callTool (ctx , sess , ToolListScheduling , struct {}{})
249+ Expect (listRes .IsError ).To (BeFalse (), resultText (listRes ))
250+ Expect (resultText (listRes )).To (ContainSubstring (`"model_name": "qwen"` ))
251+
252+ getRes := callTool (ctx , sess , ToolGetScheduling , DeleteSchedulingRequest {ModelName : "qwen" })
253+ Expect (getRes .IsError ).To (BeFalse (), resultText (getRes ))
254+ Expect (resultText (getRes )).To (ContainSubstring (`"spread_all": true` ))
255+
256+ setRes := callTool (ctx , sess , ToolSetScheduling , SetSchedulingRequest {ModelName : "qwen" , MinReplicas : 1 , MaxReplicas : 2 })
257+ Expect (setRes .IsError ).To (BeFalse (), resultText (setRes ))
258+ Expect (resultText (setRes )).To (ContainSubstring (`"max_replicas": 2` ))
259+
260+ deleteRes := callTool (ctx , sess , ToolDeleteScheduling , DeleteSchedulingRequest {ModelName : "qwen" })
261+ Expect (deleteRes .IsError ).To (BeFalse (), resultText (deleteRes ))
262+ Expect (resultText (deleteRes )).To (ContainSubstring (`"deleted": "qwen"` ))
263+ })
264+ })
265+
222266var _ = Describe ("Argument validation" , func () {
223267 type validationCase struct {
224268 desc string
@@ -235,6 +279,9 @@ var _ = Describe("Argument validation", func() {
235279 {"toggle_model_state rejects unknown action" , ToolToggleModelState , map [string ]any {"name" : "foo" , "action" : "noop" }, "action must be one of" },
236280 {"edit_model_config rejects empty patch" , ToolEditModelConfig , map [string ]any {"name" : "foo" , "patch" : map [string ]any {}}, "patch is required" },
237281 {"create_voice_profile requires consent" , ToolCreateVoiceProfile , CreateVoiceProfileRequest {Name : "Voice" , Transcript : "words" , AudioBase64 : "UklGRg==" }, "consent_confirmed must be true" },
282+ {"set_scheduling requires model_name" , ToolSetScheduling , SetSchedulingRequest {}, "model_name is required" },
283+ {"set_scheduling rejects invalid replica range" , ToolSetScheduling , SetSchedulingRequest {ModelName : "qwen" , MinReplicas : 3 , MaxReplicas : 1 }, "min_replicas must be <= max_replicas" },
284+ {"delete_scheduling requires model_name" , ToolDeleteScheduling , DeleteSchedulingRequest {}, "model_name is required" },
238285 }
239286
240287 for _ , c := range cases {
0 commit comments