@@ -253,14 +253,19 @@ static const tool_def_t TOOLS[] = {
253253 "\"Optional row limit. Default: unlimited (100k "
254254 "ceiling)\"}},\"required\":[\"query\",\"project\"]}" },
255255
256- {"trace_call_path" ,
257- "Trace function call paths — who calls a function and what it calls. Use INSTEAD OF grep when "
258- "finding callers, dependencies, or impact analysis." ,
256+ {"trace_path" ,
257+ "Trace paths through the code graph. Modes: calls (callers/callees), data_flow (value "
258+ "propagation with args at each hop), cross_service (through HTTP/async Route nodes). "
259+ "Use INSTEAD OF grep for callers, dependencies, impact analysis, or data flow tracing." ,
259260 "{\"type\":\"object\",\"properties\":{\"function_name\":{\"type\":\"string\"},\"project\":{"
260261 "\"type\":\"string\"},\"direction\":{\"type\":\"string\",\"enum\":[\"inbound\",\"outbound\","
261- "\"both\"],\"default\":\"both\"},\"depth\":{\"type\":\"integer\",\"default\":3},\"edge_"
262- "types\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"function_"
263- "name\",\"project\"]}" },
262+ "\"both\"],\"default\":\"both\"},\"depth\":{\"type\":\"integer\",\"default\":3},\"mode\":{"
263+ "\"type\":\"string\",\"enum\":[\"calls\",\"data_flow\",\"cross_service\"],\"default\":"
264+ "\"calls\",\"description\":\"calls: follow CALLS edges. data_flow: follow CALLS+DATA_FLOWS "
265+ "with arg expressions. cross_service: follow HTTP_CALLS+ASYNC_CALLS+DATA_FLOWS through "
266+ "Routes.\"},\"parameter_name\":{\"type\":\"string\",\"description\":\"For data_flow mode: "
267+ "scope trace to a specific parameter name\"},\"edge_types\":{\"type\":\"array\",\"items\":{"
268+ "\"type\":\"string\"}}},\"required\":[\"function_name\",\"project\"]}" },
264269
265270 {"get_code_snippet" ,
266271 "Read source code for a function/class/symbol. IMPORTANT: First call search_graph to find the "
@@ -1223,11 +1228,15 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
12231228 char * project = cbm_mcp_get_string_arg (args , "project" );
12241229 cbm_store_t * store = resolve_store (srv , project );
12251230 char * direction = cbm_mcp_get_string_arg (args , "direction" );
1231+ char * mode = cbm_mcp_get_string_arg (args , "mode" );
1232+ char * param_name = cbm_mcp_get_string_arg (args , "parameter_name" );
12261233 int depth = cbm_mcp_get_int_arg (args , "depth" , 3 );
12271234
12281235 if (!func_name ) {
12291236 free (project );
12301237 free (direction );
1238+ free (mode );
1239+ free (param_name );
12311240 return cbm_mcp_text_result ("function_name is required" , true);
12321241 }
12331242 if (!store ) {
@@ -1237,6 +1246,8 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
12371246 free (func_name );
12381247 free (project );
12391248 free (direction );
1249+ free (mode );
1250+ free (param_name );
12401251 return _res ;
12411252 }
12421253
@@ -1245,6 +1256,8 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
12451256 free (func_name );
12461257 free (project );
12471258 free (direction );
1259+ free (mode );
1260+ free (param_name );
12481261 return not_indexed ;
12491262 }
12501263
@@ -1261,6 +1274,8 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
12611274 free (func_name );
12621275 free (project );
12631276 free (direction );
1277+ free (mode );
1278+ free (param_name );
12641279 cbm_store_free_nodes (nodes , 0 );
12651280 return cbm_mcp_text_result ("{\"error\":\"function not found\"}" , true);
12661281 }
@@ -1271,9 +1286,55 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
12711286
12721287 yyjson_mut_obj_add_str (doc , root , "function" , func_name );
12731288 yyjson_mut_obj_add_str (doc , root , "direction" , direction );
1289+ if (mode ) {
1290+ yyjson_mut_obj_add_str (doc , root , "mode" , mode );
1291+ }
1292+
1293+ /* Edge types: explicit > mode-based > default */
1294+ static const char * mode_calls [] = {"CALLS" };
1295+ static const char * mode_data_flow [] = {"CALLS" , "DATA_FLOWS" };
1296+ static const char * mode_cross_svc [] = {"HTTP_CALLS" , "ASYNC_CALLS" , "DATA_FLOWS" , "CALLS" };
1297+
1298+ const char * edge_types [16 ];
1299+ int edge_type_count = 0 ;
1300+
1301+ /* Try parsing explicit edge_types array from args */
1302+ yyjson_doc * et_doc = yyjson_read (args , strlen (args ), 0 );
1303+ if (et_doc ) {
1304+ yyjson_val * et_arr = yyjson_obj_get (yyjson_doc_get_root (et_doc ), "edge_types" );
1305+ if (et_arr && yyjson_is_arr (et_arr )) {
1306+ size_t idx2 ;
1307+ size_t max2 ;
1308+ yyjson_val * val2 ;
1309+ yyjson_arr_foreach (et_arr , idx2 , max2 , val2 ) {
1310+ if (yyjson_is_str (val2 ) && edge_type_count < 16 ) {
1311+ edge_types [edge_type_count ++ ] = yyjson_get_str (val2 );
1312+ }
1313+ }
1314+ }
1315+ }
12741316
1275- const char * edge_types [] = {"CALLS" };
1276- int edge_type_count = 1 ;
1317+ yyjson_doc * et_doc_keep = et_doc ;
1318+ if (edge_type_count == 0 ) {
1319+ /* Select defaults by mode */
1320+ const char * * defaults = mode_calls ;
1321+ int n_defaults = 1 ;
1322+ if (mode && strcmp (mode , "data_flow" ) == 0 ) {
1323+ defaults = mode_data_flow ;
1324+ n_defaults = 2 ;
1325+ } else if (mode && strcmp (mode , "cross_service" ) == 0 ) {
1326+ defaults = mode_cross_svc ;
1327+ n_defaults = 4 ;
1328+ }
1329+ for (int i = 0 ; i < n_defaults ; i ++ ) {
1330+ edge_types [i ] = defaults [i ];
1331+ }
1332+ edge_type_count = n_defaults ;
1333+ if (et_doc_keep ) {
1334+ yyjson_doc_free (et_doc_keep );
1335+ et_doc_keep = NULL ;
1336+ }
1337+ }
12771338
12781339 /* Run BFS for each requested direction.
12791340 * IMPORTANT: yyjson_mut_obj_add_str borrows pointers — we must keep
@@ -1338,6 +1399,11 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
13381399 free (func_name );
13391400 free (project );
13401401 free (direction );
1402+ free (mode );
1403+ free (param_name );
1404+ if (et_doc_keep ) {
1405+ yyjson_doc_free (et_doc_keep );
1406+ }
13411407
13421408 char * result = cbm_mcp_text_result (json , false);
13431409 free (json );
@@ -2698,7 +2764,7 @@ char *cbm_mcp_handle_tool(cbm_mcp_server_t *srv, const char *tool_name, const ch
26982764 if (strcmp (tool_name , "delete_project" ) == 0 ) {
26992765 return handle_delete_project (srv , args_json );
27002766 }
2701- if (strcmp (tool_name , "trace_call_path" ) == 0 ) {
2767+ if (strcmp (tool_name , "trace_path" ) == 0 || strcmp ( tool_name , " trace_call_path" ) == 0 ) {
27022768 return handle_trace_call_path (srv , args_json );
27032769 }
27042770 if (strcmp (tool_name , "get_architecture" ) == 0 ) {
0 commit comments