mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 18:58:00 +00:00
trace_path mode=cross_service resolved its default edge-type list to
{HTTP_CALLS, ASYNC_CALLS, DATA_FLOWS, CALLS} — none of the CROSS_* edge
types the cross-repo pass actually writes. Since cbm_store_bfs filters
edges with an exact `WHERE e.type IN (...)` clause, cross-service traces
silently skipped every cross hop even when the edge was present and
visible via query_graph.
Add the six CROSS_* types (CROSS_HTTP_CALLS, CROSS_ASYNC_CALLS,
CROSS_CHANNEL, CROSS_GRPC_CALLS, CROSS_GRAPHQL_CALLS, CROSS_TRPC_CALLS)
to the cross_service default list — exactly the set pass_cross_repo.c
emits and cross_repo_delete_edges() cleans up. The count is now computed
from the array size (sizeof) so it can't drift; the dead MCP_N_DEFAULTS_4
constant is removed. Tool description updated to match.
Adds integ_mcp_trace_path_cross_service: seeds a CROSS_HTTP_CALLS edge
between two indexed functions with no CALLS relationship and asserts
cross_service surfaces the hop while calls mode does not.
Signed-off-by: kirilklein <kikl@di.ku.dk>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
8ba286324c
commit
df8bc9254d
2 files changed
+65
-4
No files matched your search
+8
-4
@@ -29,7 +29,6 @@ enum {
|
||||
MCP_DEFAULT_LIMIT = 10,
|
||||
MCP_BFS_LIMIT = 100,
|
||||
MCP_N_DEFAULTS_2 = 2,
|
||||
MCP_N_DEFAULTS_4 = 4,
|
||||
MCP_URI_PREFIX = 7, /* strlen("file://") */
|
||||
MCP_CONTENT_PREFIX = 15, /* strlen("Content-Length:") */
|
||||
MCP_RETURN_2 = 2,
|
||||
@@ -362,7 +361,9 @@ static const tool_def_t TOOLS[] = {
|
||||
"\"type\":\"string\",\"enum\":[\"calls\",\"data_flow\",\"cross_service\"],\"default\":"
|
||||
"\"calls\",\"description\":\"calls: follow CALLS edges. data_flow: follow CALLS+DATA_FLOWS "
|
||||
"with arg expressions. cross_service: follow HTTP_CALLS+ASYNC_CALLS+DATA_FLOWS through "
|
||||
"Routes.\"},\"parameter_name\":{\"type\":\"string\",\"description\":\"For data_flow mode: "
|
||||
"Routes, plus CROSS_* cross-repo edges (CROSS_HTTP_CALLS/ASYNC_CALLS/CHANNEL/GRPC_CALLS/"
|
||||
"GRAPHQL_CALLS/TRPC_CALLS) to hop into other services.\"},\"parameter_name\":{\"type\":"
|
||||
"\"string\",\"description\":\"For data_flow mode: "
|
||||
"scope trace to a specific parameter name\"},\"edge_types\":{\"type\":\"array\",\"items\":{"
|
||||
"\"type\":\"string\"}},\"risk_labels\":{\"type\":\"boolean\",\"default\":false,"
|
||||
"\"description\":\"Add risk classification (CRITICAL/HIGH/MEDIUM/LOW) based on hop distance"
|
||||
@@ -2164,7 +2165,10 @@ static yyjson_doc *resolve_trace_edge_types(const char *args, const char *mode,
|
||||
const char **out_types, int *out_count) {
|
||||
static const char *mode_calls[] = {"CALLS"};
|
||||
static const char *mode_data_flow[] = {"CALLS", "DATA_FLOWS"};
|
||||
static const char *mode_cross_svc[] = {"HTTP_CALLS", "ASYNC_CALLS", "DATA_FLOWS", "CALLS"};
|
||||
static const char *mode_cross_svc[] = {
|
||||
"HTTP_CALLS", "ASYNC_CALLS", "DATA_FLOWS", "CALLS",
|
||||
"CROSS_HTTP_CALLS", "CROSS_ASYNC_CALLS", "CROSS_CHANNEL", "CROSS_GRPC_CALLS",
|
||||
"CROSS_GRAPHQL_CALLS", "CROSS_TRPC_CALLS"};
|
||||
|
||||
*out_count = 0;
|
||||
|
||||
@@ -2196,7 +2200,7 @@ static yyjson_doc *resolve_trace_edge_types(const char *args, const char *mode,
|
||||
n_defaults = MCP_N_DEFAULTS_2;
|
||||
} else if (mode && strcmp(mode, "cross_service") == 0) {
|
||||
defaults = mode_cross_svc;
|
||||
n_defaults = MCP_N_DEFAULTS_4;
|
||||
n_defaults = (int)(sizeof(mode_cross_svc) / sizeof(mode_cross_svc[0]));
|
||||
}
|
||||
for (int i = 0; i < n_defaults; i++) {
|
||||
out_types[i] = defaults[i];
|
||||
|
||||
@@ -383,6 +383,62 @@ TEST(integ_mcp_trace_path) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* #522: trace_path mode=cross_service must follow CROSS_* cross-repo edges.
|
||||
* Seed a CROSS_HTTP_CALLS edge between two indexed functions that have no CALLS
|
||||
* relationship, then confirm cross_service surfaces the hop while the default
|
||||
* calls mode does not (proving the cross edge specifically is what's followed).
|
||||
*
|
||||
* The trace goes through a fresh server so it opens the db after the edge is
|
||||
* committed — exactly what a new MCP session sees after a cross-repo pass writes
|
||||
* CROSS_* edges (g_srv's cached connection predates this write). */
|
||||
TEST(integ_mcp_trace_path_cross_service) {
|
||||
cbm_store_t *store = cbm_store_open_path(g_dbpath);
|
||||
ASSERT_NOT_NULL(store);
|
||||
|
||||
cbm_node_t *src = NULL;
|
||||
cbm_node_t *dst = NULL;
|
||||
int src_count = 0;
|
||||
int dst_count = 0;
|
||||
cbm_store_find_nodes_by_name(store, g_project, "greet", &src, &src_count);
|
||||
cbm_store_find_nodes_by_name(store, g_project, "farewell", &dst, &dst_count);
|
||||
ASSERT_TRUE(src_count > 0 && dst_count > 0);
|
||||
|
||||
cbm_edge_t edge = {.project = g_project,
|
||||
.source_id = src[0].id,
|
||||
.target_id = dst[0].id,
|
||||
.type = "CROSS_HTTP_CALLS"};
|
||||
ASSERT_TRUE(cbm_store_insert_edge(store, &edge) > 0);
|
||||
|
||||
cbm_store_free_nodes(src, src_count);
|
||||
cbm_store_free_nodes(dst, dst_count);
|
||||
cbm_store_close(store);
|
||||
|
||||
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
|
||||
ASSERT_NOT_NULL(srv);
|
||||
|
||||
char args[256];
|
||||
snprintf(args, sizeof(args),
|
||||
"{\"function_name\":\"greet\",\"project\":\"%s\","
|
||||
"\"direction\":\"outbound\",\"mode\":\"cross_service\"}",
|
||||
g_project);
|
||||
char *resp = cbm_mcp_handle_tool(srv, "trace_path", args);
|
||||
ASSERT_NOT_NULL(resp);
|
||||
ASSERT_NOT_NULL(strstr(resp, "farewell"));
|
||||
free(resp);
|
||||
|
||||
snprintf(args, sizeof(args),
|
||||
"{\"function_name\":\"greet\",\"project\":\"%s\","
|
||||
"\"direction\":\"outbound\",\"mode\":\"calls\"}",
|
||||
g_project);
|
||||
resp = cbm_mcp_handle_tool(srv, "trace_path", args);
|
||||
ASSERT_NOT_NULL(resp);
|
||||
ASSERT_TRUE(strstr(resp, "farewell") == NULL);
|
||||
free(resp);
|
||||
|
||||
cbm_mcp_server_free(srv);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(integ_mcp_index_status) {
|
||||
char args[128];
|
||||
snprintf(args, sizeof(args), "{\"project\":\"%s\"}", g_project);
|
||||
@@ -604,6 +660,7 @@ SUITE(integration) {
|
||||
RUN_TEST(integ_mcp_get_graph_schema);
|
||||
RUN_TEST(integ_mcp_get_architecture);
|
||||
RUN_TEST(integ_mcp_trace_path);
|
||||
RUN_TEST(integ_mcp_trace_path_cross_service);
|
||||
RUN_TEST(integ_mcp_index_status);
|
||||
|
||||
/* Store query validation */
|
||||
|
||||
Reference in new issue
Block a user