fix(mcp): extend project-not-indexed guard to all query handlers

- Add static helper verify_project_indexed() before handle_get_graph_schema
- Replace inline guard in handle_get_architecture with helper call
- Apply guard to handle_search_graph, handle_get_graph_schema,
  handle_trace_call_path, handle_get_code_snippet, handle_query_graph
- All five query handlers now return {"error":"project not indexed —
  run index_repository first"} instead of silently returning empty results

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Shane McCarronandClaude Sonnet 4.6 committed 2026-03-22 18:18:21 -05:00
1 parent c38853f999
commit 172d3a658a
1 file changed
+62
+62
View File
@@ -745,11 +745,36 @@ static char *handle_list_projects(cbm_mcp_server_t *srv, const char *args) {
return result;
}
/* verify_project_indexed — returns a heap-allocated error JSON string when the
* named project has not been indexed yet, or NULL when the project exists.
* resolve_store uses SQLITE_OPEN_CREATE so store is always non-NULL even for
* unindexed projects; this check catches that silent-empty case.
* Callers that receive a non-NULL return value must free(project) themselves
* before returning the error string. */
static char *verify_project_indexed(cbm_store_t *store, const char *project) {
if (!project) {
return NULL; /* default project — always exists */
}
cbm_project_t proj_check = {0};
if (cbm_store_get_project(store, project, &proj_check) != CBM_STORE_OK) {
return cbm_mcp_text_result(
"{\"error\":\"project not indexed — run index_repository first\"}", true);
}
cbm_project_free_fields(&proj_check);
return NULL;
}
static char *handle_get_graph_schema(cbm_mcp_server_t *srv, const char *args) {
char *project = cbm_mcp_get_string_arg(args, "project");
cbm_store_t *store = resolve_store(srv, project);
REQUIRE_STORE(store, project);
char *not_indexed = verify_project_indexed(store, project);
if (not_indexed) {
free(project);
return not_indexed;
}
cbm_schema_info_t schema = {0};
cbm_store_get_schema(store, project, &schema);
@@ -807,6 +832,13 @@ static char *handle_search_graph(cbm_mcp_server_t *srv, const char *args) {
char *project = cbm_mcp_get_string_arg(args, "project");
cbm_store_t *store = resolve_store(srv, project);
REQUIRE_STORE(store, project);
char *not_indexed = verify_project_indexed(store, project);
if (not_indexed) {
free(project);
return not_indexed;
}
char *label = cbm_mcp_get_string_arg(args, "label");
char *name_pattern = cbm_mcp_get_string_arg(args, "name_pattern");
char *file_pattern = cbm_mcp_get_string_arg(args, "file_pattern");
@@ -882,6 +914,13 @@ static char *handle_query_graph(cbm_mcp_server_t *srv, const char *args) {
return cbm_mcp_text_result("{\"error\":\"no project loaded\"}", true);
}
char *not_indexed = verify_project_indexed(store, project);
if (not_indexed) {
free(project);
free(query);
return not_indexed;
}
cbm_cypher_result_t result = {0};
int rc = cbm_cypher_execute(store, query, project, max_rows, &result);
@@ -1012,6 +1051,13 @@ static char *handle_get_architecture(cbm_mcp_server_t *srv, const char *args) {
cbm_store_t *store = resolve_store(srv, project);
REQUIRE_STORE(store, project);
char *not_indexed = verify_project_indexed(store, project);
if (not_indexed) {
free(project);
return not_indexed;
}
cbm_schema_info_t schema = {0};
cbm_store_get_schema(store, project, &schema);
@@ -1085,6 +1131,15 @@ static char *handle_trace_call_path(cbm_mcp_server_t *srv, const char *args) {
free(direction);
return cbm_mcp_text_result("{\"error\":\"no project loaded\"}", true);
}
char *not_indexed = verify_project_indexed(store, project);
if (not_indexed) {
free(func_name);
free(project);
free(direction);
return not_indexed;
}
if (!direction) {
direction = heap_strdup("both");
}
@@ -1575,6 +1630,13 @@ static char *handle_get_code_snippet(cbm_mcp_server_t *srv, const char *args) {
return cbm_mcp_text_result("no project loaded — run index_repository first", true);
}
char *not_indexed = verify_project_indexed(store, project);
if (not_indexed) {
free(qn);
free(project);
return not_indexed;
}
/* Default to current project (same as all other tools) */
const char *effective_project = project ? project : srv->current_project;