aether-mcp-servers 0.5.0

Built-in MCP tool servers for the Aether AI agent framework
Documentation
use clap::Parser;
use mcp_servers::plan::default_plans_dir;
use mcp_servers::workspace_paths::{current_dir, resolve_path};
use mcp_servers::{CodingMcp, CodingMcpArgs, PlanMcp, SkillsMcp, SubAgentsMcp, SurveyMcp, TasksMcp};
use mcp_utils::ServiceExt;
use rmcp::ServerHandler;
use rmcp::transport::io::stdio;

#[derive(Parser)]
#[command(name = "mcp-servers-stdio", about = "Run an MCP server over stdio")]
struct Cli {
    /// Which server to run: coding, skills, tasks, subagents, survey, plan
    #[arg(long)]
    server: String,

    /// Arguments forwarded to the selected server (e.g. --root-dir /path)
    #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
    args: Vec<String>,
}

#[derive(Debug, thiserror::Error)]
enum StdioError {
    #[error("Unknown server: '{0}'. Available: coding, skills, tasks, subagents, survey, plan")]
    UnknownServer(String),
    #[error("{0}")]
    ServerArgs(#[from] mcp_servers::error::ServerInitError),
    #[error("Failed to start server: {0}")]
    Serve(String),
    #[error("Server task failed: {0}")]
    Join(tokio::task::JoinError),
}

async fn serve_stdio(server: impl ServerHandler) -> Result<(), StdioError> {
    let running = server.serve(stdio()).await.map_err(|e| StdioError::Serve(e.to_string()))?;
    running.waiting().await.map_err(StdioError::Join)?;
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), StdioError> {
    let cli = Cli::parse();

    match cli.server.as_str() {
        "coding" => {
            let CodingMcpArgs { root_dir, rules_dirs, permission_mode, disable_lsp } =
                CodingMcpArgs::from_args(cli.args).map_err(StdioError::ServerArgs)?;
            let root_dir = root_dir.unwrap_or_else(current_dir);
            let rules_dirs = rules_dirs.into_iter().map(|path| resolve_path(&root_dir, path)).collect();
            let server = CodingMcp::new()
                .with_root_dir(root_dir.clone())
                .with_rules_dirs(rules_dirs)
                .with_permission_mode(permission_mode);
            let server = if disable_lsp { server } else { server.with_lsp(root_dir) };
            serve_stdio(server).await
        }
        "skills" => {
            let server = SkillsMcp::from_args(cli.args).map_err(StdioError::ServerArgs)?;
            serve_stdio(server).await
        }
        "tasks" => {
            let server = TasksMcp::from_args(cli.args).map_err(StdioError::ServerArgs)?;
            serve_stdio(server).await
        }
        "subagents" => {
            let server = SubAgentsMcp::standalone_from_args(cli.args).map_err(StdioError::ServerArgs)?;
            serve_stdio(server).await
        }
        "survey" => {
            let server = SurveyMcp::from_args(cli.args).map_err(StdioError::ServerArgs)?;
            serve_stdio(server).await
        }
        "plan" => {
            let server = PlanMcp::from_args(cli.args, default_plans_dir()).map_err(StdioError::ServerArgs)?;
            serve_stdio(server).await
        }
        other => Err(StdioError::UnknownServer(other.to_string())),
    }
}