Managing Model Context Protocol in iRules - Part 3
In part 2 of this series, we took a look at a couple iRules use cases that do not require the json or sse profiles and don't capitalize on the new JSON commands and events introduced in the v21 release. That changes now! In this article, we'll take a look at two use cases for logging MCP activity and removing MCP tools from a servers tool list.
Event logging
This iRule logs various HTTP, SSE, and JSON-related events for debugging and monitoring purposes. It provides clear visibility into request/response flow and detects anomalies or errors.
How it works
- HTTP_REQUEST
- Logs each HTTP request with its URI and client IP.
- Example: "HTTP request received: URI /example from 192.168.1.1"
- SSE_RESPONSE
- Logs when a Server-Sent Event (SSE) response is identified.
- Example: "SSE response detected successfully."
- JSON_REQUEST and JSON_RESPONSE
- Logs when valid JSON requests or responses are detected
- Examples:
- "JSON Request detected successfully"
- JSON Response detected successfully"
- JSON_REQUEST_MISSING and JSON_RESPONSE_MISSING
- Logs if JSON payloads are missing from requests or responses.
- Examples:
- "JSON Request missing."
- "JSON Response missing."
- JSON_REQUEST_ERROR and JSON_RESPONSE_ERROR
- Logs when there are errors in parsing JSON during requests or responses.
- Examples:
- "Error processing JSON request. Rejecting request."
- "Error processing JSON response."
iRule: Event Logging
when HTTP_REQUEST {
# Log the event (for debugging)
log local0. "HTTP request received: URI [HTTP::uri] from [IP::client_addr]"
when SSE_RESPONSE {
# Triggered when a Server-Sent Event response is detected
log local0. "SSE response detected successfully."
}
when JSON_REQUEST {
# Triggered when the JSON request is detected
log local0. "JSON Request detected successfully."
}
when JSON_RESPONSE {
# Triggered when a Server-Sent Event response is detected
log local0. "JSON response detected successfully."
}
when JSON_RESPONSE_MISSING {
# Triggered when the JSON payload is missing from the server response
log local0. "JSON Response missing."
}
when JSON_REQUEST_MISSING {
# Triggered when the JSON is missing or can't be parsed in the request
log local0. "JSON Request missing."
}
when JSON_RESPONSE_ERROR {
# Triggered when there's an error in the JSON response processing
log local0. "Error processing JSON response."
#HTTP::respond 500 content "Invalid JSON response from server."
}
when JSON_REQUEST_ERROR {
# Triggered when an error occurs (e.g., malformed JSON) during JSON processing
log local0. "Error processing JSON request. Rejecting request."
#HTTP::respond 400 content "Malformed JSON payload. Please check your input."
}
MCP tool removal
This iRule modifies server JSON responses by removing disallowed tools from the result.tools array while logging detailed debugging information.
How it works
- JSON parsing and logging
- print procedure - recursively traverses and logs the JSON structure, including arrays, objects, strings, and other types.
- jpath procedure - extracts values or JSON elements based on a provided path, allowing targeted retrieval of nested properties.
- JSON response handling
- When JSON_RESPONSE is triggered:
- Logs the root JSON object and parses it using JSON::root.
- Extracts the tools array from result.tools.
- When JSON_RESPONSE is triggered:
- Tool removal logic
- Iterates over the tools array and retrieves the name of each tool.
- If the tool name matches start-notification-stream:
- Removes it from the array using JSON::array remove.
- Logs that the tool is not allowed.
- If the tool does not match:
- Logs that the tool is allowed and moves to the next one.
- Logging information
- Logs all JSON structures and actions:
- Full JSON structure.
- Extracted tools array.
- Tools allowed or removed.
- Logs all JSON structures and actions:
Input JSON Response
{
"result": {
"tools": [
{"name": "start-notification-stream"},
{"name": "allowed-tool"}
]
}
}
Modified Response
{
"result": {
"tools": [
{"name": "allowed-tool"}
]
}
}
iRule: Remove tool list
# Code to check JSON and print in logs
proc print { e } {
set t [JSON::type $e]
set v [JSON::get $e]
set p0 [string repeat " " [expr {2 * ([info level] - 1)}]]
set p [string repeat " " [expr {2 * [info level]}]]
switch $t {
array {
log local0. "$p0\["
set size [JSON::array size $v]
for {set i 0} {$i < $size} {incr i} {
set e2 [JSON::array get $v $i]
call print $e2
}
log local0. "$p0\]"
}
object {
log local0. "$p0{"
set keys [JSON::object keys $v]
foreach k $keys {
set e2 [JSON::object get $v $k]
log local0. "$p${k}:"
call print $e2
}
log local0. "$p0}"
}
string - literal {
set v2 [JSON::get $e $t]
log local0. "$p\"$v2\""
}
default {
set v2 [JSON::get $e $t]
log local0. "$p$v2"
}
}
}
proc jpath { e path {d .} } {
if { [catch {set v [call jpath2 $e $path $d]} err] } {
return ""
}
return $v
}
proc jpath2 { e path {d .} } {
set parray [split $path $d]
set plen [llength $parray]
set i 0
for {} {$i < [expr {$plen }]} {incr i} {
set p [lindex $parray $i]
set t [JSON::type $e]
set v [JSON::get $e]
if { $t eq "array" } {
# array
set e [JSON::array get $v $p]
} else {
# object
set e [JSON::object get $v $p]
}
}
set t [JSON::type $e]
set v [JSON::get $e $t]
return $v
}
# Modify in response
when JSON_RESPONSE {
log local0. "JSON::root"
set root [JSON::root]
call print $root
set tools [call jpath $root result.tools]
log local0. "root = $root tools= $tools"
if { $tools ne "" } {
log local0. "TOOLS not empty"
set i 0
set block_tool "start-notification-stream"
while { $i < 100 } {
set name [call jpath $root result.tools.${i}.name]
if { $name eq "" } { break }
if { $name eq $block_tool } {
log local0. "tool $name is not alowed"
JSON::array remove $tools $i
} else {
log local0. "tool $name is alowed"
incr i
}
}
} else {
log local0. "no tools"
}
}
Conclusion
This not only concludes the article, but also this introductory series on managing MCP in iRules. Note that all these commands handle all things JSON, so you are not limited to MCP contexts. We look forward to what the community will build (and hopefully share back) with this new functionality!
NOTE: This series is ghostwritten. Awaiting permission from original author to credit.