server-less 0.4.0

Composable derive macros for common Rust patterns
Documentation

Server-less - Composable derive macros for Rust

Server-less takes an impl-first approach: write your Rust methods, and derive macros project them into various protocols (HTTP, CLI, MCP, WebSocket).

Quick Start

use server_less::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct User { name: String, email: String }

#[derive(Debug, ServerlessError)]
enum UserError { NotFound }

struct UserService;

#[mcp]
impl UserService {
    /// Create a new user
    async fn create_user(&self, name: String, email: String) -> Result<User, UserError> {
        Ok(User { name, email })
    }

    /// List all users
    async fn list_users(&self, limit: Option<u32>) -> Vec<User> {
        let _ = limit;
        vec![]
    }
}

This generates:

  • MCP: Tools create_user, list_users (Model Context Protocol)

Available Macros

Macro Protocol Generated Methods
#[http] HTTP/REST http_router(), openapi_spec()
#[cli] Command Line cli_command(), cli_run()
#[mcp] MCP mcp_tools(), mcp_call(), mcp_call_async()
#[ws] WebSocket ws_router(), ws_handle_message(), ws_handle_message_async()

Naming Conventions

Method names infer HTTP methods and CLI subcommand structure:

Prefix HTTP CLI
create_*, add_* POST <cmd> create-*
get_*, fetch_* GET (single) <cmd> get-*
list_*, find_* GET (collection) <cmd> list-*
update_*, set_* PUT <cmd> update-*
delete_*, remove_* DELETE <cmd> delete-*

Return Types

Type HTTP CLI MCP/WS
T 200 + JSON stdout JSON JSON result
Option<T> 200 or 404 stdout or exit 1 result or null
Result<T, E> 200 or error stdout or stderr result or error
() 204 silent {"success": true}
impl Stream<Item=T> SSE N/A N/A

Async Methods

All macros support async methods:

use server_less::prelude::*;

struct MyService;

#[mcp]
impl MyService {
    /// Sync method - works with mcp_call() and mcp_call_async()
    pub fn sync_method(&self) -> String {
        String::from("hello")
    }

    /// Async method - use mcp_call_async() for proper await
    pub async fn async_method(&self) -> String {
        String::from("hello async")
    }
}

#[tokio::main]
async fn main() {
    let service = MyService;
    // Sync call (errors on async methods)
    service.mcp_call("sync_method", serde_json::json!({}));
    // Async call (awaits async methods properly)
    service.mcp_call_async("async_method", serde_json::json!({})).await;
}

SSE Streaming (HTTP)

Return impl Stream<Item=T> for Server-Sent Events:

use server_less::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Clone, Serialize, Deserialize)]
struct Event { message: String }

#[derive(Clone)]
struct StreamService;

#[http]
impl StreamService {
    // Note: Rust 2024 requires `+ use<>` to avoid lifetime capture
    pub fn stream_events(&self) -> impl futures::Stream<Item = Event> + use<> {
        futures::stream::iter(vec![Event { message: String::from("hello") }])
    }
}

Feature Flags

Enable only what you need:

[dependencies]
server-less = { version = "0.2", default-features = false, features = ["http", "cli"] }

Available features:

  • mcp - MCP macro (no extra deps)
  • http - HTTP macro (requires axum)
  • cli - CLI macro (requires clap)
  • ws - WebSocket macro (requires axum, futures)
  • full - All features (default)