Skip to content

Commit d7cc2f7

Browse files
author
Your Name
committed
feat(mcp): cross-repo channel query + has_property in trace output
Cross-repo channels: when get_channels is called without a project parameter, iterates ALL indexed project .db files in the cache directory, queries each for matching channels, and merges results. Enables cross-service message flow tracing (e.g., find all repos that emit/listen on 'UserCreated'). has_property in trace: trace_call_path now includes outgoing.has_property section for Class/Interface nodes, showing all property nodes linked via HAS_PROPERTY edges — property name, file path, and line number.
1 parent 0aa615a commit d7cc2f7

1 file changed

Lines changed: 68 additions & 3 deletions

File tree

src/mcp/mcp.c

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,12 +1486,54 @@ static char *handle_get_impact(cbm_mcp_server_t *srv, const char *args) {
14861486
static char *handle_get_channels(cbm_mcp_server_t *srv, const char *args) {
14871487
char *project = cbm_mcp_get_string_arg(args, "project");
14881488
char *channel = cbm_mcp_get_string_arg(args, "channel");
1489-
cbm_store_t *store = resolve_store(srv, project);
1490-
REQUIRE_STORE(store, project);
14911489

1490+
/* Cross-repo channel query: when project is NULL, iterate all indexed projects */
14921491
cbm_channel_info_t *channels = NULL;
14931492
int count = 0;
1494-
cbm_store_find_channels(store, project, channel, &channels, &count);
1493+
1494+
if (!project || strlen(project) == 0) {
1495+
char dir_path[1024];
1496+
cache_dir(dir_path, sizeof(dir_path));
1497+
cbm_dir_t *d = cbm_opendir(dir_path);
1498+
if (d) {
1499+
cbm_dirent_t *entry;
1500+
while ((entry = cbm_readdir(d)) != NULL) {
1501+
const char *n = entry->name;
1502+
size_t len = strlen(n);
1503+
if (len < 4 || strcmp(n + len - 3, ".db") != 0) continue;
1504+
if (strncmp(n, "tmp-", 4) == 0 || strncmp(n, "_", 1) == 0) continue;
1505+
1506+
/* Extract project name (filename without .db) */
1507+
char proj_name[512];
1508+
snprintf(proj_name, sizeof(proj_name), "%.*s", (int)(len - 3), n);
1509+
1510+
/* Open this project's store and query channels */
1511+
char db_path[2048];
1512+
snprintf(db_path, sizeof(db_path), "%s/%s", dir_path, n);
1513+
cbm_store_t *ps = cbm_store_open_path_query(db_path);
1514+
if (!ps) continue;
1515+
1516+
cbm_channel_info_t *proj_ch = NULL;
1517+
int proj_count = 0;
1518+
cbm_store_find_channels(ps, proj_name, channel, &proj_ch, &proj_count);
1519+
1520+
if (proj_count > 0) {
1521+
/* Merge into main results */
1522+
channels = safe_realloc(channels,
1523+
(count + proj_count) * sizeof(cbm_channel_info_t));
1524+
memcpy(channels + count, proj_ch, proj_count * sizeof(cbm_channel_info_t));
1525+
count += proj_count;
1526+
free(proj_ch); /* shallow free — info fields now owned by channels[] */
1527+
}
1528+
cbm_store_close(ps);
1529+
}
1530+
cbm_closedir(d);
1531+
}
1532+
} else {
1533+
cbm_store_t *store = resolve_store(srv, project);
1534+
REQUIRE_STORE(store, project);
1535+
cbm_store_find_channels(store, project, channel, &channels, &count);
1536+
}
14951537

14961538
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
14971539
yyjson_mut_val *root = yyjson_mut_obj(doc);
@@ -2165,6 +2207,29 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
21652207
yyjson_mut_obj_add_val(doc, outgoing, "has_method", methods_arr);
21662208
}
21672209

2210+
/* Outgoing HAS_PROPERTY (for Classes — class properties). */
2211+
{
2212+
int saved_tr = tr_count;
2213+
if (is_class_like && tr_count < MAX_TR) {
2214+
const char *hp_types[] = {"HAS_PROPERTY"};
2215+
cbm_store_bfs(store, nodes[best_idx].id, "outbound", hp_types, 1, 1, 30,
2216+
&all_tr[tr_count]);
2217+
tr_count++;
2218+
}
2219+
yyjson_mut_val *props_arr = yyjson_mut_arr(doc);
2220+
for (int t = saved_tr; t < tr_count; t++) {
2221+
for (int i = 0; i < all_tr[t].visited_count; i++) {
2222+
cbm_node_t *vn = &all_tr[t].visited[i].node;
2223+
yyjson_mut_val *item = yyjson_mut_obj(doc);
2224+
yyjson_mut_obj_add_str(doc, item, "name", vn->name ? vn->name : "");
2225+
yyjson_mut_obj_add_str(doc, item, "file_path", vn->file_path ? vn->file_path : "");
2226+
yyjson_mut_obj_add_int(doc, item, "line", vn->start_line);
2227+
yyjson_mut_arr_add_val(props_arr, item);
2228+
}
2229+
}
2230+
yyjson_mut_obj_add_val(doc, outgoing, "has_property", props_arr);
2231+
}
2232+
21682233
/* Outgoing INHERITS (what this extends) */
21692234
{
21702235
int saved_tr = tr_count;

0 commit comments

Comments
 (0)