re_ghidra_qwen_mcp/main.rs
1//! `re-ghidra-qwen-mcp` — the extension's MCP server, spoken over stdio.
2//!
3//! Qwen Code launches this binary via `mcpServers` in `qwen-extension.json` and
4//! talks JSON-RPC to it on stdin/stdout. It owns no reverse-engineering logic:
5//! the server, its 19 tools, the config contract and the embedded Ghidra worker
6//! all live in the shared `ghidra-mcp` crate, so the cc and agy plugins front
7//! exactly the same code. What this binary contributes is the Qwen-Code-shaped
8//! part — reading `.qwen/re-ghidra-mcp-qwen.local.md` as the lowest config layer.
9//!
10//! Two rules follow from stdio being the protocol channel, and both are easy to
11//! get wrong:
12//!
13//! 1. **stdout belongs to the protocol.** `serve` logs only to its per-instance
14//! file log; usage and configuration errors go to stderr.
15//! 2. **The process is long-lived.** It stays up until Qwen Code closes the
16//! pipe.
17
18#[tokio::main]
19async fn main() {
20 let args: Vec<String> = std::env::args().skip(1).collect();
21
22 // Qwen Code launches MCP servers with the workspace as the working
23 // directory, so this is where the project's settings file lives.
24 let project_dir = std::env::current_dir().unwrap_or_default();
25 let file_config = re_ghidra_mcp_qwen::load_settings(&project_dir);
26
27 let code = ghidra_mcp::cli::dispatch(
28 env!("CARGO_BIN_NAME"),
29 env!("CARGO_PKG_VERSION"),
30 args,
31 file_config,
32 )
33 .await;
34 if code != 0 {
35 std::process::exit(code);
36 }
37}