Skip to main content

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}