workspace/skills/f5-config-mgmt/SKILL.md
F5 BIG-IP configuration management - safe change workflow with baseline capture, planning, creation/update/deletion of virtual servers, pools, iRules, and profiles with full verification. Use when creating or modifying F5 virtual servers, adding pool members, deploying iRules, performing blue-green traffic shifts, or rolling back a BIG-IP change.
npx skillsauth add automateyournetwork/netclaw f5-config-mgmtInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
NEVER apply configuration without first capturing a baseline. If the change goes wrong, you need to know what to restore.
The F5 MCP server provides 6 tools. Call them via mcp-call with the required environment variables:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" <tool_name> '{"param":"value"}'
| Tool | Purpose | HTTP Method | Key Arguments |
|------|---------|-------------|---------------|
| list_tool | List F5 objects | GET | object_name, object_type |
| show_stats_tool | Show object statistics | GET | object_name, object_type |
| show_logs_tool | Show system logs | GET | lines_number |
| create_tool | Create objects | POST | url_body, object_type |
| update_tool | Update objects | PATCH | url_body, object_type, object_name |
| delete_tool | Delete objects | DELETE | object_type, object_name |
Object types: virtual, pool, irule, profile
Capture the current state of everything the change might affect. This is the rollback reference.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" list_tool '{"object_name":"","object_type":"virtual"}'
Store the full list of virtual servers, their configurations, pool assignments, and profiles.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" list_tool '{"object_name":"","object_type":"pool"}'
Store pool configurations, member lists, monitor assignments, and load balancing methods.
For each affected object, capture current stats to compare post-change:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"my_virtual_server","object_type":"virtual"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"my_pool","object_type":"pool"}'
Record the last 50 lines of logs to establish a timestamp reference:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_logs_tool '{"lines_number":"50"}'
Note the most recent log timestamp -- any errors after this timestamp are change-related.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" list_tool '{"object_name":"","object_type":"irule"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" list_tool '{"object_name":"","object_type":"profile"}'
Before applying any configuration, explicitly state:
Use create_tool to create new objects via POST. The url_body dict contains the iControl REST API body.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"pool_webapp","monitor":"http","loadBalancingMode":"round-robin","members":["10.1.1.10:80","10.1.1.11:80","10.1.1.12:80"]},"object_type":"pool"}'
Pool creation best practices:
http, https, tcp, icmp, or a custom monitor)round-robin -- default, equal distributionleast-connections-member -- best for unequal server capacity or variable request durationratio-member -- weighted distribution for heterogeneous backendsfastest-node -- route to fastest responding serverserviceDownAction for graceful failure handling:
none -- connections persist on down member until timeoutreset -- RST sent to clientsreselect -- reselect a new member (recommended for HTTP)drop -- silently drop connectionsminActiveMembers to trigger action when too many members faildescription for documentationIP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"pool_api_backend","monitor":"https_443","loadBalancingMode":"least-connections-member","minActiveMembers":2,"serviceDownAction":"reselect","slowRampTime":300,"description":"API backend pool - managed by NetClaw","members":["10.2.1.20:443","10.2.1.21:443","10.2.1.22:443","10.2.1.23:443"]},"object_type":"pool"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"vs_webapp_https","destination":"10.100.1.50:443","ipProtocol":"tcp","pool":"pool_webapp","sourceAddressTranslation":{"type":"automap"},"profiles":[{"name":"clientssl"},{"name":"http"},{"name":"tcp-wan-optimized","context":"clientside"},{"name":"tcp-lan-optimized","context":"serverside"}],"description":"HTTPS virtual server for webapp - managed by NetClaw"},"object_type":"virtual"}'
Virtual server creation best practices:
destination as VIP_IP:portsourceAddressTranslation (automap or SNAT pool) unless servers have BIG-IP as default gatewaytcp-wan-optimized on clientside, tcp-lan-optimized on serversidepool to the backend pool namedescription for documentationconnectionLimit to protect backend serversIP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"vs_webapp_http","destination":"10.100.1.50:80","ipProtocol":"tcp","pool":"pool_webapp","sourceAddressTranslation":{"type":"automap"},"profiles":[{"name":"http"},{"name":"tcp-wan-optimized","context":"clientside"},{"name":"tcp-lan-optimized","context":"serverside"}],"description":"HTTP virtual server for webapp - managed by NetClaw"},"object_type":"virtual"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"vs_webapp_redirect","destination":"10.100.1.50:80","ipProtocol":"tcp","profiles":[{"name":"http"}],"rules":["/Common/redirect_to_https"],"description":"HTTP-to-HTTPS redirect - managed by NetClaw"},"object_type":"virtual"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"redirect_to_https","apiAnonymous":"when HTTP_REQUEST {\n HTTP::redirect https://[HTTP::host][HTTP::uri]\n}"},"object_type":"irule"}'
iRule creation best practices:
log statements in production iRules on high-traffic virtual serversHTTP::collect with HTTP::release to prevent memory leakscatch blocks for error handling in complex iRulesIP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"insert_headers","apiAnonymous":"when HTTP_REQUEST {\n HTTP::header insert X-Forwarded-Proto https\n HTTP::header insert X-Real-IP [IP::client_addr]\n}\nwhen HTTP_RESPONSE {\n HTTP::header insert Strict-Transport-Security \"max-age=31536000; includeSubDomains\"\n}"},"object_type":"irule"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"maintenance_page","apiAnonymous":"when HTTP_REQUEST {\n HTTP::respond 503 content \"<html><body><h1>Service Temporarily Unavailable</h1><p>We are performing scheduled maintenance. Please try again later.</p></body></html>\" Content-Type \"text/html\"\n}"},"object_type":"irule"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"uri_routing","apiAnonymous":"when HTTP_REQUEST {\n switch -glob [string tolower [HTTP::uri]] {\n \"/api/*\" { pool pool_api_backend }\n \"/static/*\" { pool pool_static_content }\n default { pool pool_webapp }\n }\n}"},"object_type":"irule"}'
Use update_tool to modify existing objects via PATCH. Only include the fields you want to change.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"members":["10.1.1.10:80","10.1.1.11:80","10.1.1.12:80","10.1.1.13:80"]},"object_type":"pool","object_name":"pool_webapp"}'
WARNING: The members list in an update is a full replacement, not an append. Always include ALL desired members (existing + new) in the list. Omitting existing members will remove them.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"loadBalancingMode":"least-connections-member"},"object_type":"pool","object_name":"pool_webapp"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"monitor":"https_443"},"object_type":"pool","object_name":"pool_api_backend"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"pool":"pool_webapp_v2"},"object_type":"virtual","object_name":"vs_webapp_https"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"rules":["/Common/redirect_to_https","/Common/insert_headers"]},"object_type":"virtual","object_name":"vs_webapp_https"}'
WARNING: The rules list in an update is a full replacement. Include ALL desired iRules in the list.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"enabled":false},"object_type":"virtual","object_name":"vs_webapp_https"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"enabled":true},"object_type":"virtual","object_name":"vs_webapp_https"}'
Use delete_tool to remove objects. Always verify no dependencies exist before deletion.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" delete_tool '{"object_type":"pool","object_name":"pool_old_webapp"}'
CRITICAL: You cannot delete a pool that is still assigned to a virtual server. Remove the pool reference from the virtual server first, or reassign to a different pool.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" delete_tool '{"object_type":"virtual","object_name":"vs_old_webapp"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" delete_tool '{"object_type":"irule","object_name":"old_redirect_rule"}'
CRITICAL: You cannot delete an iRule that is still assigned to a virtual server. Remove the iRule reference from the virtual server first.
When decommissioning a full application stack, delete in this order:
Reversing this order will cause dependency errors.
A common F5 change pattern is shifting traffic between pool versions for deployments.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" create_tool '{"url_body":{"name":"pool_webapp_v2","monitor":"http","loadBalancingMode":"round-robin","members":["10.1.2.10:80","10.1.2.11:80","10.1.2.12:80"],"description":"Webapp v2.0 pool - blue/green deployment"},"object_type":"pool"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"pool_webapp_v2","object_type":"pool"}'
Confirm all members are available and passing health checks before shifting traffic.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"pool":"pool_webapp_v2"},"object_type":"virtual","object_name":"vs_webapp_https"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"vs_webapp_https","object_type":"virtual"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"pool_webapp_v2","object_type":"pool"}'
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_logs_tool '{"lines_number":"100"}'
Verify traffic is flowing to the new pool, no errors in logs, and response times are acceptable.
If the new pool is unhealthy, immediately revert to the old pool:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"pool":"pool_webapp"},"object_type":"virtual","object_name":"vs_webapp_https"}'
Once the new pool is verified stable (after appropriate burn-in period), remove the old pool:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" delete_tool '{"object_type":"pool","object_name":"pool_webapp"}'
Immediately after applying configuration, verify the change.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" list_tool '{"object_name":"pool_webapp","object_type":"pool"}'
Compare with the pre-change baseline to confirm only intended changes were made.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"pool_webapp","object_type":"pool"}'
Confirm:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_logs_tool '{"lines_number":"100"}'
Look for new error messages that appeared after the Phase 1D baseline timestamp.
If you changed a pool, verify the virtual servers that reference it are still healthy:
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" show_stats_tool '{"object_name":"vs_webapp_https","object_type":"virtual"}'
If verification fails, roll back by restoring the baseline state.
For created objects: Delete the newly created object.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" delete_tool '{"object_type":"pool","object_name":"pool_webapp_v2"}'
For updated objects: Patch the object with the original values from the baseline.
IP_ADDRESS=$F5_IP_ADDRESS Authorization_string=$F5_AUTH_STRING python3 $MCP_CALL "python3 -u $F5_MCP_SCRIPT" update_tool '{"url_body":{"pool":"pool_webapp"},"object_type":"virtual","object_name":"vs_webapp_https"}'
For deleted objects: Recreate the object using the baseline configuration.
After rollback, re-verify that the BIG-IP returned to its baseline state.
After every change, produce a change report:
F5 Change Report -- YYYY-MM-DD HH:MM UTC
Device: $F5_IP_ADDRESS
Requestor: [who requested the change]
Change Description:
Created pool_webapp with 3 members for new web application
Objects Modified:
[CREATED] pool_webapp (pool) -- 3 members, round-robin, HTTP monitor
[CREATED] vs_webapp_https (virtual) -- 10.100.1.50:443, SSL offload, automap
Pre-Change State:
- Virtual servers: 4 active
- Pools: 3 active
- No errors in logs
Post-Change State:
- Virtual servers: 5 active (+1 vs_webapp_https)
- Pools: 4 active (+1 pool_webapp)
- pool_webapp: 3/3 members available
- vs_webapp_https: available, accepting connections
- New log entries: pool_webapp member 10.1.1.10:80 monitor status up (expected)
Verification: PASSED
Rollback Required: No
When ServiceNow is available ($SERVICENOW_MCP_SCRIPT is set), every F5 configuration change MUST be gated by an approved Change Request.
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" create_change_request '{"short_description":"Create pool_webapp and vs_webapp_https on F5 BIG-IP","description":"Create new pool with 3 web server members (10.1.1.10-12:80) and HTTPS virtual server (10.100.1.50:443) with SSL offload. Health monitor: HTTP. Load balancing: round-robin. Rollback: delete vs_webapp_https then pool_webapp.","category":"Network","priority":"3","risk":"moderate","impact":"3"}'
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" get_change_request_details '{"change_id":"CHG0012345"}'
STOP if state is not approved. Inform the human and wait.
If verification passes:
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0012345","work_notes":"Change applied and verified. pool_webapp 3/3 members available, vs_webapp_https accepting connections, no errors in logs.","state":"closed"}'
If verification fails:
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0012345","work_notes":"Post-change verification FAILED. Rollback initiated. Objects removed. Human review required.","state":"review"}'
| Skill | Integration Point | |-------|------------------| | f5-health-check | Pre-change health validation and post-change verification | | f5-troubleshoot | Investigate failures during verification phase | | servicenow-change-workflow | CR creation, approval gate, closure | | drawio-diagram | Generate before/after topology diagrams | | markmap-viz | Visualize change plan as a mind map | | gait-session-tracking | Audit trail for every phase |
Record every phase of the change in GAIT:
python3 $MCP_CALL "python3 -u $GAIT_MCP_SCRIPT" gait_record_turn '{"prompt":"F5 config change: Create pool_webapp and vs_webapp_https","response":"Phase 1 baseline captured (4 virtuals, 3 pools, no errors). Phase 2 plan approved. Phase 3 applied: created pool_webapp (3 members, HTTP monitor, round-robin) and vs_webapp_https (10.100.1.50:443, SSL offload, automap). Phase 4 verification PASSED: all members available, VIP accepting connections, no log errors. ServiceNow CR CHG0012345 closed successful.","artifacts":["f5-change-report.txt"]}'
The 5-phase workflow with GAIT creates an immutable record:
testing
Human-in-the-loop escalation via HumanRail — route low-confidence agent decisions, pre-destructive operation approvals, and ambiguous incident tickets to real human engineers. Human answers are verified and returned as structured output. Workers are paid via Lightning Network. Use when the agent is uncertain, when a destructive change needs explicit human sign-off beyond a ServiceNow CR, or when an ambiguous ticket requires human triage before automated handling.
testing
Manage EVE-NG node lifecycle. Use when listing nodes, checking runtime state, creating or deleting nodes, starting or stopping nodes or whole labs, verifying node details, or wiping node NVRAM back to factory defaults.
development
Manage EVE-NG labs and platform inventory. Use when listing labs, checking lab metadata, creating or deleting labs, importing or exporting lab archives, checking EVE-NG health or auth, or verifying available node images before build work.
tools
Execute live CLI commands on running EVE-NG nodes over telnet console. Use when running show commands, making live config changes, verifying protocol state, testing connectivity, checking console readiness, or interacting with IOS, Junos, VPCS, EOS, or NX-OS nodes.