Goro commited on
Commit
f7f3b5c
·
1 Parent(s): 8612b4f

Add component manager tests

Browse files
tests/contrib/test_component_manager.py ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from starlette import status
3
+ from starlette.testclient import TestClient
4
+
5
+ from fastmcp import FastMCP
6
+ from fastmcp.contrib.component_manager.component_manager import set_up_component_manager
7
+ from fastmcp.server.auth.providers.bearer import BearerAuthProvider, RSAKeyPair
8
+
9
+
10
+ class TestComponentManagementRoutes:
11
+ """Test the component management routes for tools, resources, and prompts."""
12
+
13
+ @pytest.fixture
14
+ def mounted_mcp(self):
15
+ """Create a FastMCP server with a mounted sub-server and a tool, resource, and prompt on the sub-server."""
16
+ mounted_mcp = FastMCP("SubServer")
17
+
18
+ @mounted_mcp.tool()
19
+ def mounted_tool() -> str:
20
+ """Test tool for tool management routes."""
21
+ return "mounted_tool_result"
22
+
23
+ @mounted_mcp.resource("data://mounted_resource")
24
+ def mounted_resource() -> str:
25
+ """Test resource for tool management routes."""
26
+ return "mounted_resource_result"
27
+
28
+ # Add a test resource
29
+ @mounted_mcp.resource("data://mounted_resource/{id}")
30
+ def test_template(id: str) -> dict:
31
+ """Test template for tool management routes."""
32
+ return {"id": id, "value": "data"}
33
+
34
+ @mounted_mcp.prompt()
35
+ def mounted_prompt() -> str:
36
+ """Test prompt for tool management routes."""
37
+ return "mounted_prompt_result"
38
+
39
+ return mounted_mcp
40
+
41
+ @pytest.fixture
42
+ def mcp(self, mounted_mcp):
43
+ """Create a FastMCP server with test tools, resources, and prompts."""
44
+ mcp = FastMCP("TestServer")
45
+ mcp.mount(mounted_mcp, prefix="sub")
46
+ set_up_component_manager(server=mcp)
47
+ # Add a test tool
48
+ @mcp.tool
49
+ def test_tool() -> str:
50
+ """Test tool for tool management routes."""
51
+ return "test_tool_result"
52
+
53
+ # Add a test resource
54
+ @mcp.resource("data://test_resource")
55
+ def test_resource() -> str:
56
+ """Test resource for tool management routes."""
57
+ return "test_resource_result"
58
+
59
+ # Add a test resource
60
+ @mcp.resource("data://test_resource/{id}")
61
+ def test_template(id: str) -> dict:
62
+ """Test template for tool management routes."""
63
+ return {"id": id, "value": "data"}
64
+
65
+ # Add a test prompt
66
+ @mcp.prompt
67
+ def test_prompt() -> str:
68
+ """Test prompt for tool management routes."""
69
+ return "test_prompt_result"
70
+
71
+ return mcp
72
+
73
+ @pytest.fixture
74
+ def client(self, mcp):
75
+ """Create a test client for the FastMCP server."""
76
+ return TestClient(mcp.http_app())
77
+
78
+ async def test_enable_tool_route(self, client, mcp):
79
+ """Test enabling a tool via the HTTP route."""
80
+ # First disable the tool
81
+ tool = await mcp._tool_manager.get_tool("test_tool")
82
+ tool.enabled = False
83
+
84
+ # Enable the tool via the HTTP route
85
+ response = client.post("/tools/test_tool/enable")
86
+
87
+ assert response.status_code == status.HTTP_200_OK
88
+ assert response.json() == {"message": "Enabled tool: test_tool"}
89
+
90
+ # Verify the tool is enabled
91
+ tool = await mcp._tool_manager.get_tool("test_tool")
92
+ assert tool.enabled is True
93
+
94
+ async def test_disable_tool_route(self, client, mcp):
95
+ """Test disabling a tool via the HTTP route."""
96
+ # First ensure the tool is enabled
97
+ tool = await mcp._tool_manager.get_tool("test_tool")
98
+ tool.enabled = True
99
+
100
+ # Disable the tool via the HTTP route
101
+ response = client.post("/tools/test_tool/disable")
102
+
103
+ assert response.status_code == status.HTTP_200_OK
104
+ assert response.json() == {"message": "Disabled tool: test_tool"}
105
+
106
+ # Verify the tool is disabled
107
+ tool = await mcp._tool_manager.get_tool("test_tool")
108
+ assert tool.enabled is False
109
+
110
+ async def test_enable_resource_route(self, client, mcp):
111
+ """Test enabling a resource via the HTTP route."""
112
+ # First disable the resource
113
+ resource = await mcp._resource_manager.get_resource("data://test_resource")
114
+ resource.enabled = False
115
+
116
+ # Enable the resource via the HTTP route
117
+ response = client.post("/resources/data://test_resource/enable")
118
+
119
+ assert response.status_code == status.HTTP_200_OK
120
+ assert response.json() == {"message": "Enabled resource: data://test_resource"}
121
+
122
+ # Verify the resource is enabled
123
+ resource = await mcp._resource_manager.get_resource("data://test_resource")
124
+ assert resource.enabled is True
125
+
126
+ async def test_disable_resource_route(self, client, mcp):
127
+ """Test disabling a resource via the HTTP route."""
128
+ # First ensure the resource is enabled
129
+ resource = await mcp._resource_manager.get_resource("data://test_resource")
130
+ resource.enabled = True
131
+
132
+ # Disable the resource via the HTTP route
133
+ response = client.post("/resources/data://test_resource/disable")
134
+
135
+ assert response.status_code == status.HTTP_200_OK
136
+ assert response.json() == {"message": "Disabled resource: data://test_resource"}
137
+
138
+ # Verify the resource is disabled
139
+ resource = await mcp._resource_manager.get_resource("data://test_resource")
140
+ assert resource.enabled is False
141
+
142
+ async def test_enable_template_route(self, client, mcp):
143
+ """Test enabling a resource on a mounted server via the parent server's HTTP route."""
144
+ key = "data://test_resource/{id}"
145
+ resource = mcp._resource_manager._templates[key]
146
+ resource.enabled = False
147
+ response = client.post("/resources/data://test_resource/{id}/enable")
148
+ assert response.status_code == status.HTTP_200_OK
149
+ assert response.json() == {
150
+ "message": "Enabled resource: data://test_resource/{id}"
151
+ }
152
+ assert resource.enabled is True
153
+
154
+ async def test_disable_template_route(self, client, mcp):
155
+ """Test disabling a resource on a mounted server via the parent server's HTTP route."""
156
+ key = "data://test_resource/{id}"
157
+ resource = mcp._resource_manager._templates[key]
158
+ resource.enabled = True
159
+ response = client.post("/resources/data://test_resource/{id}/disable")
160
+ assert response.status_code == status.HTTP_200_OK
161
+ assert response.json() == {
162
+ "message": "Disabled resource: data://test_resource/{id}"
163
+ }
164
+ assert resource.enabled is False
165
+
166
+ async def test_enable_prompt_route(self, client, mcp):
167
+ """Test enabling a prompt via the HTTP route."""
168
+ # First disable the prompt
169
+ prompt = await mcp._prompt_manager.get_prompt("test_prompt")
170
+ prompt.enabled = False
171
+
172
+ # Enable the prompt via the HTTP route
173
+ response = client.post("/prompts/test_prompt/enable")
174
+
175
+ assert response.status_code == status.HTTP_200_OK
176
+ assert response.json() == {"message": "Enabled prompt: test_prompt"}
177
+
178
+ # Verify the prompt is enabled
179
+ prompt = await mcp._prompt_manager.get_prompt("test_prompt")
180
+ assert prompt.enabled is True
181
+
182
+ async def test_disable_prompt_route(self, client, mcp):
183
+ """Test disabling a prompt via the HTTP route."""
184
+ # First ensure the prompt is enabled
185
+ prompt = await mcp._prompt_manager.get_prompt("test_prompt")
186
+ prompt.enabled = True
187
+
188
+ # Disable the prompt via the HTTP route
189
+ response = client.post("/prompts/test_prompt/disable")
190
+
191
+ assert response.status_code == status.HTTP_200_OK
192
+ assert response.json() == {"message": "Disabled prompt: test_prompt"}
193
+
194
+ # Verify the prompt is disabled
195
+ prompt = await mcp._prompt_manager.get_prompt("test_prompt")
196
+ assert prompt.enabled is False
197
+
198
+ async def test_enable_tool_route_on_mounted_server(self, client, mounted_mcp):
199
+ """Test enabling a tool on a mounted server via the parent server's HTTP route."""
200
+ # Disable the tool on the sub-server
201
+ sub_tool = await mounted_mcp._tool_manager.get_tool("mounted_tool")
202
+ sub_tool.enabled = False
203
+ # Enable via parent
204
+ response = client.post("/tools/sub_mounted_tool/enable")
205
+ assert response.status_code == status.HTTP_200_OK
206
+ assert response.json() == {"message": "Enabled tool: sub_mounted_tool"}
207
+ # Confirm disabled on sub-server
208
+ assert sub_tool.enabled is True
209
+
210
+ async def test_disable_tool_route_on_mounted_server(self, client, mounted_mcp):
211
+ """Test disabling a tool on a mounted server via the parent server's HTTP route."""
212
+ # Enable the tool on the sub-server
213
+ sub_tool = await mounted_mcp._tool_manager.get_tool("mounted_tool")
214
+ sub_tool.enabled = True
215
+ # Disable via parent
216
+ response = client.post("/tools/sub_mounted_tool/disable")
217
+ assert response.status_code == status.HTTP_200_OK
218
+ assert response.json() == {"message": "Disabled tool: sub_mounted_tool"}
219
+ # Confirm disabled on sub-server
220
+ assert sub_tool.enabled is False
221
+
222
+ async def test_enable_resource_route_on_mounted_server(self, client, mounted_mcp):
223
+ """Test enabling a resource on a mounted server via the parent server's HTTP route."""
224
+ resource = await mounted_mcp._resource_manager.get_resource(
225
+ "data://mounted_resource"
226
+ )
227
+ resource.enabled = False
228
+ response = client.post("/resources/data://sub/mounted_resource/enable")
229
+ assert response.status_code == status.HTTP_200_OK
230
+ assert response.json() == {
231
+ "message": "Enabled resource: data://sub/mounted_resource"
232
+ }
233
+ resource = await mounted_mcp._resource_manager.get_resource(
234
+ "data://mounted_resource"
235
+ )
236
+ assert resource.enabled is True
237
+
238
+ async def test_disable_resource_route_on_mounted_server(self, client, mounted_mcp):
239
+ """Test disabling a resource on a mounted server via the parent server's HTTP route."""
240
+ resource = await mounted_mcp._resource_manager.get_resource(
241
+ "data://mounted_resource"
242
+ )
243
+ resource.enabled = True
244
+ response = client.post("/resources/data://sub/mounted_resource/disable")
245
+ assert response.status_code == status.HTTP_200_OK
246
+ assert response.json() == {
247
+ "message": "Disabled resource: data://sub/mounted_resource"
248
+ }
249
+ resource = await mounted_mcp._resource_manager.get_resource(
250
+ "data://mounted_resource"
251
+ )
252
+ assert resource.enabled is False
253
+
254
+ async def test_enable_template_route_on_mounted_server(self, client, mounted_mcp):
255
+ """Test enabling a resource on a mounted server via the parent server's HTTP route."""
256
+ key = "data://mounted_resource/{id}"
257
+ resource = mounted_mcp._resource_manager._templates[key]
258
+ resource.enabled = False
259
+ response = client.post("/resources/data://sub/mounted_resource/{id}/enable")
260
+ assert response.status_code == status.HTTP_200_OK
261
+ assert response.json() == {
262
+ "message": "Enabled resource: data://sub/mounted_resource/{id}"
263
+ }
264
+ assert resource.enabled is True
265
+
266
+ async def test_disable_template_route_on_mounted_server(self, client, mounted_mcp):
267
+ """Test disabling a resource on a mounted server via the parent server's HTTP route."""
268
+ key = "data://mounted_resource/{id}"
269
+ resource = mounted_mcp._resource_manager._templates[key]
270
+ resource.enabled = True
271
+ response = client.post("/resources/data://sub/mounted_resource/{id}/disable")
272
+ assert response.status_code == status.HTTP_200_OK
273
+ assert response.json() == {
274
+ "message": "Disabled resource: data://sub/mounted_resource/{id}"
275
+ }
276
+ assert resource.enabled is False
277
+
278
+ async def test_enable_prompt_route_on_mounted_server(self, client, mounted_mcp):
279
+ """Test enabling a prompt on a mounted server via the parent server's HTTP route."""
280
+ prompt = await mounted_mcp._prompt_manager.get_prompt("mounted_prompt")
281
+ prompt.enabled = False
282
+ response = client.post("/prompts/sub_mounted_prompt/enable")
283
+ assert response.status_code == status.HTTP_200_OK
284
+ assert response.json() == {"message": "Enabled prompt: sub_mounted_prompt"}
285
+ prompt = await mounted_mcp._prompt_manager.get_prompt("mounted_prompt")
286
+ assert prompt.enabled is True
287
+
288
+ async def test_disable_prompt_route_on_mounted_server(self, client, mounted_mcp):
289
+ """Test disabling a prompt on a mounted server via the parent server's HTTP route."""
290
+ prompt = await mounted_mcp._prompt_manager.get_prompt("mounted_prompt")
291
+ prompt.enabled = True
292
+ response = client.post("/prompts/sub_mounted_prompt/disable")
293
+ assert response.status_code == status.HTTP_200_OK
294
+ assert response.json() == {"message": "Disabled prompt: sub_mounted_prompt"}
295
+ prompt = await mounted_mcp._prompt_manager.get_prompt("mounted_prompt")
296
+ assert prompt.enabled is False
297
+
298
+ def test_enable_nonexistent_tool(self, client):
299
+ """Test enabling a non-existent tool returns 404."""
300
+ response = client.post("/tools/nonexistent_tool/enable")
301
+ assert response.status_code == status.HTTP_404_NOT_FOUND
302
+ assert response.text == "Unknown tool: nonexistent_tool"
303
+
304
+ def test_disable_nonexistent_tool(self, client):
305
+ """Test disabling a non-existent tool returns 404."""
306
+ response = client.post("/tools/nonexistent_tool/disable")
307
+ assert response.status_code == status.HTTP_404_NOT_FOUND
308
+ assert response.text == "Unknown tool: nonexistent_tool"
309
+
310
+ def test_enable_nonexistent_resource(self, client):
311
+ """Test enabling a non-existent resource returns 404."""
312
+ response = client.post("/resources/nonexistent://resource/enable")
313
+ assert response.status_code == status.HTTP_404_NOT_FOUND
314
+ assert response.text == "Unknown resource: nonexistent://resource"
315
+
316
+ def test_disable_nonexistent_resource(self, client):
317
+ """Test disabling a non-existent resource returns 404."""
318
+ response = client.post("/resources/nonexistent://resource/disable")
319
+ assert response.status_code == status.HTTP_404_NOT_FOUND
320
+ assert response.text == "Unknown resource: nonexistent://resource"
321
+
322
+ def test_enable_nonexistent_prompt(self, client):
323
+ """Test enabling a non-existent prompt returns 404."""
324
+ response = client.post("/prompts/nonexistent_prompt/enable")
325
+ assert response.status_code == status.HTTP_404_NOT_FOUND
326
+ assert response.text == "Unknown prompt: nonexistent_prompt"
327
+
328
+ def test_disable_nonexistent_prompt(self, client):
329
+ """Test disabling a non-existent prompt returns 404."""
330
+ response = client.post("/prompts/nonexistent_prompt/disable")
331
+ assert response.status_code == status.HTTP_404_NOT_FOUND
332
+ assert response.text == "Unknown prompt: nonexistent_prompt"
333
+
334
+
335
+ class TestAuthComponentManagementRoutes:
336
+ """Test the component management routes with authentication for tools, resources, and prompts."""
337
+
338
+ def setup_method(self):
339
+ """Set up test fixtures."""
340
+ # Generate a key pair and create an auth provider
341
+ key_pair = RSAKeyPair.generate()
342
+ self.auth = BearerAuthProvider(
343
+ public_key=key_pair.public_key,
344
+ issuer="https://dev.example.com",
345
+ audience="my-dev-server",
346
+ )
347
+ self.mcp = FastMCP("TestServerWithAuth", auth=self.auth)
348
+ set_up_component_manager(server=self.mcp, required_scopes=["tool:write", "tool:read"])
349
+ self.token = key_pair.create_token(
350
+ subject="dev-user",
351
+ issuer="https://dev.example.com",
352
+ audience="my-dev-server",
353
+ scopes=["tool:write", "tool:read"],
354
+ )
355
+ self.token_without_scopes = key_pair.create_token(
356
+ subject="dev-user",
357
+ issuer="https://dev.example.com",
358
+ audience="my-dev-server",
359
+ scopes=["tool:read"],
360
+ )
361
+
362
+ # Add test components
363
+ @self.mcp.tool
364
+ def test_tool() -> str:
365
+ """Test tool for auth testing."""
366
+ return "test_tool_result"
367
+
368
+ @self.mcp.resource("data://test_resource")
369
+ def test_resource() -> str:
370
+ """Test resource for auth testing."""
371
+ return "test_resource_result"
372
+
373
+ @self.mcp.prompt
374
+ def test_prompt() -> str:
375
+ """Test prompt for auth testing."""
376
+ return "test_prompt_result"
377
+
378
+ # Create test client
379
+ self.client = TestClient(self.mcp.http_app())
380
+
381
+ async def test_unauthorized_enable_tool(self):
382
+ """Test that unauthenticated requests to enable a tool are rejected."""
383
+ tool = await self.mcp._tool_manager.get_tool("test_tool")
384
+ tool.enabled = False
385
+
386
+ response = self.client.post("/tools/test_tool/enable")
387
+ assert response.status_code == 401
388
+ assert tool.enabled is False
389
+
390
+ async def test_authorized_enable_tool(self):
391
+ """Test that authenticated requests to enable a tool are allowed."""
392
+ tool = await self.mcp._tool_manager.get_tool("test_tool")
393
+ tool.enabled = False
394
+
395
+ response = self.client.post(
396
+ "/tools/test_tool/enable", headers={"Authorization": "Bearer " + self.token}
397
+ )
398
+ assert response.status_code == 200
399
+ assert response.json() == {"message": "Enabled tool: test_tool"}
400
+ assert tool.enabled is True
401
+
402
+ async def test_unauthorized_disable_tool(self):
403
+ """Test that unauthenticated requests to disable a tool are rejected."""
404
+ tool = await self.mcp._tool_manager.get_tool("test_tool")
405
+ tool.enabled = True
406
+
407
+ response = self.client.post("/tools/test_tool/disable")
408
+ assert response.status_code == 401
409
+ assert tool.enabled is True
410
+
411
+ async def test_authorized_disable_tool(self):
412
+ """Test that authenticated requests to disable a tool are allowed."""
413
+ tool = await self.mcp._tool_manager.get_tool("test_tool")
414
+ tool.enabled = True
415
+
416
+ response = self.client.post(
417
+ "/tools/test_tool/disable",
418
+ headers={"Authorization": "Bearer " + self.token},
419
+ )
420
+ assert response.status_code == 200
421
+ assert response.json() == {"message": "Disabled tool: test_tool"}
422
+ assert tool.enabled is False
423
+
424
+ async def test_forbidden_enable_tool(self):
425
+ """Test that unauthenticated requests to enable a resource are rejected."""
426
+ tool = await self.mcp._tool_manager.get_tool("test_tool")
427
+ tool.enabled = False
428
+
429
+ response = self.client.post(
430
+ "/tools/test_tool/enable",
431
+ headers={"Authorization": "Bearer " + self.token_without_scopes},
432
+ )
433
+ assert response.status_code == 403
434
+ assert tool.enabled is False
435
+
436
+ async def test_authorized_enable_resource(self):
437
+ """Test that authenticated requests to enable a resource are allowed."""
438
+ resource = await self.mcp._resource_manager.get_resource("data://test_resource")
439
+ resource.enabled = False
440
+
441
+ response = self.client.post(
442
+ "/resources/data://test_resource/enable",
443
+ headers={"Authorization": "Bearer " + self.token},
444
+ )
445
+ assert response.status_code == 200
446
+ assert response.json() == {"message": "Enabled resource: data://test_resource"}
447
+ assert resource.enabled is True
448
+
449
+ async def test_unauthorized_disable_resource(self):
450
+ """Test that unauthenticated requests to disable a resource are rejected."""
451
+ resource = await self.mcp._resource_manager.get_resource("data://test_resource")
452
+ resource.enabled = True
453
+
454
+ response = self.client.post("/resources/data://test_resource/disable")
455
+ assert response.status_code == 401
456
+ assert resource.enabled is True
457
+
458
+ async def test_forbidden_enable_resource(self):
459
+ """Test that unauthenticated requests to enable a resource are rejected."""
460
+ resource = await self.mcp._resource_manager.get_resource("data://test_resource")
461
+ resource.enabled = False
462
+
463
+ response = self.client.post(
464
+ "/resources/data://test_resource/disable",
465
+ headers={"Authorization": "Bearer " + self.token_without_scopes},
466
+ )
467
+ assert response.status_code == 403
468
+ assert resource.enabled is False
469
+
470
+ async def test_authorized_disable_resource(self):
471
+ """Test that authenticated requests to disable a resource are allowed."""
472
+ resource = await self.mcp._resource_manager.get_resource("data://test_resource")
473
+ resource.enabled = True
474
+
475
+ response = self.client.post(
476
+ "/resources/data://test_resource/disable",
477
+ headers={"Authorization": "Bearer " + self.token},
478
+ )
479
+ assert response.status_code == 200
480
+ assert response.json() == {"message": "Disabled resource: data://test_resource"}
481
+ assert resource.enabled is False
482
+
483
+ async def test_unauthorized_enable_prompt(self):
484
+ """Test that unauthenticated requests to enable a prompt are rejected."""
485
+ prompt = await self.mcp._prompt_manager.get_prompt("test_prompt")
486
+ prompt.enabled = False
487
+
488
+ response = self.client.post("/prompts/test_prompt/enable")
489
+ assert response.status_code == 401
490
+ assert prompt.enabled is False
491
+
492
+ async def test_authorized_enable_prompt(self):
493
+ """Test that authenticated requests to enable a prompt are allowed."""
494
+ prompt = await self.mcp._prompt_manager.get_prompt("test_prompt")
495
+ prompt.enabled = False
496
+
497
+ response = self.client.post(
498
+ "/prompts/test_prompt/enable",
499
+ headers={"Authorization": "Bearer " + self.token},
500
+ )
501
+ assert response.status_code == 200
502
+ assert response.json() == {"message": "Enabled prompt: test_prompt"}
503
+ assert prompt.enabled is True
504
+
505
+ async def test_unauthorized_disable_prompt(self):
506
+ """Test that unauthenticated requests to disable a prompt are rejected."""
507
+ prompt = await self.mcp._prompt_manager.get_prompt("test_prompt")
508
+ prompt.enabled = True
509
+
510
+ response = self.client.post("/prompts/test_prompt/disable")
511
+ assert response.status_code == 401
512
+ assert prompt.enabled is True
513
+
514
+ async def test_forbidden_disable_prompt(self):
515
+ """Test that unauthenticated requests to enable a resource are rejected."""
516
+ prompt = await self.mcp._prompt_manager.get_prompt("test_prompt")
517
+ prompt.enabled = True
518
+
519
+ response = self.client.post(
520
+ "/prompts/test_prompt/disable",
521
+ headers={"Authorization": "Bearer " + self.token_without_scopes},
522
+ )
523
+ assert response.status_code == 403
524
+ assert prompt.enabled is True
525
+
526
+ async def test_authorized_disable_prompt(self):
527
+ """Test that authenticated requests to disable a prompt are allowed."""
528
+ prompt = await self.mcp._prompt_manager.get_prompt("test_prompt")
529
+ prompt.enabled = True
530
+
531
+ response = self.client.post(
532
+ "/prompts/test_prompt/disable",
533
+ headers={"Authorization": "Bearer " + self.token},
534
+ )
535
+ assert response.status_code == 200
536
+ assert response.json() == {"message": "Disabled prompt: test_prompt"}
537
+ assert prompt.enabled is False