|
| 1 | +# elicit_axum |
| 2 | + |
| 3 | +`elicit_axum` is the [elicitation] shadow crate for [axum]. It exposes 22 MCP |
| 4 | +tools across 4 plugins that let an AI agent describe and emit a complete axum |
| 5 | +web service — routers, handlers, responses, and the top-level serve |
| 6 | +configuration — without any live axum instances crossing the MCP boundary. |
| 7 | + |
| 8 | +## Shadow crate concept |
| 9 | + |
| 10 | +A shadow crate mirrors the API surface of its source library using names that |
| 11 | +are familiar to any developer who knows axum, but replaces the live types with |
| 12 | +MCP-compatible descriptors. When an agent calls `axum_router__new` it gets back |
| 13 | +a UUID handle, not a real `Router<S>`. All descriptors live in server-side |
| 14 | +registries keyed by those UUIDs. When the agent is satisfied with the |
| 15 | +configuration it calls the `emit` tool to recover idiomatic Rust source that can |
| 16 | +be pasted directly into a project. |
| 17 | + |
| 18 | +## Plugins |
| 19 | + |
| 20 | +| Plugin | Namespace | Description | |
| 21 | +|---|---|---| |
| 22 | +| `AxumRouterPlugin` | `axum_router__*` | Router descriptor: routes, layers, fallback, state | |
| 23 | +| `AxumHandlerPlugin` | `axum_handler__*` | Handler descriptor: extractors, body | |
| 24 | +| `AxumResponsePlugin` | `axum_response__*` | Response descriptor: JSON, HTML, redirect, status | |
| 25 | +| `AxumServePlugin` | `axum_serve__*` | Serve descriptor: bind address, graceful shutdown | |
| 26 | + |
| 27 | +## Tool reference |
| 28 | + |
| 29 | +### `axum_router__*` |
| 30 | + |
| 31 | +| Tool | Params | Returns | Establishes | |
| 32 | +|---|---|---|---| |
| 33 | +| `new` | `state_type` | `{ router_id }` | `AxumRouterCreated` | |
| 34 | +| `add_route` | `router_id, method, path, handler` | `{ route_count }` | `AxumRouteAdded` | |
| 35 | +| `add_layer` | `router_id, layer_expr` | `{ layer_count }` | — | |
| 36 | +| `set_fallback` | `router_id, handler` | — | — | |
| 37 | +| `set_db_slot` | `router_id, pool_type, var_name, provide_leptos_context` | — | — | |
| 38 | +| `set_custom_state` | `router_id, state_type, state_expr` | — | — | |
| 39 | +| `describe` | `router_id` | JSON descriptor | — | |
| 40 | +| `emit` | `router_id` | Rust source string | — | |
| 41 | + |
| 42 | +### `axum_handler__*` |
| 43 | + |
| 44 | +| Tool | Params | Returns | Establishes | |
| 45 | +|---|---|---|---| |
| 46 | +| `new` | `name, return_type` | `{ handler_id }` | `AxumHandlerDefined` | |
| 47 | +| `add_extractor` | `handler_id, var_name, kind, type_name` | `{ extractor_count }` | `AxumExtractorAdded` | |
| 48 | +| `set_body` | `handler_id, body` | — | — | |
| 49 | +| `describe` | `handler_id` | JSON descriptor | — | |
| 50 | +| `emit` | `handler_id` | Rust `async fn` source | — | |
| 51 | + |
| 52 | +Supported extractor kinds: `Path`, `Query`, `Json`, `State`, `Extension`, |
| 53 | +`Form`, `Headers`, `RawBody`, `RawQuery`, `OriginalUri`, `MatchedPath`, |
| 54 | +`ConnectInfo`. |
| 55 | + |
| 56 | +### `axum_response__*` |
| 57 | + |
| 58 | +| Tool | Params | Returns | Establishes | |
| 59 | +|---|---|---|---| |
| 60 | +| `json` | `status_code, body_expr` | `{ response_id }` | `AxumResponseDefined` | |
| 61 | +| `html` | `status_code, body_expr` | `{ response_id }` | `AxumResponseDefined` | |
| 62 | +| `redirect_permanent` | `uri` | `{ response_id }` | `AxumResponseDefined` | |
| 63 | +| `redirect_temporary` | `uri` | `{ response_id }` | `AxumResponseDefined` | |
| 64 | +| `no_content` | — | `{ response_id }` | `AxumResponseDefined` | |
| 65 | +| `status` | `status_code, body_expr?` | `{ response_id }` | `AxumResponseDefined` | |
| 66 | +| `describe` | `response_id` | JSON descriptor | — | |
| 67 | +| `emit` | `response_id` | Rust expression string | — | |
| 68 | + |
| 69 | +### `axum_serve__*` |
| 70 | + |
| 71 | +| Tool | Params | Returns | Establishes | |
| 72 | +|---|---|---|---| |
| 73 | +| `new` | `router_id, addr` | `{ serve_id }` | `AxumServerConfigured` | |
| 74 | +| `with_graceful_shutdown` | `serve_id, signal_expr` | — | — | |
| 75 | +| `describe` | `serve_id` | JSON descriptor | — | |
| 76 | +| `emit_main` | `serve_id` | Complete `main.rs` source | — | |
| 77 | + |
| 78 | +## Propositions |
| 79 | + |
| 80 | +Each state-changing tool establishes a typed proposition: |
| 81 | + |
| 82 | +| Proposition | Established by | |
| 83 | +|---|---| |
| 84 | +| `AxumRouterCreated` | `axum_router__new` | |
| 85 | +| `AxumRouteAdded` | `axum_router__add_route` | |
| 86 | +| `AxumHandlerDefined` | `axum_handler__new` | |
| 87 | +| `AxumExtractorAdded` | `axum_handler__add_extractor` | |
| 88 | +| `AxumResponseDefined` | all `axum_response__*` creation tools | |
| 89 | +| `AxumServerConfigured` | `axum_serve__new` | |
| 90 | + |
| 91 | +Propositions implement [`Prop`] and [`VerifiedWorkflow`], and carry Kani, Verus, |
| 92 | +and Creusot proof skeletons that can be discharged by the elicitation prove |
| 93 | +pipeline. |
| 94 | + |
| 95 | +## Typical workflow |
| 96 | + |
| 97 | +```text |
| 98 | +1. axum_router__new → router_id |
| 99 | +2. axum_handler__new → handler_id |
| 100 | +3. axum_handler__add_extractor (repeat as needed) |
| 101 | +4. axum_handler__set_body |
| 102 | +5. axum_router__add_route → links handler name into router |
| 103 | +6. axum_response__json → response_id (optional, for documenting responses) |
| 104 | +7. axum_serve__new → serve_id |
| 105 | +8. axum_serve__with_graceful_shutdown (optional) |
| 106 | +9. axum_router__emit → paste Router construction into project |
| 107 | +10. axum_handler__emit → paste async fn into project |
| 108 | +11. axum_serve__emit_main → paste main() into project |
| 109 | +``` |
| 110 | + |
| 111 | +## Feature flags |
| 112 | + |
| 113 | +| Feature | Description | |
| 114 | +|---|---| |
| 115 | +| `emit` | Enable `EmitCode` code-recovery support (re-exports `elicitation/emit`) | |
| 116 | + |
| 117 | +## Usage |
| 118 | + |
| 119 | +Add to your `Cargo.toml`: |
| 120 | + |
| 121 | +```toml |
| 122 | +[dependencies] |
| 123 | +elicit_axum = "0.11" |
| 124 | +``` |
| 125 | + |
| 126 | +Register the plugins with your MCP server: |
| 127 | + |
| 128 | +```rust |
| 129 | +use elicit_axum::{AxumHandlerPlugin, AxumResponsePlugin, AxumRouterPlugin, AxumServePlugin}; |
| 130 | + |
| 131 | +let server = server |
| 132 | + .register_plugin(AxumRouterPlugin::new()) |
| 133 | + .register_plugin(AxumHandlerPlugin::new()) |
| 134 | + .register_plugin(AxumResponsePlugin::new()) |
| 135 | + .register_plugin(AxumServePlugin::new()); |
| 136 | +``` |
| 137 | + |
| 138 | +[elicitation]: https://crates.io/crates/elicitation |
| 139 | +[axum]: https://crates.io/crates/axum |
| 140 | +[`Prop`]: https://docs.rs/elicitation/latest/elicitation/contracts/trait.Prop.html |
| 141 | +[`VerifiedWorkflow`]: https://docs.rs/elicitation/latest/elicitation/trait.VerifiedWorkflow.html |
0 commit comments