feat(agent): bind transport S-MCP — outils idea_* vivants de bout en bout (M5a-e) — §14.3.1
Dernier kilomètre de l'orchestration native : une CLI MCP réellement lancée
joint le serveur MCP du projet et ses outils idea_* aboutissent au vrai dispatch.
- M5a endpoint loopback par projet (interprocess UDS/named pipe, source unique
mcp_endpoint, cleanup au close) — zéro port réseau, AppImage/SSH-safe.
- M5b sous-commande `idea mcp-server` : pont stdio↔loopback headless (avant init
Tauri), handshake {"project","requester"}, endpoint-absent borné, EOF propre.
- M5c McpServerHandle boucle accept + serve_peer par pair ; requester réel
propagé jusqu'à OrchestratorRequestProcessed (fin du "mcp" figé) ; isolation
des pairs ; terminaison propre.
- M5d apply_mcp_config écrit la déclaration réelle (current_exe + --endpoint
mcp_endpoint + --project simple-uuid + --requester) ; McpRuntime injecté comme
donnée (application ne dépend pas de app-tauri).
- M5e smoke e2e sur vrai loopback : list/ask inline, cible PTY → erreur typée,
JSON malformé → pas de panic, requester propagé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -17,13 +17,49 @@ pub mod chat;
|
||||
pub mod commands;
|
||||
pub mod dto;
|
||||
pub mod events;
|
||||
pub mod mcp_bridge;
|
||||
pub mod mcp_endpoint;
|
||||
pub mod pty;
|
||||
pub mod state;
|
||||
|
||||
use std::process::ExitCode;
|
||||
|
||||
use tauri::Manager;
|
||||
|
||||
use state::AppState;
|
||||
|
||||
/// The `argv[1]` subcommand token that switches the binary into the headless
|
||||
/// `mcp-server` **bridge** mode (cadrage v5 §1.3) instead of launching Tauri.
|
||||
pub const MCP_SERVER_SUBCOMMAND: &str = "mcp-server";
|
||||
|
||||
/// Process entry point: routes `argv` **before** anything Tauri/WebKit is touched.
|
||||
///
|
||||
/// When invoked as `<exe> mcp-server …` (an MCP CLI spawned us from the injected
|
||||
/// `.mcp.json` declaration), we run the **stdio↔loopback bridge** headless and
|
||||
/// **never** initialise the webview — see [`mcp_bridge::run_mcp_bridge`]. Any other
|
||||
/// invocation is the normal IDE launch: [`run`] (which blocks until the window
|
||||
/// closes and then exits the process itself).
|
||||
///
|
||||
/// Returns the [`ExitCode`] for the bridge path; the normal path does not return.
|
||||
#[must_use]
|
||||
pub fn dispatch() -> ExitCode {
|
||||
let mut args = std::env::args_os().skip(1);
|
||||
if args
|
||||
.next()
|
||||
.is_some_and(|a| a == *MCP_SERVER_SUBCOMMAND)
|
||||
{
|
||||
// Headless bridge: bypass Tauri entirely. Forward the remaining args
|
||||
// (`--endpoint`, `--project`, `--requester`) to the bridge parser.
|
||||
let rest: Vec<String> = args
|
||||
.map(|a| a.to_string_lossy().into_owned())
|
||||
.collect();
|
||||
return mcp_bridge::run_mcp_bridge(rest);
|
||||
}
|
||||
|
||||
run();
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
/// Builds and runs the Tauri application.
|
||||
///
|
||||
/// Sets up the composition root (resolving the app-data directory via the Tauri
|
||||
|
||||
Reference in New Issue
Block a user