Skip to content

Commit 80772e3

Browse files
author
Your Name
committed
feat(mcp): process participation in search_graph results
BM25 search results now include a 'processes' array showing which execution flows each result symbol participates in (up to 5 per symbol). Uses a single prepared statement with process_steps JOIN for efficiency. This closes the gap with flow-grouped search: users can see not just the symbol name and file, but which end-to-end flows it belongs to. Requires sqlite3.h include in mcp.c for direct SQLite access to the process_steps table via cbm_store_get_db().
1 parent 00b096d commit 80772e3

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

src/mcp/mcp.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "mcp/mcp.h"
1111
#include "store/store.h"
12+
#include <sqlite3.h>
1213
#include "cypher/cypher.h"
1314
#include "pipeline/pipeline.h"
1415
#include "cli/cli.h"
@@ -1002,6 +1003,21 @@ static char *handle_search_graph(cbm_mcp_server_t *srv, const char *args) {
10021003

10031004
yyjson_mut_obj_add_int(doc, root, "total", out.total);
10041005

1006+
/* For each result, look up which execution flows it participates in.
1007+
* This enables process-grouped search results similar to GitNexus's
1008+
* flow-aware query output. Uses a single prepared statement. */
1009+
sqlite3_stmt *proc_stmt = NULL;
1010+
{
1011+
const char *psql =
1012+
"SELECT DISTINCT p.id, p.label, p.step_count FROM process_steps ps "
1013+
"JOIN processes p ON p.id = ps.process_id AND p.project = ?2 "
1014+
"WHERE ps.node_id = ?1 LIMIT 5";
1015+
sqlite3_prepare_v2(cbm_store_get_db(store), psql, -1, &proc_stmt, NULL);
1016+
if (proc_stmt) {
1017+
sqlite3_bind_text(proc_stmt, 2, project, -1, SQLITE_STATIC);
1018+
}
1019+
}
1020+
10051021
yyjson_mut_val *results = yyjson_mut_arr(doc);
10061022
for (int i = 0; i < out.count; i++) {
10071023
cbm_search_result_t *sr = &out.results[i];
@@ -1014,8 +1030,28 @@ static char *handle_search_graph(cbm_mcp_server_t *srv, const char *args) {
10141030
sr->node.file_path ? sr->node.file_path : "");
10151031
yyjson_mut_obj_add_int(doc, item, "in_degree", sr->in_degree);
10161032
yyjson_mut_obj_add_int(doc, item, "out_degree", sr->out_degree);
1033+
1034+
/* Process participation */
1035+
if (proc_stmt && sr->node.id > 0) {
1036+
sqlite3_reset(proc_stmt);
1037+
sqlite3_bind_int64(proc_stmt, 1, sr->node.id);
1038+
1039+
yyjson_mut_val *proc_arr = yyjson_mut_arr(doc);
1040+
while (sqlite3_step(proc_stmt) == SQLITE_ROW) {
1041+
yyjson_mut_val *pobj = yyjson_mut_obj(doc);
1042+
yyjson_mut_obj_add_int(doc, pobj, "id", sqlite3_column_int64(proc_stmt, 0));
1043+
const char *plabel = (const char *)sqlite3_column_text(proc_stmt, 1);
1044+
yyjson_mut_obj_add_strcpy(doc, pobj, "label", plabel ? plabel : "");
1045+
yyjson_mut_obj_add_int(doc, pobj, "step_count", sqlite3_column_int(proc_stmt, 2));
1046+
yyjson_mut_arr_add_val(proc_arr, pobj);
1047+
}
1048+
yyjson_mut_obj_add_val(doc, item, "processes", proc_arr);
1049+
}
1050+
10171051
yyjson_mut_arr_add_val(results, item);
10181052
}
1053+
if (proc_stmt) sqlite3_finalize(proc_stmt);
1054+
10191055
yyjson_mut_obj_add_val(doc, root, "results", results);
10201056
yyjson_mut_obj_add_bool(doc, root, "has_more", out.total > offset + out.count);
10211057

0 commit comments

Comments
 (0)