Iteration Log
Living document tracking the evolution of server-less macros.
Current State (2025-01-20)
Working Macros
| Macro | Status | Key Features |
|---|---|---|
#[mcp] | ✅ Solid | Tool schemas, dispatch, optional params |
#[http] | ✅ Working | Axum router, OpenAPI, method inference |
#[cli] | ✅ Working | Clap subcommands, async support, JSON output |
Shared Patterns Identified
- Parameter Extraction - All three parse params, detect optionality, handle IDs
- Return Type Handling -
Result<T,E>,Option<T>,Vec<T>, unit, plain T - Async Detection - All need to handle sync vs async methods
- Doc Comments - All use
///docs for descriptions/help text - Method Name Conventions -
create_*,get_*,list_*, etc.
Current Pain Points
- Duplication - Param extraction logic repeated in each macro
- OpenAPI coupling - Baked into HTTP macro, should be composable
- No streaming tests -
impl Stream<Item=T>path untested - No error derive - Manual error code mapping
Protocols to Explore
| Protocol | Would Test | Complexity |
|---|---|---|
| gRPC | Streaming, protobuf, error codes | High |
| WebSocket | Bidirectional, connection state | Medium |
| GraphQL | Nested types, query/mutation | Medium |
| SSE | One-way streaming | Low |
Iteration 1: Assess Refactor Opportunity
Goal: Determine if shared abstractions would help.
Analysis: Looking at MCP, HTTP, CLI param/return handling:
- Similar structure but different outputs (JSON schema vs axum extractors vs clap args)
- Return handling: MCP →
Result<Value, String>, HTTP → axum responses, CLI → stdout - The duplication is conceptual, not copy-paste
Decision: Hold on refactor. The patterns aren't converged enough yet. Adding another protocol will give more data points.
Iteration 2: Add WebSocket Support
Goal: Add #[ws] macro to test bidirectional communication patterns.
Why WebSocket:
- Tests connection state (HTTP is stateless, WS has persistent connections)
- Tests bidirectional patterns (send/receive)
- Uses axum, so builds on HTTP infrastructure
- Common need for real-time apps
Plan:
- [x] Create
ws.rswith WebSocket macro - [x] Handle message types (text, binary, ping/pong)
- [x] Test with simple echo/chat example
- [x] Document patterns that emerge
Result: WebSocket macro implemented using JSON-RPC pattern over WebSocket. Key observations:
- WS ≈ MCP: Both are RPC-over-transport. Method dispatch is nearly identical.
- Pattern families emerging:
- RPC: MCP, WS - dispatch by method name from JSON
- REST: HTTP - dispatch by URL path + verb
- CLI: dispatch by subcommand name
- Shared code: Param extraction and return type handling are copy-paste between WS and MCP
- Feature gates needed: Added features for mcp, http, cli, ws (all enabled by default)
Iteration 3: Refactor RPC Pattern
Goal: Extract shared RPC dispatch logic from MCP and WS.
Observation: MCP's generate_dispatch_arm and WS's generate_dispatch_arm are nearly identical:
- Extract params from JSON Value
- Call method with params
- Handle Result/Option/unit/T return types
- Serialize result to JSON
Plan:
- [x] Create
rpc.rswith shared RPC dispatch generation - [x] Refactor MCP to use shared code
- [x] Refactor WS to use shared code
- [x] Add tests to ensure behavior unchanged
- [x] Add feature gates to lib.rs
Result: Created rpc.rs with:
generate_param_extraction()- extract single param from JSONgenerate_all_param_extractions()- extract all paramsgenerate_method_call()- call method with async handling optionsgenerate_json_response()- handle Result/Option/unit/T → JSONgenerate_dispatch_arm()- complete match arm combining abovegenerate_param_schema()- JSON schema for paramsinfer_json_type()- Rust type → JSON schema type
MCP and WS now both use rpc::generate_dispatch_arm() - significant code reduction.
Added feature gates:
mcp- MCP macro (no extra deps)http- HTTP macro (requires axum)cli- CLI macro (requires clap)ws- WebSocket macro (requires axum+futures)full- all of the above (default)
Current Status
| Macro | Status | Tests | Shared Code |
|---|---|---|---|
| MCP | ✅ | 8 | rpc.rs |
| HTTP | ✅ | 3 | - |
| CLI | ✅ | 6 | - |
| WS | ✅ | 10 | rpc.rs |
| Total | 27 |
Pattern families:
- RPC (MCP, WS): JSON dispatch, shared via
rpc.rs - REST (HTTP): URL routing, response types
- CLI: Subcommand dispatch, argument parsing
Iteration 4: SSE Streaming Support
Goal: Verify and fix HTTP macro's SSE streaming support.
Findings:
- SSE streaming code was already in
http.rsbut untested - Rust 2024's
impl Traitlifetime capture rules cause issues:impl Stream + 'staticstill captures&selfby default- Users need
+ use<>on their method return types - Example:
fn stream_data(&self) -> impl Stream + use<>
- Added
Box::pin(stream)to erase concrete type and ensure ownership
Result:
- Created
streaming_service.rsexample demonstrating SSE - SSE works with proper lifetime annotations
- Documented Rust 2024
+ use<>requirement
Iteration 5: E2E Tests
Goal: Validate generated code produces correct results.
Approach:
- Define
Calculatorwith reference implementations (ref_add,ref_divide, etc.) - Wrap in
McpCalculator,WsCalculator,HttpCalculator,CliCalculator - Call through generated handlers, verify results match reference
- Test error cases (Result::Err), missing cases (Option::None), optional params
Result:
- 20 E2E tests added
- Cross-protocol consistency verified (MCP and WS produce identical results)
- Total test count: 53
Iteration 6: Async Method Support
Goal: Add proper async method support to MCP and WebSocket macros.
Problem:
- Both MCP and WS previously used
AsyncHandling::Errorwhich rejected async methods - MCP had a stub
mcp_call_asyncthat just called the sync version - Real-world services often need async database calls, HTTP fetches, etc.
Solution:
- Generate both sync and async dispatch arms
- For sync callers (
mcp_call,ws_handle_message): async methods return error - For async callers (
mcp_call_async,ws_handle_message_async): async methods awaited - WebSocket connection handler uses async dispatch (supports async methods over real connections)
Changes:
rpc.rs: Fixedgenerate_dispatch_armto handle async error case without generating unreachable codemcp.rs: Generate bothdispatch_arms_syncanddispatch_arms_async, use in respective methodsws.rs: Addedws_handle_message_asyncandws_dispatch_async, connection handler uses asyncws.rs: Made__trellis_ws_connectionunique per struct to avoid conflicts
Tests Added:
- MCP: 5 async tests (sync/async methods with sync/async callers)
- WS: 6 async tests (sync/async methods with sync/async handlers)
Result:
- Async methods fully supported in MCP and WS
- Backwards compatible: sync callers still work for sync methods
- Real WebSocket connections can call async methods
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Solid | 3 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Total tests | 64 |
Remaining work:
- Documentation improvements
- GraphQL if more protocol coverage needed
- Error derive macro
- "Serve" coordination pattern
Iteration 7: Better Error Messages
Goal: Improve macro error messages with proper spans and helpful suggestions.
Changes:
Unknown attribute arguments now list valid options:
unknown argument 'badarg'. Valid arguments: namespace(MCP)unknown argument 'badarg'. Valid arguments: prefix(HTTP)unknown argument 'badarg'. Valid arguments: name, version, about(CLI)unknown argument 'badarg'. Valid arguments: path(WS)
Associated functions without
&self(constructors, etc.) are silently skipped, not errored.Unsupported parameter patterns now report errors instead of silently skipping:
unsupported parameter pattern. Use a simple identifier like 'name: String'
All errors use syn::Error::new_spanned() to point to the exact problematic code.
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Solid | 3 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Error messages | ✅ Improved | - |
| Total tests | 64 |
Iteration 8: Documentation Improvements
Goal: Update documentation to reflect all implemented features.
Changes:
lib.rs crate docs - Comprehensive overview including:
- All 4 macros (HTTP, CLI, MCP, WebSocket)
- Generated methods table
- Async method support with examples
- SSE streaming with Rust 2024
+ use<>note - Feature flags documentation
README.md - Updated from placeholder to real examples:
- Quick start with all 4 macros
- Generated code table showing what each macro produces
- Feature highlights
- Installation with feature flags
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Solid | 3 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Error messages | ✅ Improved | - |
| Documentation | ✅ Updated | - |
| Total tests | 64 |
Iteration 9: Error Derive Macro
Goal: Add #[derive(ServerlessError)] for error types with protocol-agnostic codes.
Features:
- Implements
IntoErrorCode,Display, andstd::error::Error #[error(code = NotFound)]- explicit ErrorCode variant#[error(code = 404)]- HTTP status (mapped to ErrorCode)#[error(message = "...")]- custom message- Code inference from variant name (e.g.,
Unauthorized→Unauthenticated) - Supports unit, tuple, and struct variants
Example:
#[derive(ServerlessError)]
enum MyError {
#[error(code = NotFound, message = "User not found")]
UserNotFound,
#[error(code = 400)]
ValidationFailed(String),
Unauthorized, // inferred from name
}Tests: 10 new tests, 74 total.
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Solid | 3 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| Error derive | ✅ NEW | 10 |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Error messages | ✅ Improved | - |
| Documentation | ✅ Updated | - |
| Total tests | 74 |
Iteration 10: Attribute Customization
Goal: Allow per-method HTTP route customization via #[route(...)].
Features:
#[route(method = "POST")]- override HTTP method#[route(path = "/custom")]- override path#[route(skip)]- exclude from HTTP router and OpenAPI#[route(hidden)]- include in router but hide from OpenAPI
Example:
#[http(prefix = "/api")]
impl MyService {
#[route(method = "POST", path = "/custom")]
fn my_method(&self) { }
#[route(skip)]
fn internal_only(&self) { }
}Implementation:
- Added
#[route]passthrough macro (inner attributes on methods) HttpMethodOverridestruct parses method attributes- Override logic in
generate_routeandgenerate_openapi_spec
Tests: 7 new tests, 81 total.
Iteration 11: OpenAPI Improvements
Goal: Enhance OpenAPI spec generation with proper parameter schemas and response types.
Features:
- Query parameter schemas: Type inference for GET/DELETE params (integer, string, boolean)
- Path parameter schemas: ID params marked as path params with proper types
- Request body schemas: POST/PUT/PATCH get request body with properties and required fields
- Error responses: Result return types generate 200/400/500 responses
Implementation Details:
- Added
extract_option_inner()helper to get inner type fromOption<T>(avoids double-wrapping) - Made handler names unique per struct (
__trellis_http_{struct}_{method}) to support multiple services - Fixed parameter type handling for optional params (parse as inner type, not
Option<T>) - Enhanced
generate_openapi_specwith proper parameter/body/response generation
Tests Added:
test_openapi_query_parameters- verifies page/limit query paramstest_openapi_path_parameters- verifies item_id path paramtest_openapi_request_body- verifies POST body schematest_openapi_error_responses- verifies Result generates error codes
Total: 4 new OpenAPI tests, 85 total tests.
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Enhanced | 14 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| Error derive | ✅ Working | 10 |
| Route attr | ✅ Working | - |
| OpenAPI schemas | ✅ NEW | - |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Error messages | ✅ Improved | - |
| Documentation | ✅ Updated | - |
| Total tests | 85 |
Iteration 12: Serve Coordination Pattern
Goal: Combine multiple protocol handlers into a single server.
Features:
#[serve(http, ws)]- combine HTTP and WebSocket routers#[serve(http)]or#[serve(ws)]- single protocol#[serve(http, health = "/healthz")]- custom health check path- Generates
serve(addr)async method androuter()builder
Example:
#[http]
#[ws]
#[serve(http, ws)]
impl MyService {
fn list_items(&self) -> Vec<String> { vec![] }
}
// Start server
service.serve("0.0.0.0:3000").await?;
// Or get router for custom setup
let router = service.router();Implementation:
- New
serve.rsmodule withServeArgsparser - Handles Clone requirement by cloning before passing to routers
- Auto-adds
/healthendpoint (configurable) - Both
serve()androuter()methods for flexibility
Tests: 6 new tests, 91 total.
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Enhanced | 14 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| Serve macro | ✅ NEW | 6 |
| Error derive | ✅ Working | 10 |
| Route attr | ✅ Working | - |
| OpenAPI schemas | ✅ Working | - |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Error messages | ✅ Improved | - |
| Documentation | ✅ Updated | - |
| Total tests | 91 |
Iteration 13: GraphQL Macro
Goal: Add GraphQL support using async-graphql's dynamic schema API.
Features:
#[graphql]attribute on impl blocks- Query/Mutation inference from method names (same as HTTP)
- Dynamic schema generation (no nested proc macros)
- Generates
graphql_schema(),graphql_router(),graphql_sdl()
Example:
#[graphql]
impl MyService {
fn get_user(&self, id: String) -> User { } // Query
fn create_user(&self, name: String) -> User { } // Mutation
}
let schema = service.graphql_schema();
let sdl = service.graphql_sdl();
let router = service.graphql_router(); // serves /graphql with playgroundImplementation Notes:
- Uses async-graphql's dynamic schema API (not derive macros) to avoid proc macro nesting issues
- Type mapping simplified for now (returns String) - proper type registration TBD
- Handles query-only services (no empty mutation type)
Tests: 4 new tests, 95 total.
Current Status Summary
| Component | Status | Tests |
|---|---|---|
| MCP macro | ✅ Solid | 13 (+ E2E) |
| HTTP macro | ✅ Enhanced | 14 (+ E2E) |
| CLI macro | ✅ Solid | 6 (+ E2E) |
| WS macro | ✅ Solid | 16 (+ E2E) |
| Serve macro | ✅ Working | 6 |
| GraphQL macro | ✅ Basic | 4 |
| Error derive | ✅ Working | 10 |
| Route attr | ✅ Working | - |
| OpenAPI schemas | ✅ Working | - |
| RPC utilities | ✅ Shared | - |
| Feature gates | ✅ Working | - |
| SSE streaming | ✅ Working | - |
| Async support | ✅ Working | - |
| Error messages | ✅ Improved | - |
| Documentation | ✅ Updated | - |
| Total tests | 95 |
Iteration 14: gRPC Proto Generation
Goal: Impl-first protobuf schema generation for gRPC.
Approach: Since tonic is compile-time focused (unlike async-graphql's dynamic API), we generate .proto schema files that users can then use with standard tonic-build tooling.
Features:
#[grpc]or#[grpc(package = "my.package")]- Generates
grpc_schema() -> &'static str - Generates
write_grpc(path)helper - Maps Rust types to protobuf (string, int32, bool, etc.)
- Optional parameters become
optionalfields - Doc comments preserved in schema
Example:
#[grpc(package = "users.v1")]
impl UserService {
/// Get user by ID
fn get_user(&self, id: String) -> User { }
}
// Get proto schema
let proto = UserService::grpc_schema();
// Write to file
UserService::write_grpc("proto/users.proto")?;Generated proto:
syntax = "proto3";
package users.v1;
service UserService {
// Get user by ID
rpc GetUser(GetUserRequest) returns (GetUserResponse);
}
message GetUserRequest {
string id = 1;
}
message GetUserResponse {
string result = 1;
}Tests: 8 new tests, 103 total.
Iteration 15: GraphQL Type Improvements
Goal: Fix GraphQL type mapping and make resolvers actually call methods.
Before:
- All return types mapped to String
- Resolvers returned "todo" placeholder
After:
- Proper scalar type mapping (String, Int, Float, Boolean)
- List types supported (
Vec<T>->[T]) - Resolvers extract arguments from context
- Resolvers call actual service methods
- Results converted to GraphQL values
Example resolver now generates:
FieldFuture::new(async move {
let name: String = ctx.args.try_get("name")?.deserialize()?;
let result = service.create_item(name);
Ok(Some(value_to_graphql(result)))
})Tests: 5 new execution tests, 108 total.
Iteration 16: gRPC Schema Validation
Goal: Schema-first mode - validate impl against expected .proto file.
Features:
#[grpc(schema = "path/to/expected.proto")]- validate against expected schemavalidate_schema() -> Result<(), String>- returns diff if mismatchassert_schema_matches()- panics on mismatch
Example:
// Lock down your API contract
#[grpc(package = "users.v1", schema = "proto/users.proto")]
impl UserService {
fn get_user(&self, id: String) -> User { }
}
// In tests
#[test]
fn api_contract_stable() {
UserService::assert_schema_matches();
}Workflow:
- Start impl-first:
#[grpc]generates .proto - Write proto to file:
Service::write_grpc("proto/service.proto")? - Lock it down: add
schema = "proto/service.proto" - Now changes to impl that break the schema will fail validation
Tests: 3 new validation tests, 111 total.
Iteration 17: Cap'n Proto Support
Goal: Generate Cap'n Proto .capnp schemas from impl blocks.
Features:
#[capnp]- generate schema from impl#[capnp(id = "0x...")]- set schema ID (required for production)capnp_schema() -> &'static str- get schema stringwrite_capnp(path)- write to file- Schema validation like gRPC:
schema = "path.capnp",validate_schema(),assert_schema_matches()
Type Mappings:
| Rust | Cap'n Proto |
|---|---|
| String, &str | Text |
| i8/i16/i32/i64 | Int8/Int16/Int32/Int64 |
| u8/u16/u32/u64 | UInt8/UInt16/UInt32/UInt64 |
| f32/f64 | Float32/Float64 |
| bool | Bool |
Vec<u8> | Data |
Vec<T> | List(Text) |
| () | Void |
Schema Structure:
@0x85150b117366d14b;
interface MyService {
# Doc comment becomes Cap'n Proto comment
getUser @0 (GetUserParams) -> (GetUserResult);
}
struct GetUserParams {
id @0 :Text;
}
struct GetUserResult {
value @0 :Text;
}Tests: 10 new tests, 121 total.
Iteration 18: JSON-RPC over HTTP
Goal: JSON-RPC 2.0 over HTTP (same protocol as WS, different transport).
Features:
#[jsonrpc]- generate JSON-RPC HTTP handler#[jsonrpc(path = "/rpc")]- custom endpoint pathjsonrpc_router()- axum Router with POST endpointjsonrpc_handle(request)- handle JSON-RPC requestsjsonrpc_methods()- list available methods
JSON-RPC 2.0 Compliance:
- Version validation (
"jsonrpc": "2.0") - Proper error codes (-32600, -32603, etc.)
- Batch requests (array of requests)
- Notifications (no
idfield = no response)
Example:
#[jsonrpc]
impl Calculator {
fn add(&self, a: i32, b: i32) -> i32 { a + b }
}
// POST /rpc
// {"jsonrpc": "2.0", "method": "add", "params": {"a": 1, "b": 2}, "id": 1}
// => {"jsonrpc": "2.0", "result": 3, "id": 1}
// Batch:
// [{"jsonrpc": "2.0", "method": "add", ...}, {"jsonrpc": "2.0", "method": "multiply", ...}]
// => [{"result": 3, ...}, {"result": 12, ...}]Tests: 11 new tests, 132 total.
Iteration 19: Extended Serve Coordination
Goal: Support more protocols in the #[serve] macro.
Added Protocols:
jsonrpc- JSON-RPC over HTTP routergraphql- GraphQL router
Example:
#[http]
#[jsonrpc]
#[graphql]
#[serve(http, jsonrpc, graphql)]
impl MyService { ... }
// Combines all three routers + health check
let router = service.router();Tests: 2 new tests, 134 total.
Iteration 20: Thrift Schema Generation
Goal: Generate Apache Thrift .thrift schemas from impl blocks.
Features:
#[thrift]- generate schema from impl#[thrift(namespace = "users")]- set namespacethrift_schema() -> &'static str- get schema stringwrite_thrift(path)- write to file- Schema validation like gRPC/Cap'n Proto
Type Mappings:
| Rust | Thrift |
|---|---|
| String, &str | string |
| i8 | byte |
| i16/i32/i64 | i16/i32/i64 |
| f64 | double |
| bool | bool |
Vec<u8> | binary |
Vec<T> | list<string> |
| HashMap | map<string, string> |
| () | void |
Tests: 9 new tests, 143 total.
Iteration 21: OpenRPC Specification
Goal: Generate OpenRPC specs for JSON-RPC services (like OpenAPI for REST).
Features:
#[openrpc]- generate OpenRPC 1.0 specification#[openrpc(title = "...", version = "...")]- customize metadataopenrpc_spec() -> serde_json::Value- get spec as JSON valueopenrpc_json() -> String- get spec as formatted JSONwrite_openrpc(path)- write to file
Example:
#[jsonrpc]
#[openrpc(title = "Calculator API")]
impl Calculator {
/// Add two numbers
fn add(&self, a: i32, b: i32) -> i32 { a + b }
}
// Generates OpenRPC spec with method schemas,
// parameter types, and result types
let spec = Calculator::openrpc_json();Complements #[jsonrpc]: Use both together for a complete JSON-RPC service with documentation.
Tests: 9 new tests, 152 total.
Iteration 22: Markdown Documentation
Goal: Generate human-readable API docs from impl blocks.
Features:
#[markdown]- generate Markdown documentation#[markdown(title = "...", types = false)]- customize outputmarkdown_docs() -> &'static str- get docs as stringwrite_markdown(path)- write to file
Output includes:
- Title and overview
- Method documentation with signatures
- Parameter lists with types (optional)
- Return type descriptions
- Async method badges
- Doc comments preserved
Works with any static site generator: VitePress, Docusaurus, MkDocs, etc.
Backlog: Support for other doc formats (AsciiDoc, RST, Mintlify, ReadMe.io)
Tests: 10 new tests, 162 total.
Iteration 23: Blessed Presets & Mount Points
Goal: Add blessed preset macros and cross-protocol mount point composition.
Blessed Presets:
#[server]→#[http]+#[serve(http)]#[rpc]→#[jsonrpc]+#[openrpc]+#[serve(jsonrpc)]#[tool]→#[mcp]+#[jsonschema]#[program]→#[cli]+#[markdown]
Mount Points:
CliSubcommand— nested CLI subcommand groups via&Treturn typeHttpMount— HTTP path prefix delegationMcpNamespace— MCP tool namespace delegationWsMount— WebSocket mount delegationJsonRpcMount— JSON-RPC mount delegation
See blessed-presets.md and mount-points.md.
Iteration 24: CLI Output Formatting
Goal: Display-first CLI output with opt-in machine-readable modes.
Features:
- Default output via
Display(not JSON) --json/--jsonlglobal flags for machine-readable output--jq <expr>— in-process jq filtering viajaqlibrary (no external binary)--input-schema/--output-schema— JSON Schema introspection viaschemars--params-json <json>— pass all parameters as JSONdisplay_withescape hatch for custom per-method formatting- JSON passthrough:
--jsontakes precedence overdisplay_with
Iteration 25: Param Attributes
Goal: Cross-protocol parameter customization via #[param].
Features:
#[param(positional)]— CLI positional args (beyond the_idheuristic)#[param(short = 'x')]— short CLI flags#[param(help = "...")]— custom help text#[param(name = "...")]— wire name override#[param(default = ...)]— default values#[param(query/path/body/header)]— HTTP parameter placement
See param-attributes.md.
Current Status Summary
| Component | Status |
|---|---|
| MCP macro | ✅ Solid |
| HTTP macro | ✅ Enhanced |
| CLI macro | ✅ Enhanced |
| WS macro | ✅ Solid |
| JSON-RPC macro | ✅ Working |
| GraphQL macro | ✅ Working |
| gRPC schema | ✅ Working |
| Cap'n Proto schema | ✅ Working |
| Thrift schema | ✅ Working |
| Connect schema | ✅ Working |
| Smithy schema | ✅ Working |
| AsyncAPI spec | ✅ Working |
| OpenRPC spec | ✅ Working |
| JSON Schema | ✅ Working |
| Markdown docs | ✅ Working |
| Serve macro | ✅ Working |
| Error derive | ✅ Working |
| Route attr | ✅ Working |
| Param attr | ✅ Working |
| OpenAPI composition | ✅ Working |
| Blessed presets | ✅ Working |
| Mount points | ✅ Working |
| CLI output formatting | ✅ Working |
| Total tests | 450 |