use rmcp::ErrorData as McpError;
use rmcp::model::CallToolResult;
use super::ServerState;
use super::helpers::{elapsed_us, json_result};
use super::memory::{embed_query, lance_store};
use super::types_code::{CodeSearchHit, GetChunkParams, GetChunkResponse, SearchCodeParams, SearchCodeResponse};
use crate::search::bm25::bm25_search;
use crate::search::exact::exact_lane_chunk_ids;
use crate::search::rrf::{
DEFAULT_RRF_K, FusionLane, LANE_EXACT, LANE_KEYWORD, LANE_VECTOR, WEIGHT_EXACT, WEIGHT_KEYWORD, WEIGHT_VECTOR,
rrf_fuse_detailed,
};
use crate::store::Store;
fn format_code_response<T: serde::Serialize>(value: &T, want_toon: bool) -> Result<CallToolResult, McpError> {
#[cfg(feature = "documents")]
if want_toon {
return super::helpers::format_response(value, crate::config::OutputFormat::Toon);
}
let _ = want_toon;
json_result(value)
}
fn wants_toon(state: &ServerState, format: Option<&str>) -> bool {
match format.map(str::trim) {
Some(f) if f.eq_ignore_ascii_case("toon") => true,
Some(f) if f.eq_ignore_ascii_case("json") => false,
_ => matches!(
state.shared.config.documents.output.format,
crate::config::OutputFormat::Toon
),
}
}
pub(super) async fn run_search_code(state: &ServerState, params: SearchCodeParams) -> Result<CallToolResult, McpError> {
let __body = std::time::Instant::now();
let limit = params.limit.unwrap_or(10).min(100) as usize;
let want_toon = wants_toon(state, params.format.as_deref());
let rr = &state.shared.config.code_search.reranker;
let rerank_enabled = params.reranker_enabled.unwrap_or(rr.enabled);
let rerank_preset = params.reranker_preset.clone().unwrap_or_else(|| rr.preset.clone());
let rerank_top_k = params.reranker_top_k.unwrap_or(rr.top_k);
let fetch_n = if rerank_enabled { limit.max(rerank_top_k) } else { limit };
let mode = params.mode.as_deref().map(str::trim).unwrap_or("hybrid");
let (hits, report): (Vec<CodeSearchHit>, LaneReport) = if mode.is_empty() || mode.eq_ignore_ascii_case("hybrid") {
hybrid_hits(state, ¶ms.query, fetch_n).await?
} else if mode.eq_ignore_ascii_case("semantic") {
(
semantic_hits(state, ¶ms.query, fetch_n).await?,
LaneReport::default(),
)
} else if mode.eq_ignore_ascii_case("keyword") {
(
keyword_hits(state, ¶ms.query, fetch_n).await?,
LaneReport::default(),
)
} else {
return Err(McpError::invalid_request(
format!(
"`code` mode=\"semantic\": unknown lane {mode:?}; expected \"hybrid\", \"semantic\", or \"keyword\""
),
None,
));
};
let hits = if rerank_enabled {
rerank_hits(state, ¶ms.query, hits, &rerank_preset, rerank_top_k).await?
} else {
hits
};
let budget = super::budget::apply_budget(hits, params.max_tokens);
format_code_response(
&SearchCodeResponse {
query: params.query,
budgeted: budget.budgeted,
hits: budget.items,
degraded_lanes: report.lanes,
degraded_reason: report.reason,
elapsed_us: elapsed_us(__body),
},
want_toon,
)
}
async fn hybrid_hits(
state: &ServerState,
query: &str,
limit: usize,
) -> Result<(Vec<CodeSearchHit>, LaneReport), McpError> {
let fuse_limit = (limit * 4).clamp(limit, 200);
let mut report = LaneReport::default();
let mut vector_ran = false;
let vector_ids: Vec<String> = if state.shared.config.code_search.embed {
match semantic_hits(state, query, fuse_limit).await {
Ok(hits) => {
vector_ran = true;
hits.into_iter().map(|h| h.chunk_id).collect()
}
Err(error) => {
tracing::debug!(%error, "hybrid: vector lane unavailable — fusing keyword + exact only");
report.degrade(&["vector"], format!("the vector lane failed ({error})"));
Vec::new()
}
}
} else {
Vec::new()
};
let lanes = fjall_lanes(state, query, fuse_limit, true).await?;
if let Some(reason) = &lanes.degraded {
report.degrade(&["keyword", "exact"], reason.clone());
}
if lanes.degraded.is_some() && !vector_ran {
let reason = report.reason.clone().unwrap_or_default();
return Err(McpError::internal_error(
format!(
"`code` mode=\"semantic\": no lane could run — {reason}. Nothing was searched; this \
is not an empty result set."
),
None,
));
}
let keyword_ids: Vec<String> = lanes.keyword.iter().map(|(id, _)| id.clone()).collect();
let exact_ids = lanes.exact;
let store = state.shared.store.read().await;
let fused = rrf_fuse_detailed(
&[
FusionLane::new(LANE_EXACT, &exact_ids, WEIGHT_EXACT),
FusionLane::new(LANE_VECTOR, &vector_ids, WEIGHT_VECTOR),
FusionLane::new(LANE_KEYWORD, &keyword_ids, WEIGHT_KEYWORD),
],
DEFAULT_RRF_K,
);
let mut hits = Vec::with_capacity(fused.len().min(limit));
for fh in fused.into_iter().take(limit) {
if let Some((mut hit, _text)) = hydrate_one(&store, &fh.chunk_id) {
hit.score = Some(fh.score);
hit.matched_lanes = fh.lane_ranks.iter().map(|(name, _)| name.to_string()).collect();
for (name, rank) in &fh.lane_ranks {
match *name {
LANE_EXACT => hit.exact_rank = Some(*rank),
LANE_VECTOR => hit.vector_rank = Some(*rank),
LANE_KEYWORD => hit.keyword_rank = Some(*rank),
_ => {}
}
}
hits.push(hit);
}
}
Ok((hits, report))
}
#[derive(Default)]
struct LaneReport {
lanes: Vec<String>,
reason: Option<String>,
}
impl LaneReport {
fn degrade(&mut self, lanes: &[&str], reason: String) {
self.lanes.extend(lanes.iter().map(|l| (*l).to_string()));
self.reason = Some(match self.reason.take() {
Some(existing) => format!("{existing}; {reason}"),
None => reason,
});
}
}
struct LaneOutcome {
keyword: Vec<(String, f32)>,
exact: Vec<String>,
degraded: Option<String>,
}
async fn fjall_lanes(
state: &ServerState,
query: &str,
limit: usize,
want_exact: bool,
) -> Result<LaneOutcome, McpError> {
{
let store = state.shared.store.read().await;
if let Some(db) = store.index_db.as_ref() {
let keyword = bm25_search(db, query, limit)
.into_iter()
.map(|hit| (hit.chunk_id, hit.score))
.collect();
let exact = if want_exact {
exact_lane_chunk_ids(&store, db, query, limit)
} else {
Vec::new()
};
return Ok(LaneOutcome {
keyword,
exact,
degraded: None,
});
}
}
forward_fjall_lanes(state, query, limit, want_exact).await
}
#[cfg(all(feature = "comms", any(unix, windows)))]
async fn forward_fjall_lanes(
state: &ServerState,
query: &str,
limit: usize,
want_exact: bool,
) -> Result<LaneOutcome, McpError> {
use crate::comms::code_search_proto::CodeSearchLaneQuery;
let request = CodeSearchLaneQuery {
query: query.to_string(),
limit: limit as u32,
want_exact,
};
let root = state.shared.root.clone();
if let Some(host) = state.shared.host.as_ref() {
let host = std::sync::Arc::clone(host);
let hosted = tokio::task::spawn_blocking(move || host.host_code_search_lanes(&root, request))
.await
.map_err(|join| McpError::internal_error(format!("code_search_lanes host join: {join}"), None))?;
return match hosted {
Ok(result) => Ok(LaneOutcome {
keyword: result.keyword,
exact: result.exact,
degraded: None,
}),
Err(error) => Ok(LaneOutcome {
keyword: Vec::new(),
exact: Vec::new(),
degraded: Some(format!("the hosted index read failed ({error})")),
}),
};
}
let mut client = match super::helpers_comms::connect_ephemeral_client(state).await {
Ok(client) => client,
Err(error) => {
return Ok(LaneOutcome {
keyword: Vec::new(),
exact: Vec::new(),
degraded: Some(format!("the daemon is unreachable ({error})")),
});
}
};
match client.code_search_lanes(root, request).await {
Ok(result) => Ok(LaneOutcome {
keyword: result.keyword,
exact: result.exact,
degraded: None,
}),
Err(error) => Ok(LaneOutcome {
keyword: Vec::new(),
exact: Vec::new(),
degraded: Some(format!("the daemon refused the lane read ({error})")),
}),
}
}
#[cfg(not(all(feature = "comms", any(unix, windows))))]
async fn forward_fjall_lanes(
_state: &ServerState,
_query: &str,
_limit: usize,
_want_exact: bool,
) -> Result<LaneOutcome, McpError> {
Ok(LaneOutcome {
keyword: Vec::new(),
exact: Vec::new(),
degraded: Some("this build has no `comms` feature, so there is no daemon to read it".to_string()),
})
}
async fn semantic_hits(state: &ServerState, query: &str, limit: usize) -> Result<Vec<CodeSearchHit>, McpError> {
let embedding = embed_query(state, query).await?;
let lance = lance_store(state).await?;
let scope = state.shared.scope.clone();
let hits_raw = tokio::task::spawn_blocking(move || lance.search_code_chunks(&scope, embedding, limit))
.await
.map_err(|e| McpError::internal_error(format!("spawn_blocking: {e}"), None))?
.map_err(|e| McpError::internal_error(format!("search_code_chunks: {e}"), None))?;
Ok(hits_raw
.into_iter()
.map(|h| CodeSearchHit {
path: h.path,
chunk_id: h.chunk_id,
symbol: h.symbol,
kind: h.kind,
lang: h.lang,
line_start: h.line_start,
line_end: h.line_end,
byte_start: h.byte_start,
byte_end: h.byte_end,
distance: Some(h.distance),
score: None,
rerank_score: None,
matched_lanes: Vec::new(),
keyword_rank: None,
vector_rank: None,
exact_rank: None,
})
.collect())
}
async fn keyword_hits(state: &ServerState, query: &str, limit: usize) -> Result<Vec<CodeSearchHit>, McpError> {
let lanes = fjall_lanes(state, query, limit, false).await?;
if let Some(reason) = lanes.degraded {
return Err(McpError::internal_error(
format!(
"`code` mode=\"semantic\" lane=\"keyword\": the BM25 index lives in the daemon's \
fjall store and {reason}. No search ran; this is not an empty result set."
),
None,
));
}
let store = state.shared.store.read().await;
let mut hits = Vec::with_capacity(lanes.keyword.len());
for (rank, (chunk_id, score)) in lanes.keyword.into_iter().enumerate() {
if let Some((mut ch, _text)) = hydrate_one(&store, &chunk_id) {
ch.score = Some(score);
ch.matched_lanes = vec![LANE_KEYWORD.to_string()];
ch.keyword_rank = u32::try_from(rank + 1).ok();
hits.push(ch);
}
}
Ok(hits)
}
fn hydrate_one(store: &Store, chunk_id: &str) -> Option<(CodeSearchHit, String)> {
let (hash_hex, ordinal) = chunk_id.rsplit_once(':')?;
let ordinal: usize = ordinal.parse().ok()?;
let blob = store.read_chunks_by_hex(hash_hex).ok()??;
let chunk = blob.chunks.get(ordinal)?;
let hit = CodeSearchHit {
path: chunk.path.clone(),
chunk_id: chunk_id.to_string(),
symbol: chunk.symbol.clone().unwrap_or_default(),
kind: chunk.kind.clone().unwrap_or_default(),
lang: chunk.lang.clone(),
line_start: chunk.line_start,
line_end: chunk.line_end,
byte_start: chunk.byte_start,
byte_end: chunk.byte_end,
distance: None,
score: None,
rerank_score: None,
matched_lanes: Vec::new(),
keyword_rank: None,
vector_rank: None,
exact_rank: None,
};
Some((hit, chunk.text.clone()))
}
async fn rerank_hits(
state: &ServerState,
query: &str,
hits: Vec<CodeSearchHit>,
preset: &str,
top_k: usize,
) -> Result<Vec<CodeSearchHit>, McpError> {
if hits.is_empty() {
return Ok(hits);
}
if xberg::get_reranker_preset(preset).is_none() {
return Err(McpError::invalid_params(
format!("unknown reranker preset: {preset:?}"),
None,
));
}
let texts: Vec<String> = {
let store = state.shared.store.read().await;
hits.iter()
.map(|h| {
hydrate_one(&store, &h.chunk_id)
.map(|(_, text)| text)
.unwrap_or_default()
})
.collect()
};
let krz_config = xberg::core::config::RerankerConfig {
model: xberg::core::config::RerankerModelType::Preset {
name: preset.to_string(),
},
top_k: Some(top_k),
..Default::default()
};
let reranked = xberg::rerank_async(query.to_string(), texts, &krz_config)
.await
.map_err(|e| {
let msg = e.to_string();
let kind = if msg.contains("download") || msg.contains("HuggingFace") || msg.contains("model") {
"rerank model load"
} else {
"rerank inference"
};
McpError::internal_error(format!("{kind}: {msg}"), None)
})?;
let original = hits;
reranked
.into_iter()
.map(|r| {
original
.get(r.index)
.cloned()
.map(|mut hit| {
hit.rerank_score = Some(r.score);
hit
})
.ok_or_else(|| {
McpError::internal_error(
format!(
"reranker returned out-of-range index {} (got {} hits)",
r.index,
original.len()
),
None,
)
})
})
.collect()
}
pub(super) async fn run_get_chunk(state: &ServerState, params: GetChunkParams) -> Result<CallToolResult, McpError> {
let __body = std::time::Instant::now();
let blob = {
let store = state.shared.store.read().await;
let entry = store.lookup(¶ms.path).ok_or_else(|| {
McpError::invalid_params(format!("`code` mode `chunk`: file not indexed: {}", params.path), None)
})?;
let hash_hex = entry.hash_hex.clone();
store
.read_chunks_by_hex(&hash_hex)
.map_err(|e| McpError::internal_error(format!("`code` mode `chunk`: read chunk blob: {e}"), None))?
.ok_or_else(|| {
McpError::invalid_params(
format!(
"`code` mode `chunk`: no code chunks indexed for {} (scan with --features code-search)",
params.path
),
None,
)
})?
};
let chunks = &blob.chunks;
if chunks.is_empty() {
return Err(McpError::invalid_params(
format!("`code` mode `chunk`: {} has no chunks", params.path),
None,
));
}
let chunk = if let Some(id) = params.chunk_id.as_deref() {
chunks.iter().find(|c| c.chunk_id == id).ok_or_else(|| {
McpError::invalid_params(
format!("`code` mode `chunk`: chunk_id {id:?} not found in {}", params.path),
None,
)
})?
} else if let Some(bs) = params.byte_start {
chunks.iter().find(|c| c.byte_start == bs).ok_or_else(|| {
McpError::invalid_params(
format!("`code` mode `chunk`: no chunk at byte_start {bs} in {}", params.path),
None,
)
})?
} else if chunks.len() == 1 {
&chunks[0]
} else {
let ids: Vec<&str> = chunks.iter().map(|c| c.chunk_id.as_str()).collect();
return Err(McpError::invalid_params(
format!(
"`code` mode `chunk`: {} has {} chunks; pass `chunk_id` or `byte_start` to disambiguate: {}",
params.path,
chunks.len(),
ids.join(", ")
),
None,
));
};
json_result(&GetChunkResponse {
path: chunk.path.clone(),
chunk_id: chunk.chunk_id.clone(),
symbol: chunk.symbol.clone(),
kind: chunk.kind.clone(),
lang: chunk.lang.clone(),
signature: chunk.signature.clone(),
doc: chunk.doc.clone(),
line_start: chunk.line_start,
line_end: chunk.line_end,
byte_start: chunk.byte_start,
byte_end: chunk.byte_end,
text: chunk.text.clone(),
elapsed_us: elapsed_us(__body),
})
}