新增: MCP HTTP transport + 系统托盘 + 实体解析(会话前基线收尾)
- df-mcp 加 streamable HTTP transport 层(axum 0.7 + tower,server_http.rs),lib.rs pub mod 接线 - src-tauri 加 mcp.rs(spawn_mcp_http + mcp_get_status IPC + mcp-server CLI)+ tray.rs(系统托盘 show_main/setup_tray),lib.rs 集成 + main.rs mcp-server 参数路由 - AI 工具加 entity_resolve.rs(实体解析,tools/mod.rs pub mod 接线)
This commit is contained in:
+42
-20
@@ -7,8 +7,7 @@ use std::process::ExitCode;
|
||||
fn main() -> ExitCode {
|
||||
// CLI 子命令:手动解析 argv(避免引入 clap 重依赖)。
|
||||
//
|
||||
// `devflow mcp-server [--db <path>] [--read-only]`
|
||||
// `devflow mcp-server --print-config`
|
||||
// `devflow mcp-server [--db <path>] [--read-only] [--stdio] [--print-config]`
|
||||
//
|
||||
// 仅识别首个非程序名参数是否为 `mcp-server`;其余情况走 GUI。
|
||||
// stdio 句柄由父进程(MCP 客户端)继承,无需额外配置。
|
||||
@@ -24,10 +23,12 @@ fn main() -> ExitCode {
|
||||
///
|
||||
/// - `--db <path>`:指定 SQLite 路径(默认:系统 app_data_dir/devflow[-dev].db)
|
||||
/// - `--read-only`:仅暴露 list/get 工具
|
||||
/// - `--print-config`:输出 Claude Code / Cursor 的 MCP 配置 JSON 片段到 stdout 后退出
|
||||
/// - `--stdio`:显式声明 stdio 形态(默认即 stdio;headless/CI/GUI 未启动场景)
|
||||
/// - `--print-config`:输出 MCP 配置到 stdout 后退出(默认 HTTP 形态,加 --stdio 输出 stdio command 形态)
|
||||
fn run_mcp_server(args: &[String]) -> ExitCode {
|
||||
let mut db_path: Option<PathBuf> = None;
|
||||
let mut read_only = false;
|
||||
let mut stdio_mode = false;
|
||||
let mut print_config = false;
|
||||
|
||||
let mut i = 0;
|
||||
@@ -42,13 +43,15 @@ fn run_mcp_server(args: &[String]) -> ExitCode {
|
||||
db_path = Some(PathBuf::from(&args[i]));
|
||||
}
|
||||
"--read-only" => read_only = true,
|
||||
"--stdio" => stdio_mode = true,
|
||||
"--print-config" => print_config = true,
|
||||
"-h" | "--help" => {
|
||||
println!("devflow mcp-server [--db <path>] [--read-only] [--print-config]");
|
||||
println!("devflow mcp-server [--db <path>] [--read-only] [--stdio] [--print-config]");
|
||||
println!();
|
||||
println!(" --db <path> 指定 SQLite 数据库路径(默认:app_data_dir/devflow.db)");
|
||||
println!(" --db <path> 指定 SQLite 数据库路径(默认:app_data_dir/<identifier>/devflow[-dev].db)");
|
||||
println!(" --read-only 仅暴露 list/get 工具(拒绝 create/update/delete)");
|
||||
println!(" --print-config 输出 MCP 配置 JSON 片段到 stdout 后退出");
|
||||
println!(" --stdio 显式声明 stdio 形态(默认即 stdio;headless/CI/GUI 未启动场景)");
|
||||
println!(" --print-config 输出 MCP 配置(默认 HTTP,加 --stdio 输出 stdio command 形态)");
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
other => {
|
||||
@@ -60,18 +63,36 @@ fn run_mcp_server(args: &[String]) -> ExitCode {
|
||||
}
|
||||
|
||||
if print_config {
|
||||
// 输出 Claude Code / Cursor 兼容的 MCP 配置片段(command/args 形态)。
|
||||
// Claude Code: claude mcp add devflow -- devflow mcp-server [--read-only]
|
||||
// 说明性注释(非 JSON)打 stderr,保证 stdout 是纯 JSON 可直接被客户端消费。
|
||||
if !stdio_mode {
|
||||
// 默认输出 HTTP 形态:桌面进程内嵌 HTTP MCP server + 托盘常驻,
|
||||
// Claude Code 用 --transport http 直连同一进程。端口 18765 与
|
||||
// crates/df-mcp/src/server_http.rs 的 DEFAULT_MCP_PORT 对齐(本文件不 import,直接写死)。
|
||||
let json = r#"{"mcpServers":{"devflow":{"transport":"http","url":"http://127.0.0.1:18765/mcp"}}}"#;
|
||||
println!("{json}");
|
||||
eprintln!("# Claude Code 接入(需先启动 DevFlow 桌面进程,托盘常驻):");
|
||||
eprintln!("# claude mcp add --transport http devflow http://127.0.0.1:18765/mcp");
|
||||
eprintln!("# stdio 备选(无 GUI 场景):");
|
||||
eprintln!("# devflow mcp-server --stdio --print-config");
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
// 输出 Claude Code / Cursor 兼容的 MCP 配置片段(command/args 形态,显式带 --stdio)。
|
||||
// Claude Code: claude mcp add devflow -- devflow mcp-server --stdio [--read-only]
|
||||
// Cursor: 在 ~/.cursor/mcp.json 加 mcpServers.devflow
|
||||
let read_only_flag = if read_only { r#","--read-only""# } else { "" };
|
||||
// 用当前可执行文件绝对路径(command 需要能被客户端直接执行;硬编码 devflow
|
||||
// 在 Windows 上是 DevFlow.exe,且 PATH 未必含安装目录)。
|
||||
let exe = std::env::current_exe()
|
||||
.map(|p| p.to_string_lossy().replace('\\', "/"))
|
||||
.unwrap_or_else(|_| "devflow".to_owned());
|
||||
let json = format!(
|
||||
r#"{{"mcpServers":{{"devflow":{{"command":"devflow","args":["mcp-server"{read_only_flag}]}}}}}}"#
|
||||
r#"{{"mcpServers":{{"devflow":{{"command":"{exe}","args":["mcp-server","--stdio"{read_only_flag}]}}}}}}"#
|
||||
);
|
||||
println!("{json}");
|
||||
println!();
|
||||
println!("# Claude Code 接入:");
|
||||
println!("# claude mcp add devflow -- devflow mcp-server");
|
||||
println!("# Cursor 接入:把上面 JSON 写入 ~/.cursor/mcp.json");
|
||||
eprintln!("# Claude Code 接入(stdio 形态):");
|
||||
eprintln!("# claude mcp add devflow -- {exe} mcp-server --stdio");
|
||||
eprintln!("# Cursor 接入:把上面 JSON 写入 ~/.cursor/mcp.json");
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -105,13 +126,12 @@ fn run_mcp_server(args: &[String]) -> ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
/// 默认数据库路径:与 GUI 应用同库(系统 app_data_dir/devflow.db 或 dev-dev.db)。
|
||||
/// 默认数据库路径:与 GUI 应用同库(系统 app_data_dir/{identifier}/devflow[-dev].db)。
|
||||
///
|
||||
/// 复用与 lib.rs::run 一致的命名(debug 用 devflow-dev.db,release 用 devflow.db),
|
||||
/// 保证 MCP server 与 GUI 读写同一文件。
|
||||
/// GUI 模式通过 Tauri 的 `app.path().app_data_dir()` 获取路径(含 identifier),
|
||||
/// CLI 模式无 app handle,改用编译时注入的 MCP_APP_IDENTIFIER 拼出相同路径。
|
||||
/// 保证 MCP server 与 GUI 读写同一数据库,无需手动传 --db。
|
||||
fn default_db_path() -> anyhow::Result<PathBuf> {
|
||||
// tauri 的 app_data_dir 需要 app handle,CLI 无 handle;用 dirs crate 或平台约定降级。
|
||||
// 这里用 std 环境变量推导(不引 dirs):优先 APPDATA/tav(Windows)、HOME( unix)。
|
||||
let base = if cfg!(target_os = "windows") {
|
||||
std::env::var("APPDATA").map(PathBuf::from)?
|
||||
} else if cfg!(target_os = "macos") {
|
||||
@@ -121,8 +141,10 @@ fn default_db_path() -> anyhow::Result<PathBuf> {
|
||||
let home = std::env::var("HOME").map(PathBuf::from)?;
|
||||
home.join(".local/share")
|
||||
};
|
||||
// Tauri app_data_dir 末段为包名/产品名(devflow)。dev 模式可能为 devflow-dev。
|
||||
let dir = base.join("devflow");
|
||||
// 从编译时环境变量 MCP_APP_IDENTIFIER 读取 Tauri identifier(如 top.1216.devflow),
|
||||
// 与 tauri::path::PathResolver::app_data_dir 行为一致,拼出正确路径。
|
||||
let identifier = option_env!("MCP_APP_IDENTIFIER").unwrap_or("devflow");
|
||||
let dir = base.join(identifier);
|
||||
std::fs::create_dir_all(&dir)?;
|
||||
let name = if cfg!(debug_assertions) {
|
||||
"devflow-dev.db"
|
||||
|
||||
Reference in New Issue
Block a user