Skip to content

Commit 96b49aa

Browse files
fix(mcp): wire cbm_store_get_architecture into handle_get_architecture (#281)
handle_get_architecture was returning only label/edge histograms because it never called cbm_store_get_architecture — the rich architecture computation sat completely unwired upstream of the MCP boundary regardless of which aspects were requested. Wires it up: - Parse the JSON aspects array into a const char*[MCP_COL_16] and pass to cbm_store_get_architecture, which already handles 'all' and per-name filtering internally. - Serialize each non-empty section: languages, packages, entry_points, routes, hotspots, boundaries, layers, file_tree. Existing histogram fields (node_labels, edge_types, relationship_patterns, cross_repo_links) preserved. - Call cbm_store_architecture_free before return. Closes #280.
1 parent 2ec5b2b commit 96b49aa

1 file changed

Lines changed: 128 additions & 0 deletions

File tree

src/mcp/mcp.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,9 +1785,30 @@ static char *handle_get_architecture(cbm_mcp_server_t *srv, const char *args) {
17851785
}
17861786
}
17871787

1788+
/* Build a C string array from aspects for cbm_store_get_architecture.
1789+
* Strings point into aspects_doc memory so aspects_doc must outlive this array. */
1790+
const char *aspects_strs[MCP_COL_16];
1791+
int aspects_strs_count = 0;
1792+
if (aspects_arr) {
1793+
size_t aspect_idx;
1794+
size_t aspect_max;
1795+
yyjson_val *aspect_val;
1796+
yyjson_arr_foreach(aspects_arr, aspect_idx, aspect_max, aspect_val) {
1797+
const char *s = yyjson_get_str(aspect_val);
1798+
if (s && aspects_strs_count < MCP_COL_16) {
1799+
aspects_strs[aspects_strs_count++] = s;
1800+
}
1801+
}
1802+
}
1803+
17881804
cbm_schema_info_t schema = {0};
17891805
cbm_store_get_schema(store, project, &schema);
17901806

1807+
cbm_architecture_info_t arch = {0};
1808+
cbm_store_get_architecture(store, project,
1809+
aspects_strs_count > 0 ? aspects_strs : NULL,
1810+
aspects_strs_count, &arch);
1811+
17911812
int node_count = cbm_store_count_nodes(store, project);
17921813
int edge_count = cbm_store_count_edges(store, project);
17931814

@@ -1834,10 +1855,117 @@ static char *handle_get_architecture(cbm_mcp_server_t *srv, const char *args) {
18341855
yyjson_mut_obj_add_val(doc, root, "relationship_patterns", pats);
18351856
}
18361857

1858+
/* Languages */
1859+
if (arch.language_count > 0) {
1860+
yyjson_mut_val *langs = yyjson_mut_arr(doc);
1861+
for (int i = 0; i < arch.language_count; i++) {
1862+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1863+
yyjson_mut_obj_add_str(doc, item, "language", arch.languages[i].language);
1864+
yyjson_mut_obj_add_int(doc, item, "file_count", arch.languages[i].file_count);
1865+
yyjson_mut_arr_add_val(langs, item);
1866+
}
1867+
yyjson_mut_obj_add_val(doc, root, "languages", langs);
1868+
}
1869+
1870+
/* Packages */
1871+
if (arch.package_count > 0) {
1872+
yyjson_mut_val *pkgs = yyjson_mut_arr(doc);
1873+
for (int i = 0; i < arch.package_count; i++) {
1874+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1875+
yyjson_mut_obj_add_str(doc, item, "name", arch.packages[i].name);
1876+
yyjson_mut_obj_add_int(doc, item, "node_count", arch.packages[i].node_count);
1877+
yyjson_mut_obj_add_int(doc, item, "fan_in", arch.packages[i].fan_in);
1878+
yyjson_mut_obj_add_int(doc, item, "fan_out", arch.packages[i].fan_out);
1879+
yyjson_mut_arr_add_val(pkgs, item);
1880+
}
1881+
yyjson_mut_obj_add_val(doc, root, "packages", pkgs);
1882+
}
1883+
1884+
/* Entry points */
1885+
if (arch.entry_point_count > 0) {
1886+
yyjson_mut_val *eps = yyjson_mut_arr(doc);
1887+
for (int i = 0; i < arch.entry_point_count; i++) {
1888+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1889+
yyjson_mut_obj_add_str(doc, item, "name", arch.entry_points[i].name);
1890+
yyjson_mut_obj_add_str(doc, item, "qualified_name",
1891+
arch.entry_points[i].qualified_name);
1892+
yyjson_mut_obj_add_str(doc, item, "file", arch.entry_points[i].file);
1893+
yyjson_mut_arr_add_val(eps, item);
1894+
}
1895+
yyjson_mut_obj_add_val(doc, root, "entry_points", eps);
1896+
}
1897+
1898+
/* HTTP routes */
1899+
if (arch.route_count > 0) {
1900+
yyjson_mut_val *routes = yyjson_mut_arr(doc);
1901+
for (int i = 0; i < arch.route_count; i++) {
1902+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1903+
yyjson_mut_obj_add_str(doc, item, "method", arch.routes[i].method);
1904+
yyjson_mut_obj_add_str(doc, item, "path", arch.routes[i].path);
1905+
yyjson_mut_obj_add_str(doc, item, "handler", arch.routes[i].handler);
1906+
yyjson_mut_arr_add_val(routes, item);
1907+
}
1908+
yyjson_mut_obj_add_val(doc, root, "routes", routes);
1909+
}
1910+
1911+
/* Hotspots */
1912+
if (arch.hotspot_count > 0) {
1913+
yyjson_mut_val *hotspots = yyjson_mut_arr(doc);
1914+
for (int i = 0; i < arch.hotspot_count; i++) {
1915+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1916+
yyjson_mut_obj_add_str(doc, item, "name", arch.hotspots[i].name);
1917+
yyjson_mut_obj_add_str(doc, item, "qualified_name",
1918+
arch.hotspots[i].qualified_name);
1919+
yyjson_mut_obj_add_int(doc, item, "fan_in", arch.hotspots[i].fan_in);
1920+
yyjson_mut_arr_add_val(hotspots, item);
1921+
}
1922+
yyjson_mut_obj_add_val(doc, root, "hotspots", hotspots);
1923+
}
1924+
1925+
/* Cross-package boundaries */
1926+
if (arch.boundary_count > 0) {
1927+
yyjson_mut_val *boundaries = yyjson_mut_arr(doc);
1928+
for (int i = 0; i < arch.boundary_count; i++) {
1929+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1930+
yyjson_mut_obj_add_str(doc, item, "from", arch.boundaries[i].from);
1931+
yyjson_mut_obj_add_str(doc, item, "to", arch.boundaries[i].to);
1932+
yyjson_mut_obj_add_int(doc, item, "call_count", arch.boundaries[i].call_count);
1933+
yyjson_mut_arr_add_val(boundaries, item);
1934+
}
1935+
yyjson_mut_obj_add_val(doc, root, "boundaries", boundaries);
1936+
}
1937+
1938+
/* Package layers */
1939+
if (arch.layer_count > 0) {
1940+
yyjson_mut_val *layers = yyjson_mut_arr(doc);
1941+
for (int i = 0; i < arch.layer_count; i++) {
1942+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1943+
yyjson_mut_obj_add_str(doc, item, "name", arch.layers[i].name);
1944+
yyjson_mut_obj_add_str(doc, item, "layer", arch.layers[i].layer);
1945+
yyjson_mut_obj_add_str(doc, item, "reason", arch.layers[i].reason);
1946+
yyjson_mut_arr_add_val(layers, item);
1947+
}
1948+
yyjson_mut_obj_add_val(doc, root, "layers", layers);
1949+
}
1950+
1951+
/* File tree */
1952+
if (arch.file_tree_count > 0) {
1953+
yyjson_mut_val *file_tree = yyjson_mut_arr(doc);
1954+
for (int i = 0; i < arch.file_tree_count; i++) {
1955+
yyjson_mut_val *item = yyjson_mut_obj(doc);
1956+
yyjson_mut_obj_add_str(doc, item, "path", arch.file_tree[i].path);
1957+
yyjson_mut_obj_add_str(doc, item, "type", arch.file_tree[i].type);
1958+
yyjson_mut_obj_add_int(doc, item, "children", arch.file_tree[i].children);
1959+
yyjson_mut_arr_add_val(file_tree, item);
1960+
}
1961+
yyjson_mut_obj_add_val(doc, root, "file_tree", file_tree);
1962+
}
1963+
18371964
append_cross_repo_summary(doc, root, &schema);
18381965

18391966
char *json = yy_doc_to_str(doc);
18401967
yyjson_mut_doc_free(doc);
1968+
cbm_store_architecture_free(&arch);
18411969
cbm_store_schema_free(&schema);
18421970
if (aspects_doc) {
18431971
yyjson_doc_free(aspects_doc);

0 commit comments

Comments
 (0)