use kglite_mcp_server::{
ServerExtensions, WorkspaceGraphHooks, WorkspaceGraphMode, WorkspaceGraphRequest,
WorkspaceGraphResult,
};
use std::path::Path;
fn is_graph_source(path: &Path) -> bool {
codingest::language_for_path(path).is_some()
|| path
.extension()
.and_then(|extension| extension.to_str())
.is_some_and(|extension| {
extension.eq_ignore_ascii_case("md") || extension.eq_ignore_ascii_case("rst")
})
}
fn server_extensions() -> ServerExtensions {
let hooks = WorkspaceGraphHooks {
build: Box::new(|request: WorkspaceGraphRequest| {
let include_docs = matches!(request.mode(), WorkspaceGraphMode::Workspace);
match request.revisions() {
Some(revisions) => {
let revisions = codingest::dedup_revs(revisions);
let graph = codingest::build_code_tree_revs(
request.root(),
&revisions,
None,
false,
true,
None,
None,
include_docs,
)?;
Ok(WorkspaceGraphResult::with_revisions(graph, revisions))
}
None => {
let graph = codingest::build_code_tree(
request.root(),
false,
true,
None,
None,
include_docs,
)?;
Ok(WorkspaceGraphResult::new(graph))
}
}
}),
is_relevant: Box::new(|change| is_graph_source(change.path())),
};
ServerExtensions::default().with_workspace_graph(hooks)
}
pub fn run<I, T>(args: I) -> anyhow::Result<()>
where
I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone,
{
kglite_mcp_server::run_with_extensions(args, server_extensions())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn graph_source_predicate_includes_code_and_docs_only() {
assert!(is_graph_source(Path::new("src/lib.rs")));
assert!(is_graph_source(Path::new("README.md")));
assert!(is_graph_source(Path::new("GUIDE.RST")));
assert!(!is_graph_source(Path::new("notes.txt")));
assert!(!is_graph_source(Path::new("artifact.kgl")));
}
}