Skip to content

cloudiful/server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cloudiful-server

Small Rust server bootstrap crate for Cloud1ful services. It centralizes shared listen address, CORS, TLS, Axum, Actix, and MCP transport setup without owning application routing.

Features

  • Default: actix
  • axum: Axum Router startup with optional shared state
  • mcp: rmcp stdio helpers plus Streamable HTTP service, router, and server helpers
  • tls: omit tls for plain HTTP, set cert_path + cert_key_path for server TLS, and add client_ca for mTLS

Core Config

use cloudiful_server::{CorsConfig, ServerConfig};

let config = ServerConfig::new()
    .with_listen_addr("127.0.0.1:3000")
    .with_cors(CorsConfig::restricted(["https://intranet.example.com"]))
    .build()?;

Listen addresses like :8080 are normalized to 0.0.0.0:8080.

TLS is opt-in:

use cloudiful_server::{ServerConfig, TlsConfig};

let config = ServerConfig::new()
    .with_tls(
        TlsConfig::new()
            .with_cert_path("cert.pem")
            .with_cert_key_path("key.pem"),
    )
    .build()?;

mTLS uses the same TlsConfig with an extra client CA bundle:

use cloudiful_server::{ServerConfig, TlsConfig};

let config = ServerConfig::new()
    .with_tls(
        TlsConfig::new()
            .with_cert_path("/etc/cloudiful/tls/server.crt")
            .with_cert_key_path("/etc/cloudiful/tls/server.key")
            .with_client_ca("/etc/cloudiful/tls/client-ca.crt"),
    )
    .build()?;

When client_ca is not configured, startup keeps the existing server-only TLS behavior. When client_ca is configured, the server requests and verifies client certificates against that CA bundle.

Actix

Enabled by default.

use actix_web::{HttpResponse, web};
use cloudiful_server::{Server, ServerConfig};

let config = ServerConfig::new().build()?;

Server::new(config, |cfg| {
    cfg.route("/healthz", web::get().to(|| async { HttpResponse::Ok().body("ok") }));
})
.start()
.await?;

Axum

Enable with features = ["axum"].

use axum::{Router, extract::State, routing::get};
use cloudiful_server::ServerConfig;

#[derive(Clone)]
struct AppState {
    service_name: String,
}

let config = ServerConfig::new()
    .with_app_data(AppState {
        service_name: "orders".to_string(),
    })
    .build()?;

let app = Router::new().route(
    "/healthz",
    get(|State(state): State<AppState>| async move { format!("{} ok", state.service_name) }),
);

cloudiful_server::axum::Server::new_with_state(config, app)
    .start()
    .await?;

MCP

Enable with features = ["mcp"].

use cloudiful_server::mcp::{self, tool, tool_router};

#[derive(Clone)]
struct Calculator;

#[tool_router(server_handler)]
impl Calculator {
    #[tool(description = "Add two numbers")]
    fn add(&self, a: i32, b: i32) -> String {
        (a + b).to_string()
    }
}

Run over stdio:

let server = mcp::serve_stdio(Calculator).await?;
server.waiting().await?;

Run as a standalone Streamable HTTP server:

use cloudiful_server::ServerConfig;

let http = ServerConfig::new()
    .with_listen_addr("127.0.0.1:8000")
    .build()?;

mcp::Server::new(http, || Calculator)
    .with_server_config(mcp::ServerConfig::new().with_service_path("/mcp"))
    .start()
    .await?;

Embed into an existing Axum router:

use axum::{Router, routing::get};

let mcp_service = mcp::service(mcp::ServerConfig::new(), || Calculator)?;

let app = Router::new()
    .route("/healthz", get(|| async { "ok" }))
    .nest_service("/mcp", mcp_service);

Build an MCP-only router:

let app = mcp::router(
    mcp::ServerConfig::new().with_service_path("/mcp"),
    || Calculator,
)?;

mcp::service is the shared construction path. mcp::router and mcp::Server build on top of it.

Testing

cargo test
cargo test --features mcp
cargo test --no-default-features --features axum
cargo test --all-features

About

Rust crate for a minimal http server setup (Mirror repo)

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages