feat: Replace python tests with native E2E test suite and fix capabilities schema
- Added native E2E test suite in stub to validate server<->stub<->nvim IPC - Added win-nvim integration tests - Fixed empty capabilities schema in initialize response in server and win-nvim - Refactored server to accept dynamic MCP_PORT for test isolation - Made server exit gracefully on port 3000 collision
This commit is contained in:
1 parent
f2582b58be
commit
d71b1e6e35
11 files changed
+327
-79
No files matched your search
+25
-13
@@ -56,7 +56,10 @@ async fn main() {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id,
|
||||
result: Some(json!({
|
||||
"capabilities": {},
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {
|
||||
"tools": {}
|
||||
},
|
||||
"serverInfo": {
|
||||
"name": "mcp-memory-win-nvim",
|
||||
"version": "0.1.0"
|
||||
@@ -329,7 +332,27 @@ async fn main() {
|
||||
}
|
||||
|
||||
async fn get_socket_path() -> Result<String, String> {
|
||||
// 1. Try auto-discovery in \\.\pipe\
|
||||
// 1. Primary: Use the active_nvim.txt which is updated by Neovim's BufEnter telemetry
|
||||
let profile = std::env::var("USERPROFILE").unwrap_or_else(|_| "C:\\Users\\reazul.ashraf".into());
|
||||
let path = format!("{}\\.gemini\\active_nvim.txt", profile);
|
||||
|
||||
if let Ok(content) = std::fs::read_to_string(&path) {
|
||||
let p = content.trim().to_string();
|
||||
if !p.is_empty() {
|
||||
// It might be a full pipe path or just the name. If it's just the name, prepend \\.\pipe\
|
||||
if p.starts_with(r"\\.\pipe\") {
|
||||
return Ok(p);
|
||||
} else if p.starts_with("nvim.") {
|
||||
return Ok(format!(r"\\.\pipe\{}", p));
|
||||
} else {
|
||||
// Some other servername format? Try it as is.
|
||||
return Ok(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to auto-discovery in \\.\pipe\ (only if single instance is running)
|
||||
tracing::warn!("active_nvim.txt missing or invalid, falling back to pipe discovery");
|
||||
if let Ok(dir) = std::fs::read_dir(r"\\.\pipe\") {
|
||||
for entry in dir.flatten() {
|
||||
let name = entry.file_name();
|
||||
@@ -339,17 +362,6 @@ async fn get_socket_path() -> Result<String, String> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to active_nvim.txt
|
||||
let profile = std::env::var("USERPROFILE").unwrap_or_else(|_| "C:\\Users\\reazul.ashraf".into());
|
||||
let path = format!("{}\\.gemini\\active_nvim.txt", profile);
|
||||
|
||||
if let Ok(content) = std::fs::read_to_string(&path) {
|
||||
let p = content.trim().to_string();
|
||||
if !p.is_empty() {
|
||||
return Ok(p);
|
||||
}
|
||||
}
|
||||
|
||||
Err("Could not find active Windows Neovim named pipe".to_string())
|
||||
}
|
||||
|
||||
+14
-1
@@ -40,7 +40,20 @@ pub async fn read_message(stdin: &mut BufReader<tokio::io::Stdin>) -> Option<Jso
|
||||
}
|
||||
let mut buffer = vec![0; length];
|
||||
stdin.read_exact(&mut buffer).await.unwrap_or(0);
|
||||
serde_json::from_slice(&buffer).ok()
|
||||
|
||||
match serde_json::from_slice::<JsonRpcRequest>(&buffer) {
|
||||
Ok(req) => Some(req),
|
||||
Err(e) => {
|
||||
let s = String::from_utf8_lossy(&buffer);
|
||||
tracing::error!("Failed to parse JSON-RPC request: {}. Payload: {}", e, s);
|
||||
Some(JsonRpcRequest {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: None,
|
||||
method: "unknown_parse_error".to_string(),
|
||||
params: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_response(response: JsonRpcResponse) {
|
||||
|
||||
Reference in new issue
Block a user