Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@
"Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); [print\\(p[''''name''''], p[''''version'''']\\) for p in d[''''packages''''] if p[''''name'''']==''''rmcp'''']\")",
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); [print\\(p[''''name''''], p[''''version'''']\\) for p in d[''''packages''''] if p[''''name'''']==''''rmcp'''']\")",
"Bash(git push:*)",
"Bash(gh pr:*)"
"Bash(gh pr:*)",
"Bash(do head:*)"
],
"deny": []
}
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ resolver = "2"

[workspace.package]
version = "0.17.0"
rust-version = "1.88"
rust-version = "1.89"
edition = "2024"
license = "MIT OR Apache-2.0"
authors = ["PulseEngine Contributors"]
Expand Down
16 changes: 8 additions & 8 deletions conformance-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,14 @@ fn list_servers() -> Result<()> {
let entry = entry?;
let path = entry.path();

if path.extension().and_then(|s| s.to_str()) == Some("json") {
if let Some(name) = path.file_stem().and_then(|s| s.to_str()) {
// Try to load config to get description
if let Ok(config) = ServerConfig::load(&path) {
println!(" {} - {}", name.green(), config.description);
} else {
println!(" {name}");
}
if path.extension().and_then(|s| s.to_str()) == Some("json")
&& let Some(name) = path.file_stem().and_then(|s| s.to_str())
{
// Try to load config to get description
if let Ok(config) = ServerConfig::load(&path) {
println!(" {} - {}", name.green(), config.description);
} else {
println!(" {name}");
}
}
}
Expand Down
17 changes: 8 additions & 9 deletions conformance-tests/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ impl ConformanceRunner {

// Copy conformance results if they exist
let conformance_results = PathBuf::from("results");
if conformance_results.exists() {
if let Err(e) = copy_dir_all(&conformance_results, &self.results_dir) {
eprintln!("{} Failed to copy conformance results: {}", "⚠".yellow(), e);
}
if conformance_results.exists()
&& let Err(e) = copy_dir_all(&conformance_results, &self.results_dir)
{
eprintln!("{} Failed to copy conformance results: {}", "⚠".yellow(), e);
}

// Generate summary
Expand Down Expand Up @@ -172,12 +172,11 @@ impl ConformanceRunner {
if failures > 0 {
println!("{} Failed checks:", "⚠".yellow());
for check in checks_array {
if check["status"] == "FAILURE" {
if let (Some(name), Some(desc)) =
if check["status"] == "FAILURE"
&& let (Some(name), Some(desc)) =
(check["name"].as_str(), check["description"].as_str())
{
println!(" - {name}: {desc}");
}
{
println!(" - {name}: {desc}");
}
}
}
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/cli_server_integration.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
//! Integration tests for CLI and server interaction

use crate::test_utils::*;
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/end_to_end_scenarios.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
//! End-to-end integration scenarios that test the complete MCP framework

use crate::test_utils::*;
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/monitoring_integration.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
//! Integration tests for monitoring across multiple components

use crate::test_utils::*;
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/transport_server_integration.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
//! Integration tests for transport and server interaction

use crate::test_utils::*;
Expand Down
12 changes: 6 additions & 6 deletions mcp-external-validation/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,12 @@ impl ValidationConfig {
});
}

if let Some(ref url) = self.jsonrpc.validator_url {
if !url.starts_with("http") {
return Err(ValidationError::ConfigurationError {
message: "JSON-RPC validator URL must start with http or https".to_string(),
});
}
if let Some(ref url) = self.jsonrpc.validator_url
&& !url.starts_with("http")
{
return Err(ValidationError::ConfigurationError {
message: "JSON-RPC validator URL must start with http or https".to_string(),
});
}

// Validate port ranges
Expand Down
54 changes: 27 additions & 27 deletions mcp-external-validation/src/cross_language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,25 +216,25 @@ impl CrossLanguageTester {
let python_commands = ["python3", "python"];

for cmd in &python_commands {
if let Ok(output) = Command::new(cmd).arg("--version").output() {
if output.status.success() {
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();

// Check if MCP package is available
let sdk_check = Command::new(cmd)
.args(&["-c", "import mcp; print('available')"])
.output();

let sdk_available = sdk_check.map(|o| o.status.success()).unwrap_or(false);

return Ok(LanguageRuntime {
language: Language::Python,
executable: cmd.to_string(),
version,
sdk_available,
test_scripts_dir: Some(std::env::temp_dir().join("mcp_python_cross_tests")),
});
}
if let Ok(output) = Command::new(cmd).arg("--version").output()
&& output.status.success()
{
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();

// Check if MCP package is available
let sdk_check = Command::new(cmd)
.args(&["-c", "import mcp; print('available')"])
.output();

let sdk_available = sdk_check.map(|o| o.status.success()).unwrap_or(false);

return Ok(LanguageRuntime {
language: Language::Python,
executable: cmd.to_string(),
version,
sdk_available,
test_scripts_dir: Some(std::env::temp_dir().join("mcp_python_cross_tests")),
});
}
}

Expand Down Expand Up @@ -828,17 +828,17 @@ async function testMcpCrossLanguage(serverUrl, protocolVersion) {{
if needs_setup {
match language {
Language::Python => {
if let Some(runtime) = self.available_languages.get_mut(&language) {
if let Err(e) = Self::setup_python_environment(runtime).await {
warn!("Failed to setup Python environment: {}", e);
}
if let Some(runtime) = self.available_languages.get_mut(&language)
&& let Err(e) = Self::setup_python_environment(runtime).await
{
warn!("Failed to setup Python environment: {}", e);
}
}
Language::JavaScript | Language::TypeScript => {
if let Some(runtime) = self.available_languages.get_mut(&language) {
if let Err(e) = Self::setup_javascript_environment(runtime).await {
warn!("Failed to setup JavaScript environment: {}", e);
}
if let Some(runtime) = self.available_languages.get_mut(&language)
&& let Err(e) = Self::setup_javascript_environment(runtime).await
{
warn!("Failed to setup JavaScript environment: {}", e);
}
}
_ => {
Expand Down
22 changes: 11 additions & 11 deletions mcp-external-validation/src/ecosystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,17 +280,17 @@ impl EcosystemTester {

/// Detect Cline CLI
fn detect_cline(&self) -> ValidationResult<ComponentInfo> {
if let Ok(output) = Command::new("cline").arg("--version").output() {
if output.status.success() {
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
return Ok(ComponentInfo {
component: EcosystemComponent::Cline,
available: true,
version: Some(version),
location: None,
metadata: HashMap::new(),
});
}
if let Ok(output) = Command::new("cline").arg("--version").output()
&& output.status.success()
{
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
return Ok(ComponentInfo {
component: EcosystemComponent::Cline,
available: true,
version: Some(version),
location: None,
metadata: HashMap::new(),
});
}

Err(ValidationError::ConfigurationError {
Expand Down
8 changes: 4 additions & 4 deletions mcp-external-validation/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,10 @@ impl InspectorClient {
fn extract_session_token(&self, stderr: &str) -> Option<String> {
// Look for lines like "🔑 Session token: 3a1c267fad21f7150b7d624c..."
for line in stderr.lines() {
if line.contains("Session token:") {
if let Some(token_part) = line.split("Session token:").nth(1) {
return Some(token_part.trim().to_string());
}
if line.contains("Session token:")
&& let Some(token_part) = line.split("Session token:").nth(1)
{
return Some(token_part.trim().to_string());
}
}
None
Expand Down
134 changes: 67 additions & 67 deletions mcp-external-validation/src/jsonrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,15 +332,15 @@ impl JsonRpcValidator {
}

// Check for empty string IDs
if let Some(id_str) = id.as_str() {
if id_str.is_empty() {
issues.push(ValidationIssue::new(
IssueSeverity::Warning,
"id_format".to_string(),
format!("Message {}: Empty string ID is not recommended", index),
"jsonrpc-validator".to_string(),
));
}
if let Some(id_str) = id.as_str()
&& id_str.is_empty()
{
issues.push(ValidationIssue::new(
IssueSeverity::Warning,
"id_format".to_string(),
format!("Message {}: Empty string ID is not recommended", index),
"jsonrpc-validator".to_string(),
));
}
}
}
Expand All @@ -352,43 +352,43 @@ impl JsonRpcValidator {
index: usize,
issues: &mut Vec<ValidationIssue>,
) {
if let Some(method) = message.get("method") {
if let Some(method_str) = method.as_str() {
// Check for reserved method names (starting with rpc.)
if method_str.starts_with("rpc.") && !self.is_allowed_rpc_method(method_str) {
issues.push(ValidationIssue::new(
IssueSeverity::Error,
"method_naming".to_string(),
format!(
"Message {}: Method name '{}' is reserved",
index, method_str
),
"jsonrpc-validator".to_string(),
));
}
if let Some(method) = message.get("method")
&& let Some(method_str) = method.as_str()
{
// Check for reserved method names (starting with rpc.)
if method_str.starts_with("rpc.") && !self.is_allowed_rpc_method(method_str) {
issues.push(ValidationIssue::new(
IssueSeverity::Error,
"method_naming".to_string(),
format!(
"Message {}: Method name '{}' is reserved",
index, method_str
),
"jsonrpc-validator".to_string(),
));
}

// Check for method name conventions
if method_str.is_empty() {
issues.push(ValidationIssue::new(
IssueSeverity::Error,
"method_naming".to_string(),
format!("Message {}: Method name cannot be empty", index),
"jsonrpc-validator".to_string(),
));
}
// Check for method name conventions
if method_str.is_empty() {
issues.push(ValidationIssue::new(
IssueSeverity::Error,
"method_naming".to_string(),
format!("Message {}: Method name cannot be empty", index),
"jsonrpc-validator".to_string(),
));
}

// Check for non-ASCII characters
if !method_str.is_ascii() {
issues.push(ValidationIssue::new(
IssueSeverity::Warning,
"method_naming".to_string(),
format!(
"Message {}: Method name contains non-ASCII characters",
index
),
"jsonrpc-validator".to_string(),
));
}
// Check for non-ASCII characters
if !method_str.is_ascii() {
issues.push(ValidationIssue::new(
IssueSeverity::Warning,
"method_naming".to_string(),
format!(
"Message {}: Method name contains non-ASCII characters",
index
),
"jsonrpc-validator".to_string(),
));
}
}
}
Expand Down Expand Up @@ -434,21 +434,21 @@ impl JsonRpcValidator {

/// Check error codes
fn check_error_codes(&self, message: &Value, index: usize, issues: &mut Vec<ValidationIssue>) {
if let Some(error) = message.get("error") {
if let Some(error_obj) = error.as_object() {
if let Some(code) = error_obj.get("code") {
if let Some(code_num) = code.as_i64() {
if !self.is_valid_error_code(code_num) {
issues.push(ValidationIssue::new(
IssueSeverity::Warning,
"error_codes".to_string(),
format!("Message {}: Error code {} is not a standard JSON-RPC error code", index, code_num),
"jsonrpc-validator".to_string(),
));
}
}
}
}
if let Some(error) = message.get("error")
&& let Some(error_obj) = error.as_object()
&& let Some(code) = error_obj.get("code")
&& let Some(code_num) = code.as_i64()
&& !self.is_valid_error_code(code_num)
{
issues.push(ValidationIssue::new(
IssueSeverity::Warning,
"error_codes".to_string(),
format!(
"Message {}: Error code {} is not a standard JSON-RPC error code",
index, code_num
),
"jsonrpc-validator".to_string(),
));
}
}

Expand Down Expand Up @@ -801,10 +801,10 @@ impl JsonRpcValidator {
// Parse stdout for JSON-RPC responses
let stdout_str = String::from_utf8_lossy(&output.stdout);
for line in stdout_str.lines() {
if let Ok(parsed) = serde_json::from_str::<Value>(line) {
if self.is_jsonrpc_message(&parsed) {
messages.push(parsed);
}
if let Ok(parsed) = serde_json::from_str::<Value>(line)
&& self.is_jsonrpc_message(&parsed)
{
messages.push(parsed);
}
}
}
Expand Down Expand Up @@ -871,10 +871,10 @@ impl JsonRpcValidator {
// Send request and collect response
match client.post(server_url).json(&request).send().await {
Ok(response) => {
if response.status().is_success() {
if let Ok(response_json) = response.json::<Value>().await {
messages.push(response_json);
}
if response.status().is_success()
&& let Ok(response_json) = response.json::<Value>().await
{
messages.push(response_json);
}
}
Err(_) => {
Expand Down
Loading
Loading