mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 08:13:37 +08:00
fix(mcp): preserve explicit missing project errors
Keep explicit non-path project names authoritative in resolve_project_store so a bad slug cannot fall back to the active session root after slug-based context hydration. Implicit project resolution and session/dependency aliases can still use session-root autoindex, while explicit filesystem paths keep their path-based autoindex path. Add a focused regression that first hydrates session context from a valid project slug, then verifies a different missing slug returns a structured error/not-found response. Verified with: make -j8 -f Makefile.cbm build/c/test-runner; CBM_ONLY_SUITE=tool_consolidation ./build/c/test-runner; CBM_ONLY_SUITE=mcp ./build/c/test-runner; bash scripts/check-source-safety.sh; bash scripts/test-source-safety.sh; git diff --check; escalated CBM_ONLY_SUITE=incremental ./build/c/test-runner. Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
This commit is contained in:
+11
-3
@@ -2521,8 +2521,10 @@ static cbm_store_t *resolve_project_store(cbm_mcp_server_t *srv,
|
||||
/* Save the resolved filesystem path BEFORE expand_project_param consumes
|
||||
* raw_project. Used below to auto-index paths that aren't under session_root
|
||||
* (e.g. .gitignore-excluded subdirs that are separate git repos). */
|
||||
bool raw_project_explicit = raw_project != NULL;
|
||||
bool raw_project_path = raw_project_explicit && project_is_path(raw_project);
|
||||
char *_raw_path = NULL;
|
||||
if (raw_project && project_is_path(raw_project)) {
|
||||
if (raw_project_path) {
|
||||
char *_exp = expand_tilde(raw_project);
|
||||
_raw_path = realpath(_exp ? _exp : raw_project, NULL);
|
||||
if (!_raw_path && (_exp || raw_project[0] == '/')) {
|
||||
@@ -2551,9 +2553,15 @@ static cbm_store_t *resolve_project_store(cbm_mcp_server_t *srv,
|
||||
}
|
||||
}
|
||||
cbm_store_t *store = resolve_store(srv, db_project);
|
||||
bool session_store_selected = db_project && srv->session_project[0] &&
|
||||
strcmp(db_project, srv->session_project) == 0;
|
||||
bool may_use_session_root = !raw_project_explicit || session_store_selected;
|
||||
|
||||
/* Auto-index on first use (same enablement as REQUIRE_STORE). */
|
||||
if (!store && srv->session_root[0] && access(srv->session_root, F_OK) == 0) {
|
||||
/* Auto-index on first use (same enablement as REQUIRE_STORE). Explicit
|
||||
* non-path project names are authoritative: a missing slug must report
|
||||
* not-found instead of silently searching the active session project. */
|
||||
if (!store && may_use_session_root && srv->session_root[0] &&
|
||||
access(srv->session_root, F_OK) == 0) {
|
||||
if (srv->autoindex_active) {
|
||||
cbm_thread_join(&srv->autoindex_tid);
|
||||
srv->autoindex_active = false;
|
||||
|
||||
@@ -727,12 +727,16 @@ TEST(search_graph_slug_project_sets_session_context) {
|
||||
* list_projects. Results already came from that DB, but the first response
|
||||
* context used to stay empty unless project was passed as a filesystem path. */
|
||||
const char *proj = "_tc_ctx_slug_";
|
||||
char db_path[1024];
|
||||
snprintf(db_path, sizeof(db_path), "%s/%s.db", cbm_resolve_cache_dir(), proj);
|
||||
char *root_path = th_mktempdir("cbm_tc_ctx_slug");
|
||||
ASSERT_NOT_NULL(root_path);
|
||||
char db_path[CBM_SZ_1K];
|
||||
int npath = snprintf(db_path, sizeof(db_path), "%s/%s.db", cbm_resolve_cache_dir(), proj);
|
||||
ASSERT_GT(npath, 0);
|
||||
ASSERT((size_t)npath < sizeof(db_path));
|
||||
|
||||
cbm_store_t *s = cbm_store_open_path(db_path);
|
||||
ASSERT_NOT_NULL(s);
|
||||
ASSERT_EQ(cbm_store_upsert_project(s, proj, "/tmp/tc_ctx_slug"), CBM_STORE_OK);
|
||||
ASSERT_EQ(cbm_store_upsert_project(s, proj, root_path), CBM_STORE_OK);
|
||||
cbm_node_t n = {.project = proj,
|
||||
.label = "Function",
|
||||
.name = "tc_ctx_slug_fn",
|
||||
@@ -752,8 +756,17 @@ TEST(search_graph_slug_project_sets_session_context) {
|
||||
ASSERT_NOT_NULL(strstr(result, "\\\"nodes\\\":1"));
|
||||
free(result);
|
||||
|
||||
result = cbm_mcp_handle_tool(
|
||||
srv, "search_graph",
|
||||
"{\"project\":\"_tc_ctx_slug_missing_\",\"name_pattern\":\"tc_ctx_slug_fn\",\"limit\":1}");
|
||||
ASSERT_NOT_NULL(result);
|
||||
ASSERT(strstr(result, "error") != NULL || strstr(result, "not found") != NULL ||
|
||||
strstr(result, "not_found") != NULL);
|
||||
free(result);
|
||||
|
||||
cbm_mcp_server_free(srv);
|
||||
(void)unlink(db_path);
|
||||
th_cleanup(root_path);
|
||||
PASS();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user