Project structure
carmy new creates this layout:
shop/├── Cargo.toml├── carmy.toml # name, address, timeout; CARMY_* env vars override├── README.md├── .gitignore└── src/ ├── main.rs # the entry point └── tools/ ├── mod.rs # one `mod` line per tool └── hello.rs # a tool and its testssrc/main.rs
Section titled “src/main.rs”mod tools;
#[tokio::main]async fn main() -> carmy::Result { carmy::run().await}carmy::run() is shorthand for carmy::app().run().await. carmy::app() does three
things:
- reads configuration from
carmy.tomland the environment - registers every tool declared with
#[carmy::tool] - chooses the transport from the first command-line argument
To register shared dependencies, use the builder:
#[tokio::main]async fn main() -> carmy::Result { let db = Db::connect("postgres://localhost/shop").await.expect("database"); carmy::app().state(db).run().await}src/tools/
Section titled “src/tools/”The convention is one file per tool. Declare each file in src/tools/mod.rs:
//! One file per tool. Declare each file here; `#[carmy::tool]` registers it.mod hello;mod search;Keep a tool’s tests in the same file (see Testing).
carmy.toml
Section titled “carmy.toml”name = "shop" # CARMY_NAMEaddress = "127.0.0.1:3000" # CARMY_ADDRtimeout_secs = 30 # CARMY_TIMEOUT_SECSCommands
Section titled “Commands”| command | effect |
|---|---|
cargo run or cargo run -- server |
serve HTTP on the configured address |
cargo run -- mcp |
serve MCP over stdin/stdout |
cargo run -- tools |
print the tool catalog as JSON |
cargo test |
run the tests |