cfg_explain_route
Analyze any OpenSIPS route block to identify its components: SIP methods handled, module functions called, conditions, and overall flow. Understand routing logic with clear breakdown.
Instructions
Explain an OpenSIPS route block by identifying its components.
Analyzes the route code and identifies SIP methods handled, module functions called, conditions, and overall flow.
Parameters
route_code:
The route block code to explain (e.g. the body of a route{...}).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| route_code | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- The `cfg_explain_route` tool handler function. It analyzes an OpenSIPS route block by detecting SIP methods via is_method(), module function calls, flags, AVPs, sub-route calls, and conditions. Returns a dict with methods_handled, module_functions, conditions, flags_used, avps_used, sub_routes_called, and a summary.
@mcp.tool() @require_permission("config.read") async def cfg_explain_route( ctx: Context, route_code: str, ) -> dict[str, Any]: """Explain an OpenSIPS route block by identifying its components. Analyzes the route code and identifies SIP methods handled, module functions called, conditions, and overall flow. Parameters ---------- route_code: The route block code to explain (e.g. the body of a ``route{...}``). """ explanation: dict[str, Any] = { "methods_handled": [], "module_functions": [], "conditions": [], "flags_used": [], "avps_used": [], "sub_routes_called": [], "summary": "", } # Detect SIP methods method_re = re.compile(r'is_method\s*\(\s*"([^"]+)"\s*\)') for m in method_re.finditer(route_code): for method in m.group(1).split("|"): if method not in explanation["methods_handled"]: explanation["methods_handled"].append(method) # Detect module function calls func_re = re.compile(r"\b([a-z_]+)\s*\(") known_opensips_funcs = { "t_relay", "t_check_trans", "t_on_failure", "t_on_reply", "t_on_branch", "sl_send_reply", "record_route", "loose_route", "has_totag", "mf_process_maxfwd_header", "fix_nated_contact", "fix_nated_register", "nat_uac_test", "force_rport", "save", "lookup", "create_dialog", "www_authorize", "www_challenge", "proxy_authorize", "proxy_challenge", "consume_credentials", "check_from", "ds_select_dst", "ds_next_dst", "do_routing", "use_next_gw", "lb_start", "lb_next", "lb_disable_dst", "do_accounting", "setflag", "setbflag", "isbflagset", "isflagset", "rtpengine_offer", "rtpengine_answer", "rtpengine_delete", "rtpengine_use_set", "pike_check_req", "handle_subscribe", "handle_publish", "cc_handle_call", "b2b_init_request", "is_from_local", "is_uri_host_local", "xlog", } for m in func_re.finditer(route_code): fname = m.group(1) if fname in known_opensips_funcs and fname not in explanation["module_functions"]: explanation["module_functions"].append(fname) # Detect flags flag_re = re.compile(r'(?:setflag|setbflag|isbflagset|isflagset)\s*\(\s*"?([^")\s]+)"?\s*\)') for m in flag_re.finditer(route_code): if m.group(1) not in explanation["flags_used"]: explanation["flags_used"].append(m.group(1)) # Detect AVPs avp_re = re.compile(r"\$avp\(([^)]+)\)") for m in avp_re.finditer(route_code): if m.group(1) not in explanation["avps_used"]: explanation["avps_used"].append(m.group(1)) # Detect sub-route calls route_call_re = re.compile(r"route\s*\(\s*(\w+)\s*\)") for m in route_call_re.finditer(route_code): if m.group(1) not in explanation["sub_routes_called"]: explanation["sub_routes_called"].append(m.group(1)) # Detect conditions cond_re = re.compile(r"if\s*\((.+?)\)\s*\{") for m in cond_re.finditer(route_code): cond = m.group(1).strip() if len(cond) < 120: explanation["conditions"].append(cond) # Build summary parts = [] if explanation["methods_handled"]: parts.append(f"Handles SIP methods: {', '.join(explanation['methods_handled'])}") if explanation["module_functions"]: parts.append(f"Calls {len(explanation['module_functions'])} OpenSIPS functions") if explanation["sub_routes_called"]: parts.append(f"Delegates to sub-routes: {', '.join(explanation['sub_routes_called'])}") if explanation["flags_used"]: parts.append(f"Uses flags: {', '.join(explanation['flags_used'])}") explanation["summary"] = ". ".join(parts) + "." if parts else "Empty or unrecognized route." return explanation - The output schema/dict structure that cfg_explain_route returns, including keys: methods_handled, module_functions, conditions, flags_used, avps_used, sub_routes_called, summary.
explanation: dict[str, Any] = { "methods_handled": [], "module_functions": [], "conditions": [], "flags_used": [], "avps_used": [], "sub_routes_called": [], "summary": "", } - src/opensips_mcp/tools/cfg_tools.py:262-263 (registration)Registration of cfg_explain_route as an MCP tool via the @mcp.tool() decorator, with @require_permission('config.read') for RBAC.
@mcp.tool() @require_permission("config.read") - The Explainer instance (_explainer) is initialized here but is used by cfg_explain (the "kubectl explain" tool), not by cfg_explain_route. cfg_explain_route uses inline logic and a hardcoded set of known_opensips_funcs.
_explainer = Explainer()