Skip to main content

winx_code_agent/
server.rs

1//! Winx MCP server facade.
2//!
3//! Protocol catalog, session lifecycle, task handling, MCP dispatch, and tool
4//! adapters live in focused submodules under `server/`.
5
6mod agents;
7mod catalog;
8mod coherence;
9mod executions;
10mod handler;
11mod mutations;
12mod outcomes;
13mod principal;
14mod recovery;
15mod sessions;
16mod tasks;
17mod tool_dispatch;
18mod usage;
19mod workflow_types;
20
21#[cfg(test)]
22mod tests;
23
24use std::sync::Arc;
25
26use rmcp::{
27    transport::{async_rw::AsyncRwTransport, stdio},
28    ServiceExt,
29};
30use tokio::sync::Mutex;
31use tracing::info;
32
33use crate::runtime::{configured_shell_runtime, ShellRuntime};
34use crate::state::task_state::TaskRegistry;
35use crate::state::BashState;
36use sessions::SessionRegistry;
37
38pub use sessions::SessionIsolation;
39
40/// Shared shell state for one logical Winx session.
41pub type SharedBashState = Arc<Mutex<Option<BashState>>>;
42
43/// Winx service shared by stdio or HTTP transports.
44#[derive(Clone)]
45pub struct WinxService {
46    sessions: Arc<Mutex<SessionRegistry>>,
47    tasks: Arc<Mutex<TaskRegistry>>,
48    root_bootstrap: Arc<Mutex<()>>,
49    shell_runtime: Arc<dyn ShellRuntime>,
50    mutations: mutations::MutationCoordinator,
51    execution_history: Arc<executions::history::WorkflowHistory>,
52    /// Version information advertised in the MCP handshake.
53    pub version: String,
54    isolation: SessionIsolation,
55}
56
57/// Create and start the Winx MCP server.
58pub async fn start_winx_server() -> Result<(), Box<dyn std::error::Error>> {
59    Box::pin(start_winx_server_with_runtime(configured_shell_runtime().await?)).await
60}
61
62/// Create and start the stdio MCP server with an explicit shell runtime.
63pub async fn start_winx_server_with_runtime(
64    runtime: Arc<dyn ShellRuntime>,
65) -> Result<(), Box<dyn std::error::Error>> {
66    info!("Starting Winx MCP Server");
67    let service = WinxService::with_runtime(SessionIsolation::Lenient, runtime);
68    let (stdin, stdout) = stdio();
69    let transport = AsyncRwTransport::new_server(stdin, stdout);
70    let server = Box::pin(service.serve(transport)).await?;
71    server.waiting().await?;
72    Ok(())
73}