mod support;
use anyhow::Result;
use rmcp::{model::CallToolRequestParam, service::ServiceExt, transport::TokioChildProcess};
use serde_json::json;
use std::process::Stdio;
use tokio::process::Command;
#[tokio::test]
async fn test_mcp_log_separation_and_tools() -> Result<()> {
println!("๐งช Testing MCP server log separation and tool availability");
let mut build = Command::new("cargo");
build
.arg("build")
.arg("--package")
.arg("terraphim_mcp_server");
if std::env::var_os("CI").is_some() {
build.arg("--features").arg("zlob");
}
let build_status = build.status().await?;
if !build_status.success() {
anyhow::bail!("Failed to build terraphim_mcp_server");
}
let mut cmd = Command::new(support::mcp_server_binary()?);
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.env("RUST_LOG", "info");
let transport = TokioChildProcess::new(cmd)?;
let service = ().serve(transport).await?;
println!("๐ Connected to MCP server: {:?}", service.peer_info());
println!("๐ Testing tools/list...");
let tools = service.list_tools(Default::default()).await?;
println!("โ
Found {} tools", tools.tools.len());
let expected_tools = vec![
"search",
"autocomplete_terms",
"find_matches",
"load_thesaurus",
"update_config_tool",
];
for expected_tool in &expected_tools {
let tool_found = tools.tools.iter().any(|t| t.name == *expected_tool);
if tool_found {
println!(" โ
Tool '{}' found", expected_tool);
} else {
println!(" โ ๏ธ Tool '{}' not found", expected_tool);
}
}
assert!(
!tools.tools.is_empty(),
"Should have at least some tools available"
);
println!("๐ค Testing autocomplete...");
let autocomplete_result = service
.call_tool(CallToolRequestParam {
name: "autocomplete_terms".into(),
arguments: json!({
"query": "terra",
"limit": 5
})
.as_object()
.cloned(),
})
.await?;
println!("โ
Autocomplete result: {:?}", autocomplete_result.content);
println!("๐ Testing search...");
let search_result = service
.call_tool(CallToolRequestParam {
name: "search".into(),
arguments: json!({
"query": "test",
"limit": 5
})
.as_object()
.cloned(),
})
.await?;
println!("โ
Search completed: {:?}", search_result.content);
println!("๐ Testing thesaurus loading...");
let thesaurus_result = service
.call_tool(CallToolRequestParam {
name: "load_thesaurus".into(),
arguments: json!({
"role_name": "Default",
"automata_path": "docs/src/kg"
})
.as_object()
.cloned(),
})
.await?;
println!(
"โ
Thesaurus loading result: {:?}",
thesaurus_result.content
);
println!("๐ All MCP tests passed successfully!");
Ok(())
}
#[tokio::test]
async fn test_mcp_role_configuration() -> Result<()> {
println!("โ๏ธ Testing MCP role configuration");
let mut cmd = Command::new(support::mcp_server_binary()?);
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let transport = TokioChildProcess::new(cmd)?;
let service = ().serve(transport).await?;
println!("๐ Testing configuration update...");
let test_config = json!({
"roles": {
"Test Role": {
"name": "Test Role",
"shortname": "test",
"relevance_function": "TitleScorer",
"theme": "lumen",
"haystacks": [],
"kg": null,
"terraphim_it": false,
"extra": {}
}
},
"selected_role": "Test Role",
"default_role": "Test Role",
"global_shortcut": "Ctrl+Space"
});
let config_result = service
.call_tool(CallToolRequestParam {
name: "update_config_tool".into(),
arguments: json!({
"config_str": test_config.to_string()
})
.as_object()
.cloned(),
})
.await?;
println!(
"โ
Configuration update result: {:?}",
config_result.content
);
let search_result = service
.call_tool(CallToolRequestParam {
name: "search".into(),
arguments: json!({
"query": "test",
"role": "Test Role",
"limit": 3
})
.as_object()
.cloned(),
})
.await?;
println!(
"โ
Search with role configuration: {:?}",
search_result.content
);
println!("๐ MCP role configuration test passed!");
Ok(())
}
#[tokio::test]
async fn test_mcp_text_processing_tools() -> Result<()> {
println!("๐ Testing MCP text processing tools");
let mut cmd = Command::new(support::mcp_server_binary()?);
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let transport = TokioChildProcess::new(cmd)?;
let service = ().serve(transport).await?;
println!("๐ Testing find_matches...");
let find_result = service
.call_tool(CallToolRequestParam {
name: "find_matches".into(),
arguments: json!({
"text": "This is a test document with some test words",
"patterns": ["test", "document"]
})
.as_object()
.cloned(),
})
.await?;
println!("โ
find_matches result: {:?}", find_result.content);
println!("๐ Testing replace_matches...");
let replace_result = service
.call_tool(CallToolRequestParam {
name: "replace_matches".into(),
arguments: json!({
"text": "This is a test document",
"patterns": ["test"],
"replacement": "sample",
"link_type": "PlainText"
})
.as_object()
.cloned(),
})
.await?;
println!("โ
replace_matches result: {:?}", replace_result.content);
println!("๐ Testing extract_paragraphs_from_automata...");
let extract_result = service
.call_tool(CallToolRequestParam {
name: "extract_paragraphs_from_automata".into(),
arguments: json!({
"text": "First paragraph.\n\nSecond paragraph with test content.\n\nThird paragraph.",
"terms": ["test"]
})
.as_object()
.cloned(),
})
.await?;
println!("โ
extract_paragraphs result: {:?}", extract_result.content);
println!("๐ All text processing tools working correctly!");
Ok(())
}