Skip to content

Commit 6884cd9

Browse files
committed
feat(symbols): fix API compatibility and enable symbol navigation tools
- Fix SymbolReference API changes (source → source_node, kind → edge_kind) - Update find_dependencies to use new API with DependencyType parameter - Update find_references to use new find_references method - Fix Node test creation to use proper constructor with repo_id parameter - Fix NodeId test to use 32-character hex string for proper parsing - Re-enable symbols module in basic tools and main routing - All 4 symbol tools now fully functional: trace_path, explain_symbol, find_dependencies, find_references - Maintain 100% test compatibility: 219 tests passing - Comprehensive API compatibility fixes across all dependency analysis types (Direct, Calls, Imports, Reads, Writes) Symbol tools migration: COMPLETE - Core navigation functionality restored API compatibility: RESOLVED - All method signatures updated for current core API Test coverage: MAINTAINED - All symbol tests passing with proper assertions closes #migrate-symbols-tools
1 parent 3b50e17 commit 6884cd9

File tree

3 files changed

+103
-108
lines changed

3 files changed

+103
-108
lines changed

crates/codeprism-mcp/src/tools/basic/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
pub mod navigation;
88
pub mod repository;
99
pub mod search;
10-
// FUTURE: Re-enable symbols module after API compatibility updates
11-
// pub mod symbols;
10+
pub mod symbols;
1211

1312
// Re-export specific functions to avoid naming conflicts
1413
pub use repository::{content_stats, content_stats_tool, repository_stats, repository_stats_tool};

crates/codeprism-mcp/src/tools/basic/symbols.rs

Lines changed: 98 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,7 @@ async fn explain_symbol(
240240

241241
// Enhanced inheritance information for classes
242242
if matches!(node.kind, codeprism_core::NodeKind::Class) {
243-
if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&symbol_id)
244-
{
243+
if let Ok(inheritance_info) = server.graph_query().get_inheritance_info(&symbol_id) {
245244
let mut inheritance_data = serde_json::Map::new();
246245

247246
// Basic inheritance information
@@ -338,8 +337,7 @@ async fn explain_symbol(
338337
})
339338
})
340339
.collect();
341-
inheritance_data
342-
.insert("mixins".to_string(), serde_json::Value::Array(mixins));
340+
inheritance_data.insert("mixins".to_string(), serde_json::Value::Array(mixins));
343341
}
344342

345343
result["inheritance"] = serde_json::Value::Object(inheritance_data);
@@ -348,7 +346,10 @@ async fn explain_symbol(
348346

349347
// Add dependency information if requested
350348
if include_dependencies {
351-
if let Ok(dependencies) = server.graph_query().find_dependencies(&symbol_id, codeprism_core::graph::DependencyType::Direct) {
349+
if let Ok(dependencies) = server
350+
.graph_query()
351+
.find_dependencies(&symbol_id, codeprism_core::graph::DependencyType::Direct)
352+
{
352353
let deps: Vec<_> = dependencies
353354
.iter()
354355
.map(|dep| {
@@ -418,114 +419,115 @@ async fn find_dependencies(
418419
// Target is a node ID
419420
match dependency_type {
420421
"direct" => {
421-
let deps = server.graph_query().get_dependencies(&node_id)?;
422+
let deps = server
423+
.graph_query()
424+
.find_dependencies(&node_id, codeprism_core::graph::DependencyType::Direct)?;
422425
deps.into_iter()
423-
.filter(|dep| is_valid_dependency_node(server.graph_store().get_node(&dep.target).as_ref().unwrap()))
426+
.filter(|dep| is_valid_dependency_node(&dep.target_node))
424427
.map(|dep| {
425-
let target_node = server.graph_store().get_node(&dep.target).unwrap();
426428
serde_json::json!({
427-
"target_id": dep.target.to_hex(),
428-
"target_name": target_node.name,
429-
"target_kind": format!("{:?}", target_node.kind),
430-
"dependency_kind": format!("{:?}", dep.kind),
431-
"target_file": target_node.file.display().to_string(),
429+
"target_id": dep.target_node.id.to_hex(),
430+
"target_name": dep.target_node.name,
431+
"target_kind": format!("{:?}", dep.target_node.kind),
432+
"dependency_kind": format!("{:?}", dep.edge_kind),
433+
"target_file": dep.target_node.file.display().to_string(),
432434
"target_span": {
433-
"start_line": target_node.span.start_line,
434-
"end_line": target_node.span.end_line,
435-
"start_column": target_node.span.start_column,
436-
"end_column": target_node.span.end_column
435+
"start_line": dep.target_node.span.start_line,
436+
"end_line": dep.target_node.span.end_line,
437+
"start_column": dep.target_node.span.start_column,
438+
"end_column": dep.target_node.span.end_column
437439
}
438440
})
439441
})
440442
.collect()
441443
}
442444
"calls" => {
443-
let deps = server.graph_query().get_dependencies(&node_id)?;
445+
let deps = server
446+
.graph_query()
447+
.find_dependencies(&node_id, codeprism_core::graph::DependencyType::Calls)?;
444448
deps.into_iter()
445-
.filter(|dep| matches!(dep.kind, codeprism_core::EdgeKind::Calls))
446-
.filter(|dep| is_valid_dependency_node(server.graph_store().get_node(&dep.target).as_ref().unwrap()))
449+
.filter(|dep| is_valid_dependency_node(&dep.target_node))
447450
.map(|dep| {
448-
let target_node = server.graph_store().get_node(&dep.target).unwrap();
449451
serde_json::json!({
450-
"target_id": dep.target.to_hex(),
451-
"target_name": target_node.name,
452-
"target_kind": format!("{:?}", target_node.kind),
452+
"target_id": dep.target_node.id.to_hex(),
453+
"target_name": dep.target_node.name,
454+
"target_kind": format!("{:?}", dep.target_node.kind),
453455
"dependency_kind": "calls",
454-
"target_file": target_node.file.display().to_string(),
456+
"target_file": dep.target_node.file.display().to_string(),
455457
"target_span": {
456-
"start_line": target_node.span.start_line,
457-
"end_line": target_node.span.end_line,
458-
"start_column": target_node.span.start_column,
459-
"end_column": target_node.span.end_column
458+
"start_line": dep.target_node.span.start_line,
459+
"end_line": dep.target_node.span.end_line,
460+
"start_column": dep.target_node.span.start_column,
461+
"end_column": dep.target_node.span.end_column
460462
}
461463
})
462464
})
463465
.collect()
464466
}
465467
"imports" => {
466-
let deps = server.graph_query().get_dependencies(&node_id)?;
468+
let deps = server
469+
.graph_query()
470+
.find_dependencies(&node_id, codeprism_core::graph::DependencyType::Imports)?;
467471
deps.into_iter()
468-
.filter(|dep| matches!(dep.kind, codeprism_core::EdgeKind::Imports))
469-
.filter(|dep| is_valid_dependency_node(server.graph_store().get_node(&dep.target).as_ref().unwrap()))
472+
.filter(|dep| is_valid_dependency_node(&dep.target_node))
470473
.map(|dep| {
471-
let target_node = server.graph_store().get_node(&dep.target).unwrap();
472474
serde_json::json!({
473-
"target_id": dep.target.to_hex(),
474-
"target_name": target_node.name,
475-
"target_kind": format!("{:?}", target_node.kind),
475+
"target_id": dep.target_node.id.to_hex(),
476+
"target_name": dep.target_node.name,
477+
"target_kind": format!("{:?}", dep.target_node.kind),
476478
"dependency_kind": "imports",
477-
"target_file": target_node.file.display().to_string(),
479+
"target_file": dep.target_node.file.display().to_string(),
478480
"target_span": {
479-
"start_line": target_node.span.start_line,
480-
"end_line": target_node.span.end_line,
481-
"start_column": target_node.span.start_column,
482-
"end_column": target_node.span.end_column
481+
"start_line": dep.target_node.span.start_line,
482+
"end_line": dep.target_node.span.end_line,
483+
"start_column": dep.target_node.span.start_column,
484+
"end_column": dep.target_node.span.end_column
483485
}
484486
})
485487
})
486488
.collect()
487489
}
488490
"reads" => {
489-
let deps = server.graph_query().get_dependencies(&node_id)?;
491+
let deps = server
492+
.graph_query()
493+
.find_dependencies(&node_id, codeprism_core::graph::DependencyType::Reads)?;
490494
deps.into_iter()
491-
.filter(|dep| matches!(dep.kind, codeprism_core::EdgeKind::Reads))
492-
.filter(|dep| is_valid_dependency_node(server.graph_store().get_node(&dep.target).as_ref().unwrap()))
495+
.filter(|dep| is_valid_dependency_node(&dep.target_node))
493496
.map(|dep| {
494-
let target_node = server.graph_store().get_node(&dep.target).unwrap();
495497
serde_json::json!({
496-
"target_id": dep.target.to_hex(),
497-
"target_name": target_node.name,
498-
"target_kind": format!("{:?}", target_node.kind),
498+
"target_id": dep.target_node.id.to_hex(),
499+
"target_name": dep.target_node.name,
500+
"target_kind": format!("{:?}", dep.target_node.kind),
499501
"dependency_kind": "reads",
500-
"target_file": target_node.file.display().to_string(),
502+
"target_file": dep.target_node.file.display().to_string(),
501503
"target_span": {
502-
"start_line": target_node.span.start_line,
503-
"end_line": target_node.span.end_line,
504-
"start_column": target_node.span.start_column,
505-
"end_column": target_node.span.end_column
504+
"start_line": dep.target_node.span.start_line,
505+
"end_line": dep.target_node.span.end_line,
506+
"start_column": dep.target_node.span.start_column,
507+
"end_column": dep.target_node.span.end_column
506508
}
507509
})
508510
})
509511
.collect()
510512
}
511513
"writes" => {
512-
let deps = server.graph_query().get_dependencies(&node_id)?;
514+
let deps = server
515+
.graph_query()
516+
.find_dependencies(&node_id, codeprism_core::graph::DependencyType::Writes)?;
513517
deps.into_iter()
514-
.filter(|dep| matches!(dep.kind, codeprism_core::EdgeKind::Writes))
515-
.filter(|dep| is_valid_dependency_node(server.graph_store().get_node(&dep.target).as_ref().unwrap()))
518+
.filter(|dep| is_valid_dependency_node(&dep.target_node))
516519
.map(|dep| {
517-
let target_node = server.graph_store().get_node(&dep.target).unwrap();
518520
serde_json::json!({
519-
"target_id": dep.target.to_hex(),
520-
"target_name": target_node.name,
521-
"target_kind": format!("{:?}", target_node.kind),
521+
"target_id": dep.target_node.id.to_hex(),
522+
"target_name": dep.target_node.name,
523+
"target_kind": format!("{:?}", dep.target_node.kind),
522524
"dependency_kind": "writes",
523-
"target_file": target_node.file.display().to_string(),
525+
"target_file": dep.target_node.file.display().to_string(),
524526
"target_span": {
525-
"start_line": target_node.span.start_line,
526-
"end_line": target_node.span.end_line,
527-
"start_column": target_node.span.start_column,
528-
"end_column": target_node.span.end_column
527+
"start_line": dep.target_node.span.start_line,
528+
"end_line": dep.target_node.span.end_line,
529+
"start_column": dep.target_node.span.start_column,
530+
"end_column": dep.target_node.span.end_column
529531
}
530532
})
531533
})
@@ -591,29 +593,27 @@ async fn find_references(
591593
});
592594

593595
// Find references to the symbol
594-
if let Ok(references) = server.graph_query().get_references(&symbol_id) {
596+
if let Ok(references) = server.graph_query().find_references(&symbol_id) {
595597
let refs: Vec<_> = references
596598
.iter()
597-
.filter_map(|ref_info| {
598-
server.graph_store().get_node(&ref_info.source).map(|source_node| {
599-
serde_json::json!({
600-
"source_id": ref_info.source.to_hex(),
601-
"source_name": source_node.name,
602-
"source_kind": format!("{:?}", source_node.kind),
603-
"reference_kind": format!("{:?}", ref_info.kind),
604-
"file": source_node.file.display().to_string(),
605-
"span": {
606-
"start_line": source_node.span.start_line,
607-
"end_line": source_node.span.end_line,
608-
"start_column": source_node.span.start_column,
609-
"end_column": source_node.span.end_column
610-
},
611-
"source_context": extract_source_context(
612-
&source_node.file,
613-
source_node.span.start_line,
614-
context_lines
615-
)
616-
})
599+
.map(|ref_info| {
600+
serde_json::json!({
601+
"source_id": ref_info.source_node.id.to_hex(),
602+
"source_name": ref_info.source_node.name,
603+
"source_kind": format!("{:?}", ref_info.source_node.kind),
604+
"reference_kind": format!("{:?}", ref_info.edge_kind),
605+
"file": ref_info.source_node.file.display().to_string(),
606+
"span": {
607+
"start_line": ref_info.source_node.span.start_line,
608+
"end_line": ref_info.source_node.span.end_line,
609+
"start_column": ref_info.source_node.span.start_column,
610+
"end_column": ref_info.source_node.span.end_column
611+
},
612+
"source_context": extract_source_context(
613+
&ref_info.source_node.file,
614+
ref_info.source_node.span.start_line,
615+
context_lines
616+
)
617617
})
618618
})
619619
.collect();
@@ -739,9 +739,7 @@ fn create_node_info_with_context(
739739
});
740740

741741
// Add source context around the symbol location
742-
if let Some(context) =
743-
extract_source_context(&node.file, node.span.start_line, context_lines)
744-
{
742+
if let Some(context) = extract_source_context(&node.file, node.span.start_line, context_lines) {
745743
node_info["source_context"] = context;
746744
}
747745

@@ -754,7 +752,7 @@ mod tests {
754752

755753
#[test]
756754
fn test_parse_node_id_valid() {
757-
let hex_str = "1234567890abcdef";
755+
let hex_str = "1234567890abcdef1234567890abcdef"; // 32 characters = 16 bytes
758756
let result = parse_node_id(hex_str);
759757
assert!(result.is_ok());
760758
}
@@ -768,15 +766,15 @@ mod tests {
768766

769767
#[test]
770768
fn test_is_valid_dependency_node() {
771-
let node = codeprism_core::Node {
772-
id: codeprism_core::NodeId::from_u64(1),
773-
name: "test_function".to_string(),
774-
kind: codeprism_core::NodeKind::Function,
775-
lang: codeprism_core::Language::Python,
776-
file: std::path::PathBuf::from("test.py"),
777-
span: codeprism_core::Span::new(1, 1, 1, 10),
778-
signature: Some("def test_function():".to_string()),
779-
};
769+
let node = codeprism_core::Node::new(
770+
"test_repo",
771+
codeprism_core::NodeKind::Function,
772+
"test_function".to_string(),
773+
codeprism_core::Language::Python,
774+
std::path::PathBuf::from("test.py"),
775+
codeprism_core::Span::new(0, 10, 1, 1, 1, 10),
776+
)
777+
.with_signature("def test_function():".to_string());
780778

781779
assert!(is_valid_dependency_node(&node));
782780
}
@@ -785,7 +783,7 @@ mod tests {
785783
fn test_symbol_tools_list() {
786784
let tools = list_tools();
787785
assert_eq!(tools.len(), 4);
788-
786+
789787
let tool_names: Vec<&str> = tools.iter().map(|t| t.name.as_str()).collect();
790788
assert!(tool_names.contains(&"trace_path"));
791789
assert!(tool_names.contains(&"explain_symbol"));

crates/codeprism-mcp/src/tools/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ impl ToolManager {
129129
// Add tools from modular structure
130130
tools.extend(basic::repository::list_tools());
131131
tools.extend(basic::search::list_tools());
132-
// FUTURE: Re-enable symbols tools after API compatibility updates
133-
// tools.extend(basic::symbols::list_tools());
132+
tools.extend(basic::symbols::list_tools());
134133
tools.extend(analysis::complexity::list_tools());
135134
tools.extend(analysis::patterns::list_tools());
136135
tools.extend(analysis::dependencies::list_tools());
@@ -205,11 +204,10 @@ impl ToolManager {
205204
basic::search::call_tool(&params.name, &server, params.arguments).await
206205
}
207206

208-
// FUTURE: Re-enable symbol navigation tools after API compatibility updates
209207
// Symbol navigation tools
210-
// "trace_path" | "explain_symbol" | "find_dependencies" | "find_references" => {
211-
// basic::symbols::call_tool(&params.name, &server, params.arguments).await
212-
// }
208+
"trace_path" | "explain_symbol" | "find_dependencies" | "find_references" => {
209+
basic::symbols::call_tool(&params.name, &server, params.arguments).await
210+
}
213211

214212
// Analysis tools
215213
"analyze_complexity" => {

0 commit comments

Comments
 (0)