diff --git a/bunnycdn_mcp/tools/shield.py b/bunnycdn_mcp/tools/shield.py index 6144ad1..4385113 100644 --- a/bunnycdn_mcp/tools/shield.py +++ b/bunnycdn_mcp/tools/shield.py @@ -258,6 +258,100 @@ def register_shield_tools(mcp): logger.error("bunny_shield_metrics failed: %s", e) return f"Error: {e}" + # -- Bot Detection (Advanced plan required) -- + + @mcp.tool() + async def bunny_bot_detection_get( + shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], + ) -> str: + """Get Bot Detection configuration for a Shield Zone. Requires Advanced plan ($9.50/month).""" + try: + data = await client.get(f"/shield/bot-detection/{shield_zone_id}/configuration") + return json.dumps(data, indent=2) + except Exception as e: + logger.error("bunny_bot_detection_get failed: %s", e) + return f"Error: {e}" + + @mcp.tool() + async def bunny_bot_detection_update( + shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], + settings: Annotated[str, Field(description="JSON string of bot detection settings")], + ) -> str: + """Update Bot Detection configuration. Requires Advanced plan ($9.50/month).""" + try: + parsed = json.loads(settings) + except json.JSONDecodeError as e: + return f"Error: Invalid JSON: {e}" + try: + data = await client.put(f"/shield/bot-detection/{shield_zone_id}/configuration", json=parsed) + return json.dumps(data, indent=2) if isinstance(data, dict) else f"Bot detection updated for zone {shield_zone_id}" + except Exception as e: + logger.error("bunny_bot_detection_update failed: %s", e) + return f"Error: {e}" + + # -- Access Lists (Advanced plan required) -- + + @mcp.tool() + async def bunny_access_lists( + shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], + ) -> str: + """List Access Lists for a Shield Zone. Requires Advanced plan ($9.50/month).""" + try: + data = await client.get(f"/shield/access-lists/{shield_zone_id}") + return json.dumps(data, indent=2) + except Exception as e: + logger.error("bunny_access_lists failed: %s", e) + return f"Error: {e}" + + @mcp.tool() + async def bunny_access_list_create( + shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], + rule: Annotated[str, Field(description="JSON string of access list rule (IPs, CIDRs, ASNs, or countries with allow/block/challenge/log action)")], + ) -> str: + """Create an Access List rule. Requires Advanced plan ($9.50/month).""" + try: + parsed = json.loads(rule) + parsed["shieldZoneId"] = shield_zone_id + except json.JSONDecodeError as e: + return f"Error: Invalid JSON: {e}" + try: + data = await client.post(f"/shield/access-lists/{shield_zone_id}", json=parsed) + return json.dumps(data, indent=2) + except Exception as e: + logger.error("bunny_access_list_create failed: %s", e) + return f"Error: {e}" + + @mcp.tool() + async def bunny_access_list_update( + shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], + rule_id: Annotated[int, Field(description="Access list rule ID")], + rule: Annotated[str, Field(description="JSON string of updated access list rule")], + ) -> str: + """Update an Access List rule. Requires Advanced plan ($9.50/month).""" + try: + parsed = json.loads(rule) + except json.JSONDecodeError as e: + return f"Error: Invalid JSON: {e}" + try: + data = await client.put(f"/shield/access-lists/{shield_zone_id}/{rule_id}", json=parsed) + return json.dumps(data, indent=2) if isinstance(data, dict) else f"Access list {rule_id} updated" + except Exception as e: + logger.error("bunny_access_list_update failed: %s", e) + return f"Error: {e}" + + @mcp.tool() + async def bunny_access_list_delete( + shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], + rule_id: Annotated[int, Field(description="Access list rule ID to delete")], + ) -> str: + """Delete an Access List rule. Requires Advanced plan ($9.50/month).""" + try: + await client.delete(f"/shield/access-lists/{shield_zone_id}/{rule_id}") + return f"Access list rule {rule_id} deleted" + except Exception as e: + logger.error("bunny_access_list_delete failed: %s", e) + return f"Error: {e}" + # -- DDoS Enums -- @mcp.tool()